xeij/XEiJ.java (2/2)
1 2
  //  0x00eafe00  GP-IBボード(CZ-6BG1)
  //  0x00eaff00  スーパーバイザエリア設定
  //
  //  スーパーバイザエリア設定のみ対応

  //スーパーバイザエリア設定ポート
  //  0x00eaff81  bit0  0x00200000~0x0023ffff
  //              bit1  0x00240000~0x0027ffff
  //              bit2  0x00280000~0x002bffff
  //              bit3  0x002c0000~0x002fffff
  //              bit4  0x00300000~0x0033ffff
  //              bit5  0x00340000~0x0037ffff
  //              bit6  0x00380000~0x003bffff
  //              bit7  0x003c0000~0x003fffff
  //  0x00eaff83  bit0  0x00400000~0x0043ffff
  //              bit1  0x00440000~0x0047ffff
  //              bit2  0x00480000~0x004bffff
  //              bit3  0x004c0000~0x004fffff
  //              bit4  0x00500000~0x0053ffff
  //              bit5  0x00540000~0x0057ffff
  //              bit6  0x00580000~0x005bffff
  //              bit7  0x005c0000~0x005fffff
  //  0x00eaff85  bit0  0x00600000~0x0063ffff
  //              bit1  0x00640000~0x0067ffff
  //              bit2  0x00680000~0x006bffff
  //              bit3  0x006c0000~0x006fffff
  //              bit4  0x00700000~0x0073ffff
  //              bit5  0x00740000~0x0077ffff
  //              bit6  0x00780000~0x007bffff
  //              bit7  0x007c0000~0x007fffff
  //  0x00eaff87  bit0  0x00800000~0x0083ffff
  //              bit1  0x00840000~0x0087ffff
  //              bit2  0x00880000~0x008bffff
  //              bit3  0x008c0000~0x008fffff
  //              bit4  0x00900000~0x0093ffff
  //              bit5  0x00940000~0x0097ffff
  //              bit6  0x00980000~0x009bffff
  //              bit7  0x009c0000~0x009fffff
  //  0x00eaff89  bit0  0x00a00000~0x00a3ffff
  //              bit1  0x00a40000~0x00a7ffff
  //              bit2  0x00a80000~0x00abffff
  //              bit3  0x00ac0000~0x00afffff
  //              bit4  0x00b00000~0x00b3ffff
  //              bit5  0x00b40000~0x00b7ffff
  //              bit6  0x00b80000~0x00bbffff
  //              bit7  0x00bc0000~0x00bfffff



  //========================================================================================
  //$$BNK バンクメモリ
  //  $00EAFF7F  バンクメモリのページ番号。0~255
  //  $00EE0000~$00EFFFFF  バンクメモリ

  public static final int BNK_SIZE = 1024 * 1024 * 32;  //サイズ
  public static byte[] bnkMemory;  //メモリの配列
  public static int bnkPageStart;  //ページの先頭のインデックス。ページ番号<<17
  public static boolean bnkOn;  //true=バンクメモリが有効

  public static void bnkInit () {
    bnkMemory = new byte[BNK_SIZE];
    byte[] array = Settings.sgsGetData ("bankdata");
    if (array.length != 0) {
      System.arraycopy (array, 0, bnkMemory, 0, Math.min (array.length, BNK_SIZE));
    }
    bnkPageStart = 0;
    //bnkOn = true;
    bnkOn = false;
  }

  public static void bnkTini () {
    Settings.sgsPutData ("bankdata",
                         Arrays.copyOf (bnkMemory, BNK_SIZE));
  }



  //========================================================================================
  //$$FPU FPU

  //FPU/FPCP
  public static ExpressionEvaluator fpuMotherboardCoprocessor;  //マザーボードコプロセッサ
  public static ExpressionEvaluator fpuOnChipFPU;  //on-chip FPU
  public static ExpressionEvaluator fpuBox;  //浮動小数点命令を実行するFPU/FPCP

  //数値演算プロセッサボード
  public static EFPBox fpuCoproboard1;  //数値演算プロセッサボード1
  public static EFPBox fpuCoproboard2;  //数値演算プロセッサボード2

  //浮動小数点レジスタ
  public static EFPBox.EFP[] fpuFPn;

  //FPCR control register
  //  exception enable byte
  public static final int FPU_FPCR_BSUN   = 0b00000000_00000000_10000000_00000000;  //branch/set on unordered
  public static final int FPU_FPCR_SNAN   = 0b00000000_00000000_01000000_00000000;  //signaling not a number
  public static final int FPU_FPCR_OPERR  = 0b00000000_00000000_00100000_00000000;  //operand error
  public static final int FPU_FPCR_OVFL   = 0b00000000_00000000_00010000_00000000;  //overflow
  public static final int FPU_FPCR_UNFL   = 0b00000000_00000000_00001000_00000000;  //underflow
  public static final int FPU_FPCR_DZ     = 0b00000000_00000000_00000100_00000000;  //divide by zero
  public static final int FPU_FPCR_INEX2  = 0b00000000_00000000_00000010_00000000;  //inexact operation
  public static final int FPU_FPCR_INEX1  = 0b00000000_00000000_00000001_00000000;  //inexact decimal input
  //  mode control byte
  //    rounding precision
  public static final int FPU_FPCR_PE     = 0b00000000_00000000_00000000_00000000;  //extended
  public static final int FPU_FPCR_PS     = 0b00000000_00000000_00000000_01000000;  //single
  public static final int FPU_FPCR_PD     = 0b00000000_00000000_00000000_10000000;  //double
  //    rounding mode
  public static final int FPU_FPCR_RN     = 0b00000000_00000000_00000000_00000000;  //to nearest
  public static final int FPU_FPCR_RZ     = 0b00000000_00000000_00000000_00010000;  //toward zero
  public static final int FPU_FPCR_RM     = 0b00000000_00000000_00000000_00100000;  //toward minus infinity
  public static final int FPU_FPCR_RP     = 0b00000000_00000000_00000000_00110000;  //toward plus infinity

  //FPSR status register
  //  condition code byte
  public static final int FPU_FPSR_N         = 0b00001000_00000000_00000000_00000000;  //negative
  public static final int FPU_FPSR_Z         = 0b00000100_00000000_00000000_00000000;  //zero
  public static final int FPU_FPSR_I         = 0b00000010_00000000_00000000_00000000;  //infinity
  public static final int FPU_FPSR_NAN       = 0b00000001_00000000_00000000_00000000;  //not a number or unordered
  //  quotient byte
  public static final int FPU_FPSR_S         = 0b00000000_10000000_00000000_00000000;  //sign of quotient
  public static final int FPU_FPSR_QUOTIENT  = 0b00000000_01111111_00000000_00000000;  //quotient
  //  exception status byte
  public static final int FPU_FPSR_EXC_BSUN  = 0b00000000_00000000_10000000_00000000;  //branch/set on unordered
  public static final int FPU_FPSR_EXC_SNAN  = 0b00000000_00000000_01000000_00000000;  //signaling not a number
  public static final int FPU_FPSR_EXC_OPERR = 0b00000000_00000000_00100000_00000000;  //operand error
  public static final int FPU_FPSR_EXC_OVFL  = 0b00000000_00000000_00010000_00000000;  //overflow
  public static final int FPU_FPSR_EXC_UNFL  = 0b00000000_00000000_00001000_00000000;  //underflow
  public static final int FPU_FPSR_EXC_DZ    = 0b00000000_00000000_00000100_00000000;  //divide by zero
  public static final int FPU_FPSR_EXC_INEX2 = 0b00000000_00000000_00000010_00000000;  //inexact operation
  public static final int FPU_FPSR_EXC_INEX1 = 0b00000000_00000000_00000001_00000000;  //inexact decimal input
  //  accrued exception byte
  public static final int FPU_FPSR_AEXC_IOP  = 0b00000000_00000000_00000000_10000000;  //invalid operation
  public static final int FPU_FPSR_AEXC_OVFL = 0b00000000_00000000_00000000_01000000;  //overflow
  public static final int FPU_FPSR_AEXC_UNFL = 0b00000000_00000000_00000000_00100000;  //underflow
  public static final int FPU_FPSR_AEXC_DZ   = 0b00000000_00000000_00000000_00010000;  //divide by zero
  public static final int FPU_FPSR_AEXC_INEX = 0b00000000_00000000_00000000_00001000;  //inexact

  //  EXCからAEXCへの変換
  //    AEXC_IOP |= EXC_BSUN | EXC_SNAN | EXC_OPERR
  //    AEXC_OVFL |= EXC_OVFL
  //    AEXC_UNFL |= EXC_UNFL & EXC_INEX2
  //    AEXC_DZ |= EXC_DZ
  //    AEXC_INEX |= EXC_OVFL | EXC_INEX2 | EXC_INEX1
  public static final int[] FPU_FPSR_EXC_TO_AEXC = new int[256];

  //コンディション
  //
  //  fpsrのbit27-24
  //    MZIN
  //    0000  0<x
  //    0001  NaN
  //    0010  +Inf
  //    0100  +0
  //    1000  x<0
  //    1010  -Inf
  //    1100  -0
  //
  //  FPU_CCMAP_882[(オペコードまたは拡張ワード&63)<<4|fpsr>>24&15]==trueならば条件成立
  //  FPU_CCMAP_060[(オペコードまたは拡張ワード&63)<<4|fpsr>>24&15]==trueならば条件成立
  //
  //  MC68882とMC68060ではOR,NE,GLE,SNEの条件が異なる

  //MC68882
  //  perl -e "@a=();for$a(0..15){$m=$a>>3&1;$z=$a>>2&1;$n=$a&1;@b=map{$_&1}(0,$z,~($n|$z|$m),$z|~($n|$m),$m&~($n|$z),$z|($m&~$n),~($n|$z),$z|~$n,$n,$n|$z,$n|~($m|$z),$n|($z|~$m),$n|($m&~$z),$n|$z|$m,$n|~$z,1);push@a,@b,@b,@b,@b}for$y(0..63){print'    ';$t=0;for$x(0..15){$c=$a[$x<<6|$y];$t=($t<<1)+$c;print(($c?'T':'F').',');}printf'  //%04x %06b%c',$t,$y,10;}
  //
  //F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,  //N
  //F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //Z
  //F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //NAN
  public static final boolean[] FPU_CCMAP_882 = {
    //                                       cccccc  cc    等式          意味
    //IEEEアウェアテスト
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 000000  F     0             偽
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 000001  EQ    Z             等しい
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 000010  OGT   ~(NAN|Z|N)    比較可能でより大きい
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 000011  OGE   Z|~(NAN|N)    等しいか比較可能でより大きい
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 000100  OLT   N&~(NAN|Z)    比較可能でより小さい
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 000101  OLE   Z|(N&~NAN)    等しいか比較可能でより小さい
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 000110  OGL   ~(NAN|Z)      比較可能で等しくない
    T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 000111  OR    Z|~NAN        等しいか比較可能
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 001000  UN    NAN           比較不能
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 001001  UEQ   NAN|Z         比較不能か等しい
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 001010  UGT   NAN|~(N|Z)    比較不能かより大きい
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 001011  UGE   NAN|(Z|~N)    比較不能かより大きいか等しい
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 001100  ULT   NAN|(N&~Z)    比較不能かより小さい
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 001101  ULE   NAN|Z|N       比較不能かより小さいか等しい
    T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 001110  NE    NAN|~Z        比較不能か等しくない
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 001111  T     1             真
    //IEEEノンアウェアテスト
    //  NANがセットされているとき、FPSRのBSUNがセットされ、許可されていれば例外が発生する
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 010000  SF    0             偽(シグナリング)
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 010001  SEQ   Z             等しい(シグナリング)
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 010010  GT    ~(NAN|Z|N)    より大きい
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 010011  GE    Z|~(NAN|N)    より大きいか等しい
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 010100  LT    N&~(NAN|Z)    より小さい
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 010101  LE    Z|(N&~NAN)    より小さいか等しい
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 010110  GL    ~(NAN|Z)      等しくない
    T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 010111  GLE   Z|~NAN        より大きいか小さいか等しい
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 011000  NGLE  NAN           GLEでない
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 011001  NGL   NAN|Z         GLでない
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 011010  NLE   NAN|~(N|Z)    LEでない
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 011011  NLT   NAN|(Z|~N)    LTでない
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 011100  NGE   NAN|(N&~Z)    GEでない
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 011101  NGT   NAN|Z|N       GTでない
    T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 011110  SNE   NAN|~Z        等しくない(シグナリング)
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 011111  ST    1             真(シグナリング)
    //
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 100000
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 100001
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 100010
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 100011
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 100100
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 100101
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 100110
    T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 100111
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 101000
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 101001
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 101010
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 101011
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 101100
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 101101
    T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 101110
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 101111
    //
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 110000
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 110001
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 110010
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 110011
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 110100
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 110101
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 110110
    T,F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,  //afaf 110111
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 111000
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 111001
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 111010
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 111011
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 111100
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 111101
    T,T,T,T,F,T,F,T,T,T,T,T,F,T,F,T,  //f5f5 111110
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 111111
  };

  //MC68060
  //  perl -e "@a=();for$a(0..15){$m=$a>>3&1;$z=$a>>2&1;$n=$a&1;@b=map{$_&1}(0,$z,~($n|$z|$m),$z|~($n|$m),$m&~($n|$z),$z|($m&~$n),~($n|$z),~$n,$n,$n|$z,$n|~($m|$z),$n|($z|~$m),$n|($m&~$z),$n|$z|$m,~$z,1);push@a,@b,@b,@b,@b}for$y(0..63){print'    ';$t=0;for$x(0..15){$c=$a[$x<<6|$y];$t=($t<<1)+$c;print(($c?'T':'F').',');}printf'  //%04x %06b%c',$t,$y,10;}
  //
  //F,F,F,F,F,F,F,F,T,T,T,T,T,T,T,T,  //N
  //F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //Z
  //F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //NAN
  public static final boolean[] FPU_CCMAP_060 = {
    //                                       cccccc  cc    等式          意味
    //IEEEアウェアテスト
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 000000  F     0             偽
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 000001  EQ    Z             等しい
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 000010  OGT   ~(NAN|Z|N)    比較可能でより大きい
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 000011  OGE   Z|~(NAN|N)    等しいか比較可能でより大きい
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 000100  OLT   N&~(NAN|Z)    比較可能でより小さい
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 000101  OLE   Z|(N&~NAN)    等しいか比較可能でより小さい
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 000110  OGL   ~(NAN|Z)      比較可能で等しくない
    T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 000111  OR    ~NAN          比較可能
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 001000  UN    NAN           比較不能
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 001001  UEQ   NAN|Z         比較不能か等しい
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 001010  UGT   NAN|~(N|Z)    比較不能かより大きい
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 001011  UGE   NAN|(Z|~N)    比較不能かより大きいか等しい
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 001100  ULT   NAN|(N&~Z)    比較不能かより小さい
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 001101  ULE   NAN|Z|N       比較不能かより小さいか等しい
    T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 001110  NE    ~Z            等しくない
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 001111  T     1             真
    //IEEEノンアウェアテスト
    //  NANがセットされているとき、FPSRのBSUNがセットされ、許可されていれば例外が発生する
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 010000  SF    0             偽(シグナリング)
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 010001  SEQ   Z             等しい(シグナリング)
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 010010  GT    ~(NAN|Z|N)    より大きい
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 010011  GE    Z|~(NAN|N)    より大きいか等しい
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 010100  LT    N&~(NAN|Z)    より小さい
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 010101  LE    Z|(N&~NAN)    より小さいか等しい
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 010110  GL    ~(NAN|Z)      等しくない
    T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 010111  GLE   ~NAN          より大きいか小さいか等しい
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 011000  NGLE  NAN           GLEでない
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 011001  NGL   NAN|Z         GLでない
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 011010  NLE   NAN|~(N|Z)    LEでない
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 011011  NLT   NAN|(Z|~N)    LTでない
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 011100  NGE   NAN|(N&~Z)    GEでない
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 011101  NGT   NAN|Z|N       GTでない
    T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 011110  SNE   ~Z            等しくない(シグナリング)
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 011111  ST    1             真(シグナリング)
    //
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 100000
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 100001
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 100010
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 100011
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 100100
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 100101
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 100110
    T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 100111
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 101000
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 101001
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 101010
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 101011
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 101100
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 101101
    T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 101110
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 101111
    //
    F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,F,  //0000 110000
    F,F,F,F,T,T,T,T,F,F,F,F,T,T,T,T,  //0f0f 110001
    T,F,T,F,F,F,F,F,F,F,F,F,F,F,F,F,  //a000 110010
    T,F,T,F,T,T,T,T,F,F,F,F,T,T,T,T,  //af0f 110011
    F,F,F,F,F,F,F,F,T,F,T,F,F,F,F,F,  //00a0 110100
    F,F,F,F,T,T,T,T,T,F,T,F,T,T,T,T,  //0faf 110101
    T,F,T,F,F,F,F,F,T,F,T,F,F,F,F,F,  //a0a0 110110
    T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,  //aaaa 110111
    F,T,F,T,F,T,F,T,F,T,F,T,F,T,F,T,  //5555 111000
    F,T,F,T,T,T,T,T,F,T,F,T,T,T,T,T,  //5f5f 111001
    T,T,T,T,F,T,F,T,F,T,F,T,F,T,F,T,  //f555 111010
    T,T,T,T,T,T,T,T,F,T,F,T,T,T,T,T,  //ff5f 111011
    F,T,F,T,F,T,F,T,T,T,T,T,F,T,F,T,  //55f5 111100
    F,T,F,T,T,T,T,T,T,T,T,T,T,T,T,T,  //5fff 111101
    T,T,T,T,F,F,F,F,T,T,T,T,F,F,F,F,  //f0f0 111110
    T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,  //ffff 111111
  };

  //fpuInit ()
  //  FPUを初期化する
  //  これはmpuInit()から呼ばれる
  public static void fpuInit () {
    for (int i = 0; i < 256; i++) {
      FPU_FPSR_EXC_TO_AEXC[i] = (((i << 8 & (FPU_FPSR_EXC_BSUN | FPU_FPSR_EXC_SNAN | FPU_FPSR_EXC_OPERR)) != 0 ? FPU_FPSR_AEXC_IOP : 0) |
                                 ((i << 8 & FPU_FPSR_EXC_OVFL) != 0 ? FPU_FPSR_AEXC_OVFL : 0) |
                                 ((i << 8 & (FPU_FPSR_EXC_UNFL | FPU_FPSR_EXC_INEX2)) == (FPU_FPSR_EXC_UNFL | FPU_FPSR_EXC_INEX2) ? FPU_FPSR_AEXC_UNFL : 0) |
                                 ((i << 8 & FPU_FPSR_EXC_DZ) != 0 ? FPU_FPSR_AEXC_DZ : 0) |
                                 ((i << 8 & (FPU_FPSR_EXC_OVFL | FPU_FPSR_EXC_INEX2 | FPU_FPSR_EXC_INEX1)) != 0 ? FPU_FPSR_AEXC_INEX : 0));
    }
    //マザーボードコプロセッサ
    fpuMotherboardCoprocessor = new ExpressionEvaluator ();
    //on-chip FPU
    fpuOnChipFPU = new ExpressionEvaluator ();
    //浮動小数点命令を実行するFPU/FPCP
    fpuBox = currentMPU < Model.MPU_MC68LC040 ? fpuMotherboardCoprocessor : fpuOnChipFPU;
    //浮動小数点レジスタ
    fpuFPn = fpuBox.epbFPn;
    //数値演算プロセッサボード
    fpuCoproboard1 = new EFPBox ();
    fpuCoproboard2 = new EFPBox ();
  }  //fpuInit()



  //========================================================================================
  //$$DBG デバッガ共通コンポーネント

  public static final boolean DBG_ORI_BYTE_ZERO_D0 = true;  //true=ORI.B #$00,D0(オペコード0x0000)を不当命令とみなす機能を有効にする。暴走をなるべく早く検出することで暴走の原因を特定しやすくする

  public static boolean dbgHexSelected;  //true=16進数が選択されている
  public static int dbgHexValue;  //選択されている16進数の値
  public static int dbgSupervisorMode;  //0=ユーザモード,0以外=スーパーバイザモード
  public static JPopupMenu dbgPopupMenu;  //ポップアップメニュー
  public static JMenu dbgPopupIBPMenu;  //命令ブレークポイントメニュー
  public static SpinnerNumberModel dbgPopupIBPCurrentModel;  //現在値のスピナーモデル
  public static int dbgPopupIBPCurrentValue;  //現在値
  public static SpinnerNumberModel dbgPopupIBPThresholdModel;  //閾値のスピナーモデル
  public static int dbgPopupIBPThresholdValue;  //閾値
  public static JMenuItem dbgPopupIBPClearMenuItem;  //解除
  public static JMenu dbgPopupHexMenu;  //16進数メニュー
  public static JMenuItem dbgPopupDisMenuItem;  //逆アセンブル
  public static JMenuItem dbgPopupMemMenuItem;  //メモリダンプ
  public static JMenuItem dbgPopupCopyMenuItem;  //コピー
  public static JMenuItem dbgPopupSelectAllMenuItem;  //すべて選択
  public static JTextArea dbgPopupTextArea;  //ポップアップメニューを表示したテキストエリア
  public static int dbgEventMask;  //イベントマスク。0でないときチェンジリスナーとキャレットリスナーを無効化
  public static boolean dbgStopOnError;  //true=エラーが発生したときコアを止める
  public static boolean dbgOriByteZeroD0;  //true=ORI.B #$00,D0を不当命令とみなす。普段はOFFにしておくこと
  public static boolean dbgStopAtStart;  //true=実行開始位置で停止する

  //共通
  //  sb.append(DBG_SPACES,0,length)でStringBuilderに連続する空白を追加するための配列
  public static final char[] DBG_SPACES = (
    //         11111111112222222222333333333344444444445555555555666666666677777777778
    //12345678901234567890123456789012345678901234567890123456789012345678901234567890
    "                                                                                ").toCharArray ();

  public static final int DBG_DRP_VISIBLE_MASK = 1;  //レジスタウインドウが表示されている
  public static final int DBG_DDP_VISIBLE_MASK = 2;  //逆アセンブルリストウインドウが表示されている
  public static final int DBG_DMP_VISIBLE_MASK = 4;  //メモリダンプウインドウが表示されている
  public static final int DBG_BLG_VISIBLE_MASK = 8;  //分岐ログが表示されている
  public static final int DBG_PFV_VISIBLE_MASK = 16;  //プログラムフロービジュアライザが表示されている
  public static final int DBG_RBP_VISIBLE_MASK = 32;  //ラスタブレークポイントウインドウが表示されている
  public static final int DBG_DBP_VISIBLE_MASK = 64;  //データブレークポイントウインドウが表示されている
  public static final int DBG_SMT_VISIBLE_MASK = 128;  //表示モードテストが表示されている
  public static final int DBG_ATW_VISIBLE_MASK = 256;  //アドレス変換ウインドウが表示されている
  public static final int DBG_PAA_VISIBLE_MASK = 512;  //物理アドレス空間ウインドウが表示されている
  public static final int DBG_RTL_VISIBLE_MASK = 1024;  //ルートポインタリストが表示されている
  public static final int DBG_SPV_VISIBLE_MASK = 2048;  //スプライトパターンビュアが表示されている
  public static final int DBG_PLV_VISIBLE_MASK = 4096;  //スプライトパターンビュアが表示されている
  public static final int DBG_ACM_VISIBLE_MASK = 8192;  //アドレス変換キャッシュモニタが表示されている
  public static int dbgVisibleMask;  //表示されているデバッグ関連ウインドウのマスク

  //dbgInit ()
  //  初期化
  public static void dbgInit () {
    dbgVisibleMask = 0;
    dbgHexSelected = false;
    dbgHexValue = 0;
    dbgSupervisorMode = 1;
    dbgPopupMenu = null;
    dbgPopupDisMenuItem = null;
    dbgPopupMemMenuItem = null;
    dbgPopupCopyMenuItem = null;
    dbgPopupSelectAllMenuItem = null;
    dbgPopupIBPMenu = null;
    dbgPopupIBPCurrentModel = null;
    dbgPopupIBPCurrentValue = 0;
    dbgPopupIBPThresholdModel = null;
    dbgPopupIBPThresholdValue = 0;
    dbgPopupHexMenu = null;
    dbgPopupTextArea = null;
    dbgEventMask = 0;
    dbgStopOnError = false;  //ウインドウを表示する前にも必要なのでここで初期化すること
    if (DBG_ORI_BYTE_ZERO_D0) {
      dbgOriByteZeroD0 = false;
    }
    dbgStopAtStart = false;
  }  //dbgInit()

  //dbgMakePopup ()
  //  デバッグ関連ウインドウの共通コンポーネントを作る
  public static void dbgMakePopup () {

    //ポップアップメニュー
    ActionListener popupActionListener = new ActionListener () {
      @Override public void actionPerformed (ActionEvent ae) {
        switch (ae.getActionCommand ()) {
        case "Disassemble":
          DisassembleList.ddpBacktraceRecord = -1L;  //分岐レコードの選択を解除する
          DisassembleList.ddpOpen (dbgHexValue, dbgSupervisorMode, false);
          break;
        case "Memory Dump":
          MemoryDumpList.dmpOpen (dbgHexValue, dbgSupervisorMode != 0 ? 5 : 1, false);
          break;
        case "Run to Here":
          if (InstructionBreakPoint.IBP_ON) {
            if (mpuTask == null) {
              InstructionBreakPoint.ibpInstant (DisassembleList.ddpPopupAddress, DisassembleList.ddpSupervisorMode);
              mpuStart ();
            }
          }
          break;
        case "Set Breakpoint":
          if (InstructionBreakPoint.IBP_ON) {
            InstructionBreakPoint.ibpPut (DisassembleList.ddpPopupAddress, DisassembleList.ddpSupervisorMode, dbgPopupIBPCurrentValue, dbgPopupIBPThresholdValue, null);
            DisassembleList.ddpOpen (0, DisassembleList.ddpSupervisorMode, true);
          }
          break;
        case "Clear Breakpoint":
          if (InstructionBreakPoint.IBP_ON) {
            InstructionBreakPoint.ibpRemove (DisassembleList.ddpPopupAddress, DisassembleList.ddpSupervisorMode);
            DisassembleList.ddpOpen (0, DisassembleList.ddpSupervisorMode, true);
          }
          break;
        case "Copy":
          dbgCopy ();
          break;
        case "Select All":
          dbgSelectAll ();
          break;
        }
      }
    };
    dbgPopupMenu = ComponentFactory.createPopupMenu (
      dbgPopupIBPMenu =
      InstructionBreakPoint.IBP_ON ?
      ComponentFactory.createMenu (
        "XXXXXXXX", KeyEvent.VK_UNDEFINED,
        Multilingual.mlnText (ComponentFactory.createMenuItem ("Run to Here", 'R', popupActionListener), "ja", "ここまで実行"),
        ComponentFactory.createHorizontalSeparator (),
        Multilingual.mlnText (ComponentFactory.createMenuItem ("Set Breakpoint", 'S', popupActionListener), "ja", "ブレークポイントを設定"),
        ComponentFactory.createHorizontalBox (
          Box.createHorizontalStrut (7),
          Box.createHorizontalGlue (),
          ComponentFactory.setPreferredSize (
            Multilingual.mlnText (ComponentFactory.createLabel ("current"), "ja", "現在値"),
            60, 16),
          ComponentFactory.createNumberSpinner (dbgPopupIBPCurrentModel = new SpinnerNumberModel (0, 0, 0x7fffffff, 1), 10, new ChangeListener () {
            @Override public void stateChanged (ChangeEvent ce) {
              dbgPopupIBPCurrentValue = dbgPopupIBPCurrentModel.getNumber ().intValue ();
            }
          }),
          Box.createHorizontalGlue ()
          ),
        ComponentFactory.createHorizontalBox (
          Box.createHorizontalStrut (7),
          Box.createHorizontalGlue (),
          ComponentFactory.setPreferredSize (
            Multilingual.mlnText (ComponentFactory.createLabel ("threshold"), "ja", "閾値"),
            60, 16),
          ComponentFactory.createNumberSpinner (dbgPopupIBPThresholdModel = new SpinnerNumberModel (0, 0, 0x7fffffff, 1), 10, new ChangeListener () {
            @Override public void stateChanged (ChangeEvent ce) {
              dbgPopupIBPThresholdValue = dbgPopupIBPThresholdModel.getNumber ().intValue ();
            }
          }),
          Box.createHorizontalGlue ()
          ),
        dbgPopupIBPClearMenuItem =
        Multilingual.mlnText (ComponentFactory.createMenuItem ("Clear Breakpoint", 'C', popupActionListener), "ja", "ブレークポイントを消去")
        ) :
      null,
      dbgPopupHexMenu =
      ComponentFactory.createMenu (
        "XXXXXXXX", KeyEvent.VK_UNDEFINED,
        dbgPopupDisMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Disassemble", 'D', popupActionListener), "ja", "逆アセンブル"),
        dbgPopupMemMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Memory Dump", 'M', popupActionListener), "ja", "メモリダンプ")
        ),
      dbgPopupCopyMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Copy", 'C', popupActionListener), "ja", "コピー"),
      dbgPopupSelectAllMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Select All", 'A', popupActionListener), "ja", "すべて選択")
      );

  }  //dbgMakePopup()

  //dbgShowPopup (me, textArea, dis)
  //  ポップアップメニューを表示する
  public static void dbgShowPopup (MouseEvent me, JTextArea textArea, boolean dis) {
    dbgEventMask++;
    int x = me.getX ();
    int y = me.getY ();
    //int p = textArea.viewToModel (me.getPoint ());  //クリックされた位置。viewToModel2Dは9から
    int p = textArea.viewToModel2D (me.getPoint ());  //クリックされた位置。viewToModel2Dは9から
    DisassembleList.ddpPopupAddress = -1;  //クリックされた行のアドレス
    if (dis) {
      int i = Arrays.binarySearch (DisassembleList.ddpSplitArray, 1, DisassembleList.ddpItemCount, p + 1);
      i = (i >> 31 ^ i) - 1;  //クリックされた項目の番号
      DisassembleList.ddpPopupAddress = DisassembleList.ddpAddressArray[i];  //クリックされた項目の先頭アドレス
    }
    int start = textArea.getSelectionStart ();  //選択範囲の開始位置
    int end = textArea.getSelectionEnd ();  //選択範囲の終了位置
    String text = textArea.getText ();  //テキスト全体
    int length = text.length ();  //テキスト全体の長さ
    if ((start == end ||  //選択範囲がないか
         p < start || end <= p) &&  //選択範囲の外側がクリックされて
        0 <= p && p < length && isWord (text.charAt (p))) {  //クリックされた位置に単語があるとき
      //クリックされた位置にある単語を選択する
      for (start = p; 0 < start && isWord (text.charAt (start - 1)); start--) {
      }
      for (end = p + 1; end < length && isWord (text.charAt (end)); end++) {
      }
      textArea.select (start, end);
    }
    dbgHexSelected = false;
    if (start < end) {  //選択範囲があるとき
      textArea.requestFocusInWindow ();  //フォーカスがないと選択範囲が見えない
      //選択範囲にある16進数の文字を取り出す
      //  以下の条件を加える
      //    選択範囲に16進数以外の単語の文字がないこと
      //    選択範囲に16進数の文字が9文字以上ないこと
      //    16進数の文字が偶数文字ずつの塊になっていること
      dbgHexValue = 0;
      int n = 0;
      for (int i = start; i < end; i++) {
        int t;
        if ((t = Character.digit (text.charAt (i), 16)) >= 0) {  //16進数の文字
          dbgHexValue = dbgHexValue << 4 | t;
          if (n >= 8 ||  //選択範囲に16進数の文字が9文字以上ある
              i + 1 >= end || (t = Character.digit (text.charAt (i + 1), 16)) < 0) {  //16進数の文字が偶数文字ずつの塊になっていない
            n = 0;
            break;
          }
          dbgHexValue = dbgHexValue << 4 | t;
          n += 2;
          i++;
        } else if (isWord (text.charAt (i))) {  //16進数以外の単語の文字
          n = 0;
          break;
        }
      }
      dbgHexSelected = n > 0;
      try {
        //Rectangle r = textArea.modelToView (start).getBounds ();  //modelToView2Dは9から
        Rectangle r = textArea.modelToView2D (start).getBounds ();  //modelToView2Dは9から
        //Rectangle s = textArea.modelToView (end - 1).getBounds ();  //modelToView2Dは9から
        Rectangle s = textArea.modelToView2D (end - 1).getBounds ();  //modelToView2Dは9から
        if (r.y == s.y) {  //選択範囲が1行だけのとき
          //選択範囲を隠してしまわないようにポップアップを選択範囲の下側に表示する
          y = r.y + r.height;
        }
      } catch (BadLocationException ble) {
      }
    }
    //逆アセンブルリストでコアが止まっていて選択範囲がなくてクリックされた行のアドレスがわかるとき命令ブレークポイントメニューが有効
    if (InstructionBreakPoint.IBP_ON) {
      if (dis && mpuTask == null && DisassembleList.ddpPopupAddress != -1) {
        ComponentFactory.setText (dbgPopupIBPMenu, fmtHex8 (DisassembleList.ddpPopupAddress));
        TreeMap<Integer,InstructionBreakPoint.InstructionBreakRecord> pointTable = InstructionBreakPoint.ibpPointTable;
        InstructionBreakPoint.InstructionBreakRecord r = pointTable.get (DisassembleList.ddpPopupAddress);
        if (r != null) {  //命令ブレークポイントがあるとき
          dbgPopupIBPCurrentModel.setValue (Integer.valueOf (dbgPopupIBPCurrentValue = r.ibrValue));  //現在値
          dbgPopupIBPThresholdModel.setValue (Integer.valueOf (dbgPopupIBPThresholdValue = r.ibrThreshold));  //閾値
          dbgPopupIBPClearMenuItem.setEnabled (true);  //消去できる
        } else {  //命令ブレークポイントがないとき
          dbgPopupIBPCurrentModel.setValue (Integer.valueOf (dbgPopupIBPCurrentValue = 0));  //現在値
          dbgPopupIBPThresholdModel.setValue (Integer.valueOf (dbgPopupIBPThresholdValue = 0));  //閾値
          dbgPopupIBPClearMenuItem.setEnabled (false);  //消去できない
        }
        ComponentFactory.setVisible (dbgPopupIBPMenu, true);
      } else {
        ComponentFactory.setVisible (dbgPopupIBPMenu, false);
      }
    }
    //16進数が選択されていれば16進数メニューが有効
    if (dbgHexSelected) {
      ComponentFactory.setText (dbgPopupHexMenu, fmtHex8 (dbgHexValue));
      ComponentFactory.setVisible (dbgPopupHexMenu, true);
    } else {
      ComponentFactory.setVisible (dbgPopupHexMenu, false);
    }
    //選択範囲があればコピーが有効
    ComponentFactory.setEnabled (dbgPopupCopyMenuItem, clpClipboard != null && start < end);
    //クリップボードがあればすべて選択が有効
    ComponentFactory.setEnabled (dbgPopupSelectAllMenuItem, clpClipboard != null);
    //ポップアップメニューを表示する
    dbgPopupTextArea = textArea;
    dbgPopupMenu.show (textArea, x, y);
    dbgEventMask--;
  }  //dbgShowPopup(MouseEvent,JTextArea,boolean)

  public static boolean isWord (char c) {
    return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '_';
  }  //isWord(char)

  //dbgCopy ()
  //  コピー
  public static void dbgCopy () {
    clpCopy (dbgPopupTextArea.getSelectedText ());
  }  //dbgCopy()

  //dbgSelectAll ()
  //  すべて選択
  public static void dbgSelectAll () {
    if (clpClipboard != null) {
      //すべて選択する
      dbgEventMask++;
      dbgPopupTextArea.selectAll ();
      dbgPopupTextArea.requestFocusInWindow ();
      dbgEventMask--;
    }
  }  //dbgSelectAll()

  //dbgUpdate ()
  //  デバッグウインドウを更新する
  //  コアのrun()の末尾でdbgVisibleMask!=0のとき呼び出す
  public static void dbgUpdate () {
    if ((dbgVisibleMask & DBG_DRP_VISIBLE_MASK) != 0) {
      RegisterList.drpUpdate ();  //レジスタウインドウを更新する
    }
    if (ProgramFlowVisualizer.PFV_ON) {
      if ((dbgVisibleMask & DBG_PFV_VISIBLE_MASK) != 0) {
        if (ProgramFlowVisualizer.pfvTimer == 0) {
          ProgramFlowVisualizer.pfvUpdate ();  //プログラムフロービジュアライザを更新する
        } else {
          ProgramFlowVisualizer.pfvTimer--;
        }
      }
    }
    if (RasterBreakPoint.RBP_ON) {
      if ((dbgVisibleMask & DBG_RBP_VISIBLE_MASK) != 0) {
        if (RasterBreakPoint.rbpTimer == 0) {
          RasterBreakPoint.rbpUpdateFrame ();  //ラスタブレークポイントウインドウを更新する
        } else {
          RasterBreakPoint.rbpTimer--;
        }
      }
    }
    if (ScreenModeTest.SMT_ON) {
      if ((dbgVisibleMask & DBG_SMT_VISIBLE_MASK) != 0) {
        if (ScreenModeTest.smtTimer == 0) {
          ScreenModeTest.smtUpdateFrame ();  //表示モードテストウインドウを更新する
        } else {
          ScreenModeTest.smtTimer--;
        }
      }
    }
    if (RootPointerList.RTL_ON) {
      if ((dbgVisibleMask & DBG_RTL_VISIBLE_MASK) != 0) {
        if (RootPointerList.rtlTimer == 0) {
          RootPointerList.rtlTimer = RootPointerList.RTL_INTERVAL - 1;
          RootPointerList.rtlUpdateFrame ();  //ルートポインタリストを更新する
        } else {
          RootPointerList.rtlTimer--;
        }
      }
    }
    if (SpritePatternViewer.SPV_ON) {
      if ((dbgVisibleMask & DBG_SPV_VISIBLE_MASK) != 0) {
        if (SpritePatternViewer.spvTimer == 0) {
          SpritePatternViewer.spvTimer = SpritePatternViewer.SPV_INTERVAL - 1;
          SpritePatternViewer.spvUpdateFrame ();  //スプライトパターンビュアを更新する
        } else {
          SpritePatternViewer.spvTimer--;
        }
      }
    }
    if (PaletteViewer.PLV_ON) {
      if ((dbgVisibleMask & DBG_PLV_VISIBLE_MASK) != 0) {
        if (PaletteViewer.plvTimer == 0) {
          PaletteViewer.plvTimer = PaletteViewer.PLV_INTERVAL - 1;
          PaletteViewer.plvUpdateFrame ();  //スプライトパターンビュアを更新する
        } else {
          PaletteViewer.plvTimer--;
        }
      }
    }
    if (ATCMonitor.ACM_ON) {
      if ((dbgVisibleMask & DBG_ACM_VISIBLE_MASK) != 0) {
        if (ATCMonitor.acmTimer == 0) {
          ATCMonitor.acmTimer = ATCMonitor.ACM_INTERVAL - 1;
          ATCMonitor.acmUpdateFrame ();  //アドレス変換キャッシュモニタを更新する
        } else {
          ATCMonitor.acmTimer--;
        }
      }
    }
  }  //dbgUpdate()

  //dbgDoStopOnError ()
  //  エラーで停止する
  //  エラーを検出して例外スタックフレームを構築した後にdbgStopOnErrorならば呼び出してコアを停止させる
  //
  //  Human68kの_BUS_ERRの中では停止させない
  //  human302のシステムディスクで起動した場合、
  //  SCSIボード、RS-232Cボード、MIDIボードのテストで_BUS_ERRが呼び出されてバスエラーが発生する
  //    bus error on reading from 00EA0044 at 0000E2F4
  //    bus error on reading from 00EAFC04 at 0002D04A
  //    bus error on reading from 00EAFC14 at 0002D04A
  //    bus error on reading from 00EAFA01 at 0005CD54
  //  _BUS_ERRはレベル0で入ったDOSコールの番号を更新しないので、_BUS_ERRの中かどうかはpcで判断する
  //    0x0000e342 <= pc0 && pc0 < 0x0000e3b6  human200/human201の_BUS_ERR
  //    0x0000e3c8 <= pc0 && pc0 < 0x0000e43c  human202の_BUS_ERR
  //    0x0000e1a8 <= pc0 && pc0 < 0x0000e21c  human203の_BUS_ERR
  //    0x0000e256 <= pc0 && pc0 < 0x0000e2ca  human215の_BUS_ERR
  //    0x0000e174 <= pc0 && pc0 < 0x0000e1e8  human301の_BUS_ERR
  //    0x0000e28a <= pc0 && pc0 < 0x0000e2fe  human302の_BUS_ERR
  //
  //  DOSコールで発生した特権違反では停止させない
  //
  public static boolean dbgDoStopOnError () {
    if (MainMemory.mmrHumanVersion <= 0) {  //Human68kでないか未確認
      return true;
    }
    if ((regOC & 0xff00) == 0xff00 &&  //DOSコールで発生した
        M68kException.m6eNumber == M68kException.M6E_PRIVILEGE_VIOLATION) {  //特権違反
      return false;
    }
    String message = (
      M68kException.m6eNumber < 0 ?
      fmtHex8 (new StringBuilder ("breaked").append (" at "), regPC0).toString () :
      M68kException.m6eNumber <= M68kException.M6E_ADDRESS_ERROR ?
      fmtHex8 (fmtHex8 (new StringBuilder ("ERROR: ").append (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber])
                        .append (M68kException.m6eDirection == 0 ? " on writing to " : " on reading from "), M68kException.m6eAddress)
               .append (" at "), regPC0).toString () :
      fmtHex8 (new StringBuilder (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber])
               .append (" at "), regPC0).toString ()
      );
    System.out.println (message);
    if (!(M68kException.m6eNumber == M68kException.M6E_ACCESS_FAULT &&
          0x0000e100 <= regPC0 && regPC0 < 0x0000e500)) {  //_BUS_ERRの中で発生したバスエラーでないとき
      mpuStop (message);
      return true;
    }
    return false;
  }  //dbgDoStopOnError()

  //dbgDoubleBusFault ()
  //  ダブルバスフォルト
  public static void dbgDoubleBusFault () {
    String message =
      fmtHex8 (fmtHex8 (new StringBuilder ("FATAL ERROR: ").append (M68kException.M6E_ERROR_NAME[M68kException.m6eNumber])
                        .append (M68kException.m6eDirection == 0 ? " on writing to " : " on reading from "), M68kException.m6eAddress)
               .append (" at "), regPC0).toString ();
    System.out.println (message);
    mpuStop (message);
  }  //dbgDoubleBusFault()



  //========================================================================================
  //$$RSC ResourceFile

  public static final HashMap<String,byte[]> rscResourceCache = new HashMap<String,byte[]> ();

  //array = rscGetResource (name, sizes...)
  //  リソースファイルを読み込む。null=読み込めなかった
  //  ファイル名をコンマで区切る機能はない。XEiJ.jarの中なので必要ない
  //  *.zipや*.gzは非対応。XEiJ.jarの中なので必要ない
  //  キャッシュした配列をそのまま返すので書き換えないように注意すること
  public static byte[] rscGetResource (String name, int... sizes) {
    byte[] array = rscResourceCache.get (name);  //キャッシュから出す
    if (array != null) {  //読み込み済み
      return array;
    }
    array = new byte[1024 * 64];  //最初は64KB
    int size = 0;  //これまでに読み込んだ長さ
    try (BufferedInputStream bis = new BufferedInputStream (XEiJ.class.getResourceAsStream ("../data/" + name))) {
      for (;;) {
        if (size == array.length) {  //配列が一杯
          byte[] newArray = new byte[array.length * 2];  //2倍に伸ばした配列を作る
          System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
          array = newArray;  //新しい配列に移行する
        }
        int step = bis.read (array, size, array.length - size);  //続きを読み込む。今回読み込んだ長さ
        if (step == -1) {  //終わり
          break;
        }
        size += step;  //これまでに読み込んだ長さ
      }
      if (size < array.length) {  //配列が長すぎる
        byte[] newArray = new byte[size];  //切り詰めた配列を作る
        System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
        array = newArray;  //新しい配列に移行する
      }
      boolean fit = sizes.length == 0;
      if (!fit) {
        for (int i = 0; i < sizes.length; i++) {
          if (size == sizes[i]) {  //サイズが合っている
            fit = true;
            break;
          }
        }
      }
      if (fit) {
        System.out.println (Multilingual.mlnJapanese ?
                            name + " を読み込みました" :
                            name + " was read");
        rscResourceCache.put (name, array);  //キャッシュに入れる
        return array;  //try-with-resourcesなのでここでクローズされる
      }
      System.out.println (Multilingual.mlnJapanese ?
                          name + " のサイズが違います" :
                          name + " has wrong size");
      return null;  //try-with-resourcesなのでここでクローズされる
    } catch (IOException ioe) {
    }
    //try-with-resourcesなのでここでクローズされる
    System.out.println (Multilingual.mlnJapanese ?
                        name + " を読み込めません" :
                        name + " cannot be read");
    return null;
  }

  //string = rscGetResourceText (name, charset)
  //  リソースファイルからテキストを読み込む
  public static String rscGetResourceText (String name) {
    return rscGetResourceText (name, "UTF-8");
  }
  public static String rscGetResourceText (String name, String charset) {
    byte[] array = rscGetResource (name);
    if (name != null) {
      try {
        return new String (array, charset);
      } catch (UnsupportedEncodingException uee) {
      }
    }
    return "";
  }

  public static final Pattern RSC_ZIP_SEPARATOR = Pattern.compile ("(?<=\\.(?:jar|zip))(?:/|\\\\)(?=.)", Pattern.CASE_INSENSITIVE);
  public static String rscLastFileName = null;  //最後に読み込んだファイル名

  //array = rscGetFile (names, sizes...)
  //  ファイルを読み込む。null=読み込めなかった
  //  コンマで区切られたファイルを順に探して最初に読み込めたものを返す
  //  *.zip/entryを指定するとエントリを読み込む
  //  *.gzを指定すると解凍する
  public static byte[] rscGetFile (String names, int... sizes) {
    for (String name : names.split (",")) {  //コンマで区切る
      name = name.trim ();  //前後の空白を削除する
      if (name.length () == 0 || name.equalsIgnoreCase ("none")) {
        continue;
      }
      String[] zipSplittedName = RSC_ZIP_SEPARATOR.split (name, 2);  // *.zip/entryを*.zipとentryに分ける
      InputStream is = null;
      if (zipSplittedName.length < 2) {  // *.zip/entryではない
        File file = new File (name);
        if (file.isFile ()) {  //ファイルがある
          try {
            is = new FileInputStream (file);  //ファイルを開く
          } catch (IOException ioe) {
          }
        } else {  //ファイルがない
          System.out.println (Multilingual.mlnJapanese ?
                              name + " がありません" :
                              name + " does not exist");
          continue;
        }
      } else {  // *.zip/entry
        String zipName = zipSplittedName[0];  // *.zip
        String entryName = zipSplittedName[1];  //entry
        if (new File (zipName).isFile ()) {  //ファイルがある
          try {
            ZipFile zipFile = new ZipFile (zipName);  //ファイル
            ZipEntry zipEntry = zipFile.getEntry (entryName);  //エントリ
            if (zipEntry != null) {  //エントリがある
              is = zipFile.getInputStream (zipEntry);  //エントリを開く
            } else {  //エントリがない
              System.out.println (Multilingual.mlnJapanese ?
                                  zipName + " に " + zipEntry + " がありません" :
                                  zipName + " does not include " + zipEntry);
            }
          } catch (IOException ioe) {
          }
        } else {  //ファイルがない
          System.out.println (Multilingual.mlnJapanese ?
                              zipName + " がありません" :
                              zipName + " does not exist");
          continue;
        }
      }
      if (is != null) {  //開けた
        try {
          is = new BufferedInputStream (is);
          if (name.toLowerCase ().endsWith (".gz")) {  // *.gz
            is = new GZIPInputStream (is);  //展開する
          }
          byte[] array = new byte[1024 * 64];  //最初は64KB
          int size = 0;  //これまでに読み込んだ長さ
          for (;;) {
            if (size == array.length) {  //配列が一杯
              byte[] newArray = new byte[array.length * 2];  //2倍に伸ばした配列を作る
              System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
              array = newArray;  //新しい配列に移行する
            }
            int step = is.read (array, size, array.length - size);  //続きを読み込む。今回読み込んだ長さ
            if (step == -1) {  //終わり
              break;
            }
            size += step;  //これまでに読み込んだ長さ
          }
          is.close ();  //ここはtry-with-resourcesではないので明示的にクローズすること
          is = null;
          if (size < array.length) {  //配列が長すぎる
            byte[] newArray = new byte[size];  //切り詰めた配列を作る
            System.arraycopy (array, 0, newArray, 0, size);  //読み込んだ部分を新しい配列に移す
            array = newArray;  //新しい配列に移行する
          }
          boolean fit = sizes.length == 0;
          if (!fit) {
            for (int i = 0; i < sizes.length; i++) {
              if (size == sizes[i]) {  //サイズが合っている
                fit = true;
                break;
              }
            }
          }
          if (fit) {
            System.out.println (Multilingual.mlnJapanese ?
                                name + " を読み込みました" :
                                name + " was read");
            rscLastFileName = name;  //最後に読み込んだファイル名
            return array;  //配列を返す
          }
          System.out.println (Multilingual.mlnJapanese ?
                              name + " のサイズが違います" :
                              name + " has wrong size");
          continue;
        } catch (IOException ioe) {
        }
        if (is != null) {
          try {
            is.close ();  //ここはtry-with-resourcesではないので明示的にクローズすること
            is = null;
          } catch (IOException ioe) {
          }
        }
      }  //if 開けた
      System.out.println (Multilingual.mlnJapanese ?
                          name + " を読み込めません" :
                          name + " cannot be read");
    }  //for name
    //読み込めなかった
    //ファイル名が指定されたときはメッセージが表示される
    //ファイル名が指定されなかったときはエラーメッセージも表示されない
    return null;
  }

  //string = rscGetTextFile (name)
  //string = rscGetTextFile (name, charset)
  //  テキストファイルを読み込む
  public static String rscGetTextFile (String name) {
    return rscGetTextFile (name, "UTF-8");
  }
  public static String rscGetTextFile (String name, String charset) {
    byte[] array = rscGetFile (name);
    if (array != null) {
      try {
        return new String (array, charset);
      } catch (UnsupportedEncodingException uee) {
      }
    }
    return "";
  }

  //mask = rscShowError (message, mask)
  //  ファイル操作に失敗したときに表示するダイアログ
  public static final int RSC_A_MASK = 1;  //中止
  public static final int RSC_R_MASK = 2;  //再実行
  public static final int RSC_I_MASK = 4;  //無視
  public static final String RSC_A_EN = "Abort";
  public static final String RSC_R_EN = "Retry";
  public static final String RSC_I_EN = "Ignore";
  public static final String RSC_A_JA = "中止";
  public static final String RSC_R_JA = "再実行";
  public static final String RSC_I_JA = "無視";
  public static final String[][] RSC_EN_OPTIONS = {
    { RSC_A_EN                     },
    { RSC_A_EN                     },
    {           RSC_R_EN           },
    { RSC_A_EN, RSC_R_EN           },
    {                     RSC_I_EN },
    { RSC_A_EN,           RSC_I_EN },
    {           RSC_R_EN, RSC_I_EN },
    { RSC_A_EN, RSC_R_EN, RSC_I_EN },
  };
  public static final String[][] RSC_JA_OPTIONS = {
    { RSC_A_JA                     },
    { RSC_A_JA                     },
    {           RSC_R_JA           },
    { RSC_A_JA, RSC_R_JA           },
    {                     RSC_I_JA },
    { RSC_A_JA,           RSC_I_JA },
    {           RSC_R_JA, RSC_I_JA },
    { RSC_A_JA, RSC_R_JA, RSC_I_JA },
  };
  public static int rscShowError (String message, int mask) {
    System.out.println (message);
    mask &= RSC_A_MASK | RSC_R_MASK | RSC_I_MASK;
    if (mask == 0) {
      mask = RSC_A_MASK;
    }
    String[] options = (Multilingual.mlnJapanese ? RSC_JA_OPTIONS : RSC_EN_OPTIONS)[mask];
    int def = Integer.numberOfTrailingZeros (mask);  //デフォルトの選択肢。0,1,2。中止、再実行、無視の順で最初に見つかったもの
    pnlExitFullScreen (true);
    int bit = JOptionPane.showOptionDialog (
      null,  //parentComponent
      message,  //message
      Multilingual.mlnJapanese ? "ファイル操作エラー" : "File operation error",  //title
      JOptionPane.YES_NO_CANCEL_OPTION,  //optionType
      JOptionPane.ERROR_MESSAGE,  //messageType
      null,  //icon
      options,  //options
      options[def]);  //initialValue
    if (bit == JOptionPane.CLOSED_OPTION) {  //閉じた。-1
      bit = def;
    }
    return 1 << bit;
  }

  //success = rscPutTextFile (name, string)
  //success = rscPutTextFile (name, strings)
  //success = rscPutTextFile (name, string, charset)
  //success = rscPutTextFile (name, strings, charset)
  //  テキストファイルに書き出す
  public static boolean rscPutTextFile (String name, String string) {
    return rscPutTextFile (name, string, "UTF-8");
  }
  public static boolean rscPutTextFile (String name, ArrayList<String> strings) {
    return rscPutTextFile (name, strings, "UTF-8");
  }
  public static boolean rscPutTextFile (String name, String string, String charset) {
    ArrayList<String> strings = new ArrayList<String> ();
    strings.add (string);
    return rscPutTextFile (name, strings, charset);
  }
  public static boolean rscPutTextFile (String name, ArrayList<String> strings, String charset) {
    String nameTmp = name + ".tmp";
    String nameBak = name + ".bak";
    File file = new File (name);
    File fileTmp = new File (nameTmp);
    File fileBak = new File (nameBak);
    //親ディレクトリがなければ作る
    File parentDirectory = file.getParentFile ();  //親ディレクトリ
    if (parentDirectory != null && !parentDirectory.isDirectory ()) {  //親ディレクトリがない
      if (!parentDirectory.mkdirs ()) {  //親ディレクトリを作る。必要ならば遡って作る。作れなかった
        System.out.println (parentDirectory.getPath () + (Multilingual.mlnJapanese ? " を作れません" : " cannot be created"));
        return false;
      }
    }
    //name.tmpがあればname.tmpを削除する
    if (fileTmp.exists ()) {  //name.tmpがある
      if (!fileTmp.delete ()) {  //name.tmpを削除する。削除できなかった
        System.out.println (nameTmp + (Multilingual.mlnJapanese ? " を削除できません" : " cannot be deleted"));
        return false;
      }
    }
    //name.tmpに出力する
    try (BufferedWriter bw = new BufferedWriter (new FileWriter (nameTmp, Charset.forName (charset)))) {
      for (String string : strings) {
        bw.write (string);
      }
    } catch (IOException ioe) {
      ioe.printStackTrace ();
      System.out.println (nameTmp + (Multilingual.mlnJapanese ? " に書き出せません" : " cannot be written"));
      return false;
    }
    //nameがあればnameをname.bakにリネームする
    boolean fileExists = file.exists ();
    if (fileExists) {  //nameがある
      //name.bakがあればname.bakを削除する
      if (fileBak.exists ()) {  //name.bakがある
        if (!fileBak.delete ()) {  //name.bakを削除する。削除できなかった
          System.out.println (nameBak + (Multilingual.mlnJapanese ? " を削除できません" : " cannot be deleted"));
          return false;
        }
      }
      //nameをname.bakにリネームする
      if (!file.renameTo (fileBak)) {  //nameをname.bakにリネームする。リネームできなかった
        System.out.println (name + (Multilingual.mlnJapanese ? " を " : " cannot be renamed to ") + nameBak + (Multilingual.mlnJapanese ? " にリネームできません" : ""));
        return false;
      }
    }
    //name.tmpをnameにリネームする
    if (!fileTmp.renameTo (file)) {  //name.tmpをnameにリネームする。リネームできなかった
      System.out.println (nameTmp + (Multilingual.mlnJapanese ? " を " : " cannot be renamed to ") + name + (Multilingual.mlnJapanese ? " にリネームできません" : ""));
      return false;
    }
    if (fileExists) {  //nameがあった
      System.out.println (name + (Multilingual.mlnJapanese ? " を更新しました" : " was updated"));
    } else {  //nameがあった
      System.out.println (name + (Multilingual.mlnJapanese ? " を作りました" : " was created"));
    }
    return true;
  }

  //success = rscPutFile (name, array)
  //success = rscPutFile (name, array, offset, length)
  //success = rscPutFile (name, array, offset, length, longLength2)
  //  ファイルに書き出す
  //  nameにarray[offset..offset+length-1]とlongLength2-length個の0を書き出す
  //  親ディレクトリがなければ作る
  //  同じ内容のファイルが既にあるときは更新しない
  //  *.zip/entryは非対応
  public static boolean rscPutFile (String name, byte[] array) {
    return rscPutFile (name, array, 0, array.length, (long) array.length);
  }
  public static boolean rscPutFile (String name, byte[] array, int offset, int length) {
    return rscPutFile (name, array, offset, length, (long) length);
  }
  public static boolean rscPutFile (String name, byte[] array, int offset, int length, long longLength2) {
    if (RSC_ZIP_SEPARATOR.matcher (name).matches ()) {  // *.zip/entry
      // *.zip/entryのとき確実に弾かないとファイルを破壊するおそれがある
      return false;
    }
    File file = new File (name);
    boolean fileExists = file.isFile ();  //true=同じ名前のファイルがある
    if (fileExists && file.length () == longLength2) {  //同じ名前で同じ長さのファイルがある
    comparison:
      {
        try (BufferedInputStream bis = new BufferedInputStream (new FileInputStream (file))) {
          byte[] buffer = new byte[(int) Math.min (Math.max ((long) length, longLength2 - (long) length), (long) (1024 * 1024))];  //最大1MBずつ読み込んで比較する
          int position = 0;
          while (position < length) {
            int step = bis.read (buffer, 0, Math.min (buffer.length, length - position));
            if (step == -1) {  //足りない。長さを確認してから始めたのだから途中で終わるはずがない
              break comparison;
            }
            int offsetPosition = offset + position;
            for (int i = 0; i < step; i++) {
              if (buffer[i] != array[offsetPosition + i]) {  //一致しない
                break comparison;
              }
            }
            position += step;
          }
          long longPosition2 = (long) length;
          while (longPosition2 < longLength2) {
            int step = bis.read (buffer, 0, (int) Math.min ((long) buffer.length, longLength2 - longPosition2));
            if (step == -1) {  //足りない。長さを確認してから始めたのだから途中で終わるはずがない
              break comparison;
            }
            for (int i = 0; i < step; i++) {
              if (buffer[i] != 0) {  //一致しない
                break comparison;
              }
            }
            longPosition2 += (long) step;
          }
          return true;  //一致した
        } catch (IOException ioe) {
        }
      }  //match
    }  //if 同じ名前で同じ長さのファイルがある
    String nameTmp = name + ".tmp";
    File fileTmp = new File (nameTmp);
    String nameBak = name + ".bak";
    File fileBak = new File (nameBak);
  retry:
    for (;;) {
      File parentDirectory = file.getParentFile ();  //親ディレクトリ
      if (parentDirectory != null && !parentDirectory.isDirectory ()) {  //親ディレクトリがない
        String parentName = parentDirectory.getPath ();
        if (parentDirectory.mkdirs ()) {  //親ディレクトリを作る。必要ならば遡って作る。作れた
          System.out.println (Multilingual.mlnJapanese ?
                              parentName + " を作りました" :
                              parentName + " was created");
        } else {  //作れなかった
          switch (rscShowError (Multilingual.mlnJapanese ?
                                parentName + " を作れません" :
                                parentName + " cannot be created",
                                RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
          case RSC_A_MASK:
            break retry;
          case RSC_R_MASK:
            continue retry;
          }
        }
      }
      if (fileTmp.isFile ()) {  //name.tmpがある。前回異常終了して残骸が残っている場合など
        if (!fileTmp.delete ()) {  //name.tmpを削除する。削除できない
          switch (rscShowError (Multilingual.mlnJapanese ?
                                nameTmp + " を削除できません" :
                                nameTmp + " cannot be deleted",
                                RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
          case RSC_A_MASK:
            break retry;
          case RSC_R_MASK:
            continue retry;
          }
        }
      }
      try (OutputStream os = name.toLowerCase ().endsWith (".gz") ?
           new GZIPOutputStream (new BufferedOutputStream (new FileOutputStream (fileTmp))) {
             {
               //def.setLevel (Deflater.BEST_COMPRESSION);
               def.setLevel (Deflater.DEFAULT_COMPRESSION);
               //def.setLevel (Deflater.BEST_SPEED);
             }
           } :
           new BufferedOutputStream (new FileOutputStream (fileTmp))) {  //name.tmpに書き出す
        //array[offset..offset+length-1]を書き出す
        os.write (array, offset, length);
        //longLength2-length個の0を書き出す
        //  RandomAccessFile.setLength()は拡張部分の内容が定義されていないので使えない
        if ((long) length < longLength2) {
          byte[] buffer = new byte[(int) Math.min (longLength2 - (long) length, (long) (1024 * 1024))];  //最大1MBずつ書き出す
          Arrays.fill (buffer, 0, buffer.length, (byte) 0);  //念の為
          long longPosition2 = (long) length;
          while (longPosition2 < longLength2) {
            int step = (int) Math.min ((long) buffer.length, longLength2 - longPosition2);
            os.write (buffer, 0, step);
            longPosition2 += (long) step;
          }
        }
      } catch (IOException ioe) {
        switch (rscShowError (Multilingual.mlnJapanese ?
                              nameTmp + " に書き出せません" :
                              nameTmp + " cannot be written",
                              RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
        case RSC_A_MASK:
          break retry;
        case RSC_R_MASK:
          continue retry;
        }
      }
      if (fileExists && file.isFile ()) {  //同じ名前で内容が異なるファイルがある。リトライでなくなった可能性があるので確認し直す
        if (fileBak.isFile ()) {  //name.bakがある
          if (!fileBak.delete ()) {  //name.bakを削除する。削除できない
            switch (rscShowError (Multilingual.mlnJapanese ?
                                  nameBak + " を削除できません" :
                                  nameBak + " cannot be deleted",
                                  RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
            case RSC_A_MASK:
              break retry;
            case RSC_R_MASK:
              continue retry;
            }
          }
        }
        if (!file.renameTo (fileBak)) {  //nameをname.bakにリネームする。リネームできない
          switch (rscShowError (Multilingual.mlnJapanese ?
                                name + " を " + nameBak + " にリネームできません" :
                                name + " cannot be renamed to " + nameBak,
                                RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
          case RSC_A_MASK:
            break retry;
          case RSC_R_MASK:
            continue retry;
          }
        }
      }
      if (fileTmp.renameTo (file)) {  //name.tmpをnameにリネームする。リネームできた
        if (fileExists) {  //同じ名前のファイルがあった
          System.out.println (Multilingual.mlnJapanese ?
                              name + " を更新しました" :
                              name + " was updated");
        } else {  //同じ名前のファイルがなかった
          System.out.println (Multilingual.mlnJapanese ?
                              name + " を作りました" :
                              name + " was created");
        }
        return true;  //成功
      } else {  //リネームできない
        switch (rscShowError (Multilingual.mlnJapanese ?
                              nameTmp + " を " + name + " にリネームできません" :
                              nameTmp + " cannot be renamed to " + name,
                              RSC_A_MASK | RSC_R_MASK | RSC_I_MASK)) {
        case RSC_A_MASK:
          break retry;
        case RSC_R_MASK:
          continue retry;
        }
      }
      break;
    }  //retry
    if (fileExists) {  //同じ名前のファイルがあった
      System.out.println (Multilingual.mlnJapanese ?
                          name + " を更新できません" :
                          name + " cannot be updated");
    } else {  //同じ名前のファイルがなかった
      System.out.println (Multilingual.mlnJapanese ?
                          name + " を作れません" :
                          name + " cannot be created");
    }
    return false;  //失敗
  }



  //========================================================================================
  //$$ISM InputStream

  public static final Pattern ISM_ZIP_SEPARATOR = Pattern.compile ("(?<=\\.(?:jar|zip))(?:/|\\\\)(?=.)", Pattern.CASE_INSENSITIVE);

  //in = ismOpen (name)
  //  InputStreamを開く
  //  InputStreamを返す
  //    失敗したときはnullを返す
  //  ZIPファイルの中のファイルを指定できる
  //    ZIPファイルの中のファイルはZipInputStreamで開く
  //    ZIPファイルの中のファイル名は{ZIPファイル名}/{ZIPファイルの中のファイル名}で指定する
  //    JARファイルもZIPファイルとして開くことができる
  //  GZIPで圧縮されているファイルを指定できる
  //    GZIPで圧縮されているファイルはGZIPInputStreamで開く
  public static InputStream ismOpen (String name) {
    InputStream in = null;
    in = ismOpen (name, false);  //ファイルを開く
    if (in == null && name.indexOf ('/') < 0 && name.indexOf ('\\') < 0) {  //ファイルがないとき
      in = ismOpen (name, true);  //リソースを開く
    }
    return in;
  }  //ismOpen(String)
  public static InputStream ismOpen (String name, boolean useGetResource) {
    boolean gzipped = name.toLowerCase ().endsWith (".gz");  //true=GZIPファイルが指定された
    String[] zipSplittedName = ISM_ZIP_SEPARATOR.split (name, 2);  //ZIPファイル名とZIPファイルの中のファイル名に分ける
    String fileName = zipSplittedName[0];  //通常のファイル名またはZIPファイル名
    String zipEntryName = zipSplittedName.length < 2 ? null : zipSplittedName[1];  //ZIPファイルの中のファイル名
    InputStream in = null;
    try {
      if (useGetResource) {  //getResourceを使うとき
        if (false) {
          URL url = XEiJ.class.getResource (fileName);
          if (url != null) {  //ファイルがある
            in = url.openStream ();
          }
        } else {
          in = XEiJ.class.getResourceAsStream (fileName);
        }
      } else {
        File file = new File (fileName);
        if (file.exists ()) {  //ファイルがある
          in = new FileInputStream (file);
        }
      }
      if (in != null && zipEntryName != null) {  //ZIPファイルの中のファイルが指定されたとき
        ZipInputStream zin = new ZipInputStream (in);
        in = null;
        ZipEntry entry;
        while ((entry = zin.getNextEntry ()) != null) {  //指定されたファイル名のエントリを探す
          if (zipEntryName.equals (entry.getName ())) {  //エントリが見つかった
            in = zin;
            break;
          }
        }
        if (in == null) {
          System.out.println (Multilingual.mlnJapanese ? fileName + " の中に " + zipEntryName + " がありません" :
                              zipEntryName + " does not exist in " + fileName);
        }
      }
      if (in != null && gzipped) {  //GZIPで圧縮されたファイルが指定されたとき
        in = new GZIPInputStream (in);
      }
      if (in != null) {
        System.out.println (Multilingual.mlnJapanese ? (useGetResource ? "リソースファイル " : "ファイル ") + name + " を読み込みます" :
                            (useGetResource ? "Reading resource file " : "Reading file ") + name);
        return new BufferedInputStream (in);
      }
    } catch (Exception ioe) {
      if (prgVerbose) {
        prgPrintStackTraceOf (ioe);
      }
    }
    System.out.println (Multilingual.mlnJapanese ? (useGetResource ? "リソースファイル " : "ファイル ") + name + " が見つかりません" :
                        (useGetResource ? "Resource file " : "File ") + name + " is not found");
    return null;  //失敗
  }  //ismOpen(String,boolean)

  //k = ismRead (in, bb, o, l)
  //  InputStreamからバイトバッファに読み込む
  //  読み込んだ長さを返す
  //    エラーのときは-1を返す
  //  指定されたサイズまたはファイルの末尾まで読み込む
  //    k=in.read(bb,o,l)は1回で指定されたサイズを読み込めるとは限らない
  //  ブロックされる可能性があるのでコアの動作中にコアのスレッドから呼ばないほうがよい
  public static int ismRead (InputStream in, byte[] bb, int o, int l) {
    try {
      int k = 0;
      while (k < l) {
        int t = in.read (bb, o + k, l - k);
        if (t < 0) {
          break;
        }
        k += t;
      }
      return k;
    } catch (IOException ioe) {
      if (prgVerbose) {
        prgPrintStackTraceOf (ioe);
      }
    }
    return -1;
  }  //ismRead(InputStream,byte[],int,int)

  //k = ismSkip (in, l)
  //  InputStreamを読み飛ばす
  //  読み飛ばした長さを返す
  //    エラーのときは-1を返す
  //  指定されたサイズまたはファイルの末尾まで読み飛ばす
  //    k=in.skip(l)は1回で指定されたサイズを読み飛ばせるとは限らない
  //  ブロックされる可能性があるのでコアの動作中にコアのスレッドから呼ばないほうがよい
  public static int ismSkip (InputStream in, int l) {
    try {
      int k = 0;
      while (k < l) {
        //skip(long)はファイルの末尾でなくても0を返す可能性があるのでファイルの末尾の判定はread()で行う
        //skip(long)する前に毎回read()しないとskip()がファイルの末尾で止まらなくなるらしい
        if (in.read () < 0) {
          break;
        }
        k++;
        if (k < l) {
          int t = (int) in.skip ((long) (l - k));
          if (t < 0) {
            break;
          }
          k += t;
        }
      }
      return k;
    } catch (IOException ioe) {
      if (prgVerbose) {
        prgPrintStackTraceOf (ioe);
      }
    }
    return -1;
  }  //ismSkip(InputStream,int)

  //ismClose (in)
  //  InputStreamを閉じる
  //  in==nullのときは何もしない
  //  in.close()でIOExceptionを無視するだけ
  public static void ismClose (InputStream in) {
    try {
      if (in != null) {
        in.close ();
      }
    } catch (IOException ioe) {
      if (prgVerbose) {
        prgPrintStackTraceOf (ioe);
      }
    }
  }  //ismClose(InputStream)

  //length = ismLength (name, maxLength)
  //  ファイルの長さを数える
  //  ZIPファイルの中のファイルを指定できる
  //  GZIPで圧縮されているファイルを指定できる
  //  -1  ファイルがない
  public static int ismLength (String name, int maxLength) {
    int length;
    InputStream in = ismOpen (name);
    if (in == null) {  //ファイルがない
      length = -1;
    } else {  //ファイルがある
      length = ismSkip (in, maxLength);
      ismClose (in);
    }
    return length;
  }  //ismLength(String,int)

  //success = ismLoad (bb, o, l, names)
  //  ファイルからバイトバッファに読み込む
  //  ファイル名を,で区切って複数指定できる
  //    先頭から順に指定されたサイズまで読み込めるファイルを探す
  //    1つでも読み込むことができればその時点で成功、1つも読み込めなければ失敗
  //  成功したときtrueを返す
  //  ZIPファイルの中のファイルを指定できる
  //    ZIPファイルの中のファイルはZipInputStreamで開く
  //    ZIPファイルの中のファイル名は{ZIPファイル名}/{ZIPファイルの中のファイル名}で指定する
  //    JARファイルもZIPファイルとして開くことができる
  //  GZIPで圧縮されているファイルを指定できる
  //    GZIPで圧縮されているファイルはGZIPInputStreamで開く
  //  ブロックされることがあるのでコアの動作中にコアのスレッドから呼ばないほうがよい
  public static boolean ismLoad (byte[] bb, int o, int l, String names) {
    for (String name : names.split (",")) {  //先頭から順に
      if (name.length () != 0) {  //ファイル名が指定されているとき
        InputStream in = ismOpen (name);  //開く
        if (in != null) {  //開けたら
          int k = ismRead (in, bb, o, l);  //読み込んで
          ismClose (in);  //閉じる
          if (k == l) {  //指定されたサイズまで読み込めたら
            return true;  //成功
          }
        }
      }
    }
    return false;  //1つも読み込めなかったので失敗
  }  //ismLoad(byte[],int,int,String)

  //success = ismSave (bb, offset, length, path, verbose)
  //  バイトバッファからファイルに書き出す
  //  出力範囲がバッファに収まっているとき
  //    ファイルが既に存在していてファイルサイズと内容が一致しているときは更新しない
  //  出力範囲がバッファに収まっていないとき
  //    バッファからはみ出した部分をゼロクリアする
  //    RandomAccessFileのsetLengthを使うとファイルサイズを簡単に変更できるが、ファイルを伸ばしたときに書き込まれる内容が仕様で定義されていない
  //    同じ手順で同じ内容のファイルができない可能性があるのは困るので明示的に0を書き込んでクリアする
  public static boolean ismSave (byte[] bb, int offset, long length, String path, boolean verbose) {
    if (ISM_ZIP_SEPARATOR.split (path, 2).length != 1) {  //ZIPファイルの中のファイル
      if (verbose) {
        pnlExitFullScreen (true);
        JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? path + " に書き出せません" : "Cannot write " + path);
      }
      return false;
    }
    long step = 0;  //一度にゼロクリアする長さ。0=バッファに収まっている
    byte[] zz = null;  //ゼロクリア用の配列
    long pointer = (long) (bb.length - offset);  //バッファから出力できる長さ
    if (pointer < length) {  //バッファに収まっていない
      step = Math.min (1024L * 512, length - pointer);  //一度にゼロクリアする長さ。最大512KB
      zz = new byte[(int) step];  //ゼロクリア用の配列
      Arrays.fill (zz, (byte) 0);
    }
    //ファイル
    File file = new File (path);  //ファイル
    //ファイルが既に存在しているときはファイルサイズと内容が一致しているかどうか確認する
    if (step == 0 &&  //バッファに収まっている
        file.exists () && file.length () == length) {  //ファイルサイズが一致している
      //ファイルを読み込む
      if (length == 0L) {  //ファイルサイズが0で一致しているので成功
        return true;
      }
      InputStream in = ismOpen (path);
      if (in != null) {
        int l = (int) length;  //バッファに収まっているのだからintの範囲内
        byte[] tt = new byte[l];
        int k = ismRead (in, tt, 0, l);
        ismClose (in);
        if (k == l &&
            Arrays.equals (tt, bb.length == l ? bb : Arrays.copyOfRange (bb, offset, offset + l))) {  //内容が一致している
          return true;  //更新する必要がないので成功
        }
      }
    }  //check
    // *.tmpと*.bak
    String pathTmp = path + ".tmp";  // *.tmp
    String pathBak = path + ".bak";  // *.bak
    File fileTmp = new File (pathTmp);  // *.tmp
    File fileBak = new File (pathBak);  // *.bak
    // *.tmpを削除する
    if (fileTmp.exists ()) {  // *.tmpがあるとき
      if (!fileTmp.delete ()) {  // *.tmpを削除する
        if (verbose) {
          pnlExitFullScreen (true);
          JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? pathTmp + " を削除できません" : "Cannot delete " + pathTmp);
        }
        return false;
      }
    }
    // *.tmpに書き出す
    try (OutputStream out = path.toLowerCase ().endsWith (".gz") ?  //pathの末尾が".gz"のときpathTmpの末尾は".gz.tmp"であることに注意
         new GZIPOutputStream (new BufferedOutputStream (new FileOutputStream (fileTmp))) {
           {
             //def.setLevel (Deflater.BEST_COMPRESSION);
             def.setLevel (Deflater.DEFAULT_COMPRESSION);
             //def.setLevel (Deflater.BEST_SPEED);
           }
         } :
         new BufferedOutputStream (new FileOutputStream (fileTmp))) {  //try-with-resourcesは1.7から
      if (step == 0) {  //バッファに収まっている
        out.write (bb, offset, (int) length);  //OutputStreamのwriteの返り値はvoid。エラーが出なければ1回で最後まで書き出される
      } else {  //バッファに収まっていない
        out.write (bb, offset, (int) pointer);  //バッファから出力できる範囲
        for (; pointer < length; pointer += step) {
          out.write (zz, 0, (int) Math.min (step, length - pointer));  //バッファから出力できない範囲
        }
      }
    } catch (IOException ioe) {
      if (verbose) {
        prgPrintStackTraceOf (ioe);
        pnlExitFullScreen (true);
        JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? pathTmp + " に書き出せません" : "Cannot write " + pathTmp);
      }
      return false;
    }
    //ファイルを*.bakにリネームする
    //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
    if (file.exists ()) {  //ファイルがあるとき
      if (fileBak.exists ()) {  // *.bakがあるとき
        if (!fileBak.delete ()) {  // *.bakを削除する
          if (verbose) {
            pnlExitFullScreen (true);
            JOptionPane.showMessageDialog (null, Multilingual.mlnJapanese ? pathBak + " を削除できません" : "Cannot delete " + pathBak);
          }
          return false;
        }
      }
      if (!file.renameTo (fileBak)) {  //ファイルを*.bakにリネームする
        if (verbose) {
          pnlExitFullScreen (true);
          JOptionPane.showMessageDialog (
            null, Multilingual.mlnJapanese ? path + " を " + pathBak + " にリネームできません" : "Cannot rename " + path + " to " + pathBak);
        }
        return false;
      }
    }
    // *.tmpをファイルにリネームする
    //  javaのFileのrenameToはPerlと違って上書きしてくれないので明示的に削除またはリネームする必要がある
    if (!fileTmp.renameTo (file)) {  // *.tmpをファイルにリネームする
      if (verbose) {
        pnlExitFullScreen (true);
        JOptionPane.showMessageDialog (
          null, Multilingual.mlnJapanese ? pathTmp + " を " + path + " にリネームできません" : "Cannot rename " + pathTmp + " to " + path);
      }
      return false;
    }
    return true;
  }  //ismSave(byte[],int,long,String,boolean)



  //========================================================================================
  //$$FMT フォーマット変換
  //  Formatterは遅いので自前で展開する

  public static final char[] FMT_TEMP = new char[32];

  //--------------------------------------------------------------------------------
  //2進数変換
  //  ainNは'.'と'*'、binNは'0'と'1'に変換する
  //
  //  x          00 01
  //  x<<2       00 04
  //  x<<2&4     00 04
  //  x<<2&4^46  2e 2a
  //              .  *

  public static final char[] FMT_AIN4_BASE = ".......*..*...**.*...*.*.**..****...*..**.*.*.****..**.****.****".toCharArray ();
  public static final char[] FMT_BIN4_BASE = "0000000100100011010001010110011110001001101010111100110111101111".toCharArray ();

  //fmtAin4 (a, o, x)
  //fmtBin4 (a, o, x)
  //s = fmtAin4 (x)
  //s = fmtBin4 (x)
  //sb = fmtAin4 (sb, x)
  //sb = fmtBin4 (sb, x)
  //  4桁2進数変換
  public static void fmtAin4 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>  1 & 4 ^ 46);
    a[o +  1] = (char) (x       & 4 ^ 46);
    a[o +  2] = (char) (x <<  1 & 4 ^ 46);
    a[o +  3] = (char) (x <<  2 & 4 ^ 46);
  }  //fmtAin4(char[],int,int)
  public static void fmtBin4 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>>  3 & 1 | 48);
    a[o +  1] = (char) (x >>>  2 & 1 | 48);
    a[o +  2] = (char) (x >>>  1 & 1 | 48);
    a[o +  3] = (char) (x        & 1 | 48);
  }  //fmtBin4(char[],int,int)
  public static String fmtAin4 (int x) {
    return String.valueOf (FMT_AIN4_BASE, (x & 15) << 2, 4);
  }  //fmtAin4(int)
  public static String fmtBin4 (int x) {
    return String.valueOf (FMT_BIN4_BASE, (x & 15) << 2, 4);
  }  //fmtBin4(int)
  public static StringBuilder fmtAin4 (StringBuilder sb, int x) {
    return sb.append (FMT_AIN4_BASE, (x & 15) << 2, 6);
  }  //fmtAin4(StringBuilder,int)
  public static StringBuilder fmtBin4 (StringBuilder sb, int x) {
    return sb.append (FMT_BIN4_BASE, (x & 15) << 2, 6);
  }  //fmtBin4(StringBuilder,int)

  //fmtAin6 (a, o, x)
  //fmtBin6 (a, o, x)
  //s = fmtAin6 (x)
  //s = fmtBin6 (x)
  //sb = fmtAin6 (sb, x)
  //sb = fmtBin6 (sb, x)
  //  6桁2進数変換
  public static void fmtAin6 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>  3 & 4 ^ 46);
    a[o +  1] = (char) (x >>  2 & 4 ^ 46);
    a[o +  2] = (char) (x >>  1 & 4 ^ 46);
    a[o +  3] = (char) (x       & 4 ^ 46);
    a[o +  4] = (char) (x <<  1 & 4 ^ 46);
    a[o +  5] = (char) (x <<  2 & 4 ^ 46);
  }  //fmtAin6(char[],int,int)
  public static void fmtBin6 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>>  5 & 1 | 48);
    a[o +  1] = (char) (x >>>  4 & 1 | 48);
    a[o +  2] = (char) (x >>>  3 & 1 | 48);
    a[o +  3] = (char) (x >>>  2 & 1 | 48);
    a[o +  4] = (char) (x >>>  1 & 1 | 48);
    a[o +  5] = (char) (x        & 1 | 48);
  }  //fmtBin6(char[],int,int)
  public static String fmtAin6 (int x) {
    FMT_TEMP[ 0] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x       & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x <<  2 & 4 ^ 46);
    return String.valueOf (FMT_TEMP, 0, 6);
  }  //fmtAin6(int)
  public static String fmtBin6 (int x) {
    FMT_TEMP[ 0] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x        & 1 | 48);
    return String.valueOf (FMT_TEMP, 0, 6);
  }  //fmtBin6(int)
  public static StringBuilder fmtAin6 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x       & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x <<  2 & 4 ^ 46);
    return sb.append (FMT_TEMP, 0, 6);
  }  //fmtAin6(StringBuilder,int)
  public static StringBuilder fmtBin6 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x        & 1 | 48);
    return sb.append (FMT_TEMP, 0, 6);
  }  //fmtBin6(StringBuilder,int)

  //fmtAin8 (a, o, x)
  //fmtBin8 (a, o, x)
  //s = fmtAin8 (x)
  //s = fmtBin8 (x)
  //sb = fmtAin8 (sb, x)
  //sb = fmtBin8 (sb, x)
  //  8桁2進数変換
  public static void fmtAin8 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>  5 & 4 ^ 46);
    a[o +  1] = (char) (x >>  4 & 4 ^ 46);
    a[o +  2] = (char) (x >>  3 & 4 ^ 46);
    a[o +  3] = (char) (x >>  2 & 4 ^ 46);
    a[o +  4] = (char) (x >>  1 & 4 ^ 46);
    a[o +  5] = (char) (x       & 4 ^ 46);
    a[o +  6] = (char) (x <<  1 & 4 ^ 46);
    a[o +  7] = (char) (x <<  2 & 4 ^ 46);
  }  //fmtAin8(char[],int,int)
  public static void fmtBin8 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>>  7 & 1 | 48);
    a[o +  1] = (char) (x >>>  6 & 1 | 48);
    a[o +  2] = (char) (x >>>  5 & 1 | 48);
    a[o +  3] = (char) (x >>>  4 & 1 | 48);
    a[o +  4] = (char) (x >>>  3 & 1 | 48);
    a[o +  5] = (char) (x >>>  2 & 1 | 48);
    a[o +  6] = (char) (x >>>  1 & 1 | 48);
    a[o +  7] = (char) (x        & 1 | 48);
  }  //fmtBin8(char[],int,int)
  public static String fmtAin8 (int x) {
    FMT_TEMP[ 0] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x       & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x <<  2 & 4 ^ 46);
    return String.valueOf (FMT_TEMP, 0, 8);
  }  //fmtAin8(int)
  public static String fmtBin8 (int x) {
    FMT_TEMP[ 0] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x        & 1 | 48);
    return String.valueOf (FMT_TEMP, 0, 8);
  }  //fmtBin8(int)
  public static StringBuilder fmtAin8 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x       & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x <<  2 & 4 ^ 46);
    return sb.append (FMT_TEMP, 0, 8);
  }  //fmtAin8(StringBuilder,int)
  public static StringBuilder fmtBin8 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x        & 1 | 48);
    return sb.append (FMT_TEMP, 0, 8);
  }  //fmtBin8(StringBuilder,int)

  //fmtAin12 (a, o, x)
  //fmtBin12 (a, o, x)
  //s = fmtAin12 (x)
  //s = fmtBin12 (x)
  //sb = fmtAin12 (sb, x)
  //sb = fmtBin12 (sb, x)
  //  12桁2進数変換
  public static void fmtAin12 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>  9 & 4 ^ 46);
    a[o +  1] = (char) (x >>  8 & 4 ^ 46);
    a[o +  2] = (char) (x >>  7 & 4 ^ 46);
    a[o +  3] = (char) (x >>  6 & 4 ^ 46);
    a[o +  4] = (char) (x >>  5 & 4 ^ 46);
    a[o +  5] = (char) (x >>  4 & 4 ^ 46);
    a[o +  6] = (char) (x >>  3 & 4 ^ 46);
    a[o +  7] = (char) (x >>  2 & 4 ^ 46);
    a[o +  8] = (char) (x >>  1 & 4 ^ 46);
    a[o +  9] = (char) (x       & 4 ^ 46);
    a[o + 10] = (char) (x <<  1 & 4 ^ 46);
    a[o + 11] = (char) (x <<  2 & 4 ^ 46);
  }  //fmtAin12(char[],int,int)
  public static void fmtBin12 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>> 11 & 1 | 48);
    a[o +  1] = (char) (x >>> 10 & 1 | 48);
    a[o +  2] = (char) (x >>>  9 & 1 | 48);
    a[o +  3] = (char) (x >>>  8 & 1 | 48);
    a[o +  4] = (char) (x >>>  7 & 1 | 48);
    a[o +  5] = (char) (x >>>  6 & 1 | 48);
    a[o +  6] = (char) (x >>>  5 & 1 | 48);
    a[o +  7] = (char) (x >>>  4 & 1 | 48);
    a[o +  8] = (char) (x >>>  3 & 1 | 48);
    a[o +  9] = (char) (x >>>  2 & 1 | 48);
    a[o + 10] = (char) (x >>>  1 & 1 | 48);
    a[o + 11] = (char) (x        & 1 | 48);
  }  //fmtBin12(char[],int,int)
  public static String fmtAin12 (int x) {
    FMT_TEMP[ 0] = (char) (x >>  9 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >>  8 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >>  7 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >>  6 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[ 8] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[ 9] = (char) (x       & 4 ^ 46);
    FMT_TEMP[10] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[11] = (char) (x <<  2 & 4 ^ 46);
    return String.valueOf (FMT_TEMP, 0, 12);
  }  //fmtAin12(int)
  public static String fmtBin12 (int x) {
    FMT_TEMP[ 0] = (char) (x >>> 11 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>> 10 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>>  9 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>>  8 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[ 8] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[ 9] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[10] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[11] = (char) (x        & 1 | 48);
    return String.valueOf (FMT_TEMP, 0, 12);
  }  //fmtBin12(int)
  public static StringBuilder fmtAin12 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>  9 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >>  8 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >>  7 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >>  6 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[ 8] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[ 9] = (char) (x       & 4 ^ 46);
    FMT_TEMP[10] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[11] = (char) (x <<  2 & 4 ^ 46);
    return sb.append (FMT_TEMP, 0, 12);
  }  //fmtAin12(StringBuilder,int)
  public static StringBuilder fmtBin12 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>> 11 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>> 10 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>>  9 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>>  8 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[ 8] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[ 9] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[10] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[11] = (char) (x        & 1 | 48);
    return sb.append (FMT_TEMP, 0, 12);
  }  //fmtBin12(StringBuilder,int)

  //fmtAin16 (a, o, x)
  //fmtBin16 (a, o, x)
  //s = fmtAin16 (x)
  //s = fmtBin16 (x)
  //sb = fmtAin16 (sb, x)
  //sb = fmtBin16 (sb, x)
  //  16桁2進数変換
  public static void fmtAin16 (char[] a, int o, int x) {
    a[o     ] = (char) (x >> 13 & 4 ^ 46);
    a[o +  1] = (char) (x >> 12 & 4 ^ 46);
    a[o +  2] = (char) (x >> 11 & 4 ^ 46);
    a[o +  3] = (char) (x >> 10 & 4 ^ 46);
    a[o +  4] = (char) (x >>  9 & 4 ^ 46);
    a[o +  5] = (char) (x >>  8 & 4 ^ 46);
    a[o +  6] = (char) (x >>  7 & 4 ^ 46);
    a[o +  7] = (char) (x >>  6 & 4 ^ 46);
    a[o +  8] = (char) (x >>  5 & 4 ^ 46);
    a[o +  9] = (char) (x >>  4 & 4 ^ 46);
    a[o + 10] = (char) (x >>  3 & 4 ^ 46);
    a[o + 11] = (char) (x >>  2 & 4 ^ 46);
    a[o + 12] = (char) (x >>  1 & 4 ^ 46);
    a[o + 13] = (char) (x       & 4 ^ 46);
    a[o + 14] = (char) (x <<  1 & 4 ^ 46);
    a[o + 15] = (char) (x <<  2 & 4 ^ 46);
  }  //fmtAin16(char[],int,int)
  public static void fmtBin16 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>> 15 & 1 | 48);
    a[o +  1] = (char) (x >>> 14 & 1 | 48);
    a[o +  2] = (char) (x >>> 13 & 1 | 48);
    a[o +  3] = (char) (x >>> 12 & 1 | 48);
    a[o +  4] = (char) (x >>> 11 & 1 | 48);
    a[o +  5] = (char) (x >>> 10 & 1 | 48);
    a[o +  6] = (char) (x >>>  9 & 1 | 48);
    a[o +  7] = (char) (x >>>  8 & 1 | 48);
    a[o +  8] = (char) (x >>>  7 & 1 | 48);
    a[o +  9] = (char) (x >>>  6 & 1 | 48);
    a[o + 10] = (char) (x >>>  5 & 1 | 48);
    a[o + 11] = (char) (x >>>  4 & 1 | 48);
    a[o + 12] = (char) (x >>>  3 & 1 | 48);
    a[o + 13] = (char) (x >>>  2 & 1 | 48);
    a[o + 14] = (char) (x >>>  1 & 1 | 48);
    a[o + 15] = (char) (x        & 1 | 48);
  }  //fmtBin16(char[],int,int)
  public static String fmtAin16 (int x) {
    FMT_TEMP[ 0] = (char) (x >> 13 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >> 12 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >> 11 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >> 10 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >>  9 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x >>  8 & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x >>  7 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x >>  6 & 4 ^ 46);
    FMT_TEMP[ 8] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[ 9] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[10] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[11] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[12] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[13] = (char) (x       & 4 ^ 46);
    FMT_TEMP[14] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[15] = (char) (x <<  2 & 4 ^ 46);
    return String.valueOf (FMT_TEMP, 0, 16);
  }  //fmtAin16(int)
  public static String fmtBin16 (int x) {
    FMT_TEMP[ 0] = (char) (x >>> 15 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>> 14 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>> 13 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>> 12 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>> 11 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>> 10 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>>  9 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x >>>  8 & 1 | 48);
    FMT_TEMP[ 8] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[ 9] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[10] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[11] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[12] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[13] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[14] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[15] = (char) (x        & 1 | 48);
    return String.valueOf (FMT_TEMP, 0, 16);
  }  //fmtBin16(int)
  public static StringBuilder fmtAin16 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >> 13 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >> 12 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >> 11 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >> 10 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >>  9 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x >>  8 & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x >>  7 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x >>  6 & 4 ^ 46);
    FMT_TEMP[ 8] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[ 9] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[10] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[11] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[12] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[13] = (char) (x       & 4 ^ 46);
    FMT_TEMP[14] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[15] = (char) (x <<  2 & 4 ^ 46);
    return sb.append (FMT_TEMP, 0, 16);
  }  //fmtAin16(StringBuilder,int)
  public static StringBuilder fmtBin16 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>> 15 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>> 14 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>> 13 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>> 12 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>> 11 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>> 10 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>>  9 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x >>>  8 & 1 | 48);
    FMT_TEMP[ 8] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[ 9] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[10] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[11] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[12] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[13] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[14] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[15] = (char) (x        & 1 | 48);
    return sb.append (FMT_TEMP, 0, 16);
  }  //fmtBin16(StringBuilder,int)

  //fmtAin24 (a, o, x)
  //fmtBin24 (a, o, x)
  //s = fmtAin24 (x)
  //s = fmtBin24 (x)
  //sb = fmtAin24 (sb, x)
  //sb = fmtBin24 (sb, x)
  //  24桁2進数変換
  public static void fmtAin24 (char[] a, int o, int x) {
    a[o     ] = (char) (x >> 21 & 4 ^ 46);
    a[o +  1] = (char) (x >> 20 & 4 ^ 46);
    a[o +  2] = (char) (x >> 19 & 4 ^ 46);
    a[o +  3] = (char) (x >> 18 & 4 ^ 46);
    a[o +  4] = (char) (x >> 17 & 4 ^ 46);
    a[o +  5] = (char) (x >> 16 & 4 ^ 46);
    a[o +  6] = (char) (x >> 15 & 4 ^ 46);
    a[o +  7] = (char) (x >> 14 & 4 ^ 46);
    a[o +  8] = (char) (x >> 13 & 4 ^ 46);
    a[o +  9] = (char) (x >> 12 & 4 ^ 46);
    a[o + 10] = (char) (x >> 11 & 4 ^ 46);
    a[o + 11] = (char) (x >> 10 & 4 ^ 46);
    a[o + 12] = (char) (x >>  9 & 4 ^ 46);
    a[o + 13] = (char) (x >>  8 & 4 ^ 46);
    a[o + 14] = (char) (x >>  7 & 4 ^ 46);
    a[o + 15] = (char) (x >>  6 & 4 ^ 46);
    a[o + 16] = (char) (x >>  5 & 4 ^ 46);
    a[o + 17] = (char) (x >>  4 & 4 ^ 46);
    a[o + 18] = (char) (x >>  3 & 4 ^ 46);
    a[o + 19] = (char) (x >>  2 & 4 ^ 46);
    a[o + 20] = (char) (x >>  1 & 4 ^ 46);
    a[o + 21] = (char) (x       & 4 ^ 46);
    a[o + 22] = (char) (x <<  1 & 4 ^ 46);
    a[o + 23] = (char) (x <<  2 & 4 ^ 46);
  }  //fmtAin24(char[],int,int)
  public static void fmtBin24 (char[] a, int o, int x) {
    a[o     ] = (char) (x >>> 23 & 1 | 48);
    a[o +  1] = (char) (x >>> 22 & 1 | 48);
    a[o +  2] = (char) (x >>> 21 & 1 | 48);
    a[o +  3] = (char) (x >>> 20 & 1 | 48);
    a[o +  4] = (char) (x >>> 19 & 1 | 48);
    a[o +  5] = (char) (x >>> 18 & 1 | 48);
    a[o +  6] = (char) (x >>> 17 & 1 | 48);
    a[o +  7] = (char) (x >>> 16 & 1 | 48);
    a[o +  8] = (char) (x >>> 15 & 1 | 48);
    a[o +  9] = (char) (x >>> 14 & 1 | 48);
    a[o + 10] = (char) (x >>> 13 & 1 | 48);
    a[o + 11] = (char) (x >>> 12 & 1 | 48);
    a[o + 12] = (char) (x >>> 11 & 1 | 48);
    a[o + 13] = (char) (x >>> 10 & 1 | 48);
    a[o + 14] = (char) (x >>>  9 & 1 | 48);
    a[o + 15] = (char) (x >>>  8 & 1 | 48);
    a[o + 16] = (char) (x >>>  7 & 1 | 48);
    a[o + 17] = (char) (x >>>  6 & 1 | 48);
    a[o + 18] = (char) (x >>>  5 & 1 | 48);
    a[o + 19] = (char) (x >>>  4 & 1 | 48);
    a[o + 20] = (char) (x >>>  3 & 1 | 48);
    a[o + 21] = (char) (x >>>  2 & 1 | 48);
    a[o + 22] = (char) (x >>>  1 & 1 | 48);
    a[o + 23] = (char) (x        & 1 | 48);
  }  //fmtBin24(char[],int,int)
  public static String fmtAin24 (int x) {
    FMT_TEMP[ 0] = (char) (x >> 21 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >> 20 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >> 19 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >> 18 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >> 17 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x >> 16 & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x >> 15 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x >> 14 & 4 ^ 46);
    FMT_TEMP[ 8] = (char) (x >> 13 & 4 ^ 46);
    FMT_TEMP[ 9] = (char) (x >> 12 & 4 ^ 46);
    FMT_TEMP[10] = (char) (x >> 11 & 4 ^ 46);
    FMT_TEMP[11] = (char) (x >> 10 & 4 ^ 46);
    FMT_TEMP[12] = (char) (x >>  9 & 4 ^ 46);
    FMT_TEMP[13] = (char) (x >>  8 & 4 ^ 46);
    FMT_TEMP[14] = (char) (x >>  7 & 4 ^ 46);
    FMT_TEMP[15] = (char) (x >>  6 & 4 ^ 46);
    FMT_TEMP[16] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[17] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[18] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[19] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[20] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[21] = (char) (x       & 4 ^ 46);
    FMT_TEMP[22] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[23] = (char) (x <<  2 & 4 ^ 46);
    return String.valueOf (FMT_TEMP, 0, 24);
  }  //fmtAin24(int)
  public static String fmtBin24 (int x) {
    FMT_TEMP[ 0] = (char) (x >>> 23 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>> 22 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>> 21 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>> 20 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>> 19 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>> 18 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>> 17 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x >>> 16 & 1 | 48);
    FMT_TEMP[ 8] = (char) (x >>> 15 & 1 | 48);
    FMT_TEMP[ 9] = (char) (x >>> 14 & 1 | 48);
    FMT_TEMP[10] = (char) (x >>> 13 & 1 | 48);
    FMT_TEMP[11] = (char) (x >>> 12 & 1 | 48);
    FMT_TEMP[12] = (char) (x >>> 11 & 1 | 48);
    FMT_TEMP[13] = (char) (x >>> 10 & 1 | 48);
    FMT_TEMP[14] = (char) (x >>>  9 & 1 | 48);
    FMT_TEMP[15] = (char) (x >>>  8 & 1 | 48);
    FMT_TEMP[16] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[17] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[18] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[19] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[20] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[21] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[22] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[23] = (char) (x        & 1 | 48);
    return String.valueOf (FMT_TEMP, 0, 24);
  }  //fmtBin24(int)
  public static StringBuilder fmtAin24 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >> 21 & 4 ^ 46);
    FMT_TEMP[ 1] = (char) (x >> 20 & 4 ^ 46);
    FMT_TEMP[ 2] = (char) (x >> 19 & 4 ^ 46);
    FMT_TEMP[ 3] = (char) (x >> 18 & 4 ^ 46);
    FMT_TEMP[ 4] = (char) (x >> 17 & 4 ^ 46);
    FMT_TEMP[ 5] = (char) (x >> 16 & 4 ^ 46);
    FMT_TEMP[ 6] = (char) (x >> 15 & 4 ^ 46);
    FMT_TEMP[ 7] = (char) (x >> 14 & 4 ^ 46);
    FMT_TEMP[ 8] = (char) (x >> 13 & 4 ^ 46);
    FMT_TEMP[ 9] = (char) (x >> 12 & 4 ^ 46);
    FMT_TEMP[10] = (char) (x >> 11 & 4 ^ 46);
    FMT_TEMP[11] = (char) (x >> 10 & 4 ^ 46);
    FMT_TEMP[12] = (char) (x >>  9 & 4 ^ 46);
    FMT_TEMP[13] = (char) (x >>  8 & 4 ^ 46);
    FMT_TEMP[14] = (char) (x >>  7 & 4 ^ 46);
    FMT_TEMP[15] = (char) (x >>  6 & 4 ^ 46);
    FMT_TEMP[16] = (char) (x >>  5 & 4 ^ 46);
    FMT_TEMP[17] = (char) (x >>  4 & 4 ^ 46);
    FMT_TEMP[18] = (char) (x >>  3 & 4 ^ 46);
    FMT_TEMP[19] = (char) (x >>  2 & 4 ^ 46);
    FMT_TEMP[20] = (char) (x >>  1 & 4 ^ 46);
    FMT_TEMP[21] = (char) (x       & 4 ^ 46);
    FMT_TEMP[22] = (char) (x <<  1 & 4 ^ 46);
    FMT_TEMP[23] = (char) (x <<  2 & 4 ^ 46);
    return sb.append (FMT_TEMP, 0, 24);
  }  //fmtAin24(StringBuilder,int)
  public static StringBuilder fmtBin24 (StringBuilder sb, int x) {
    FMT_TEMP[ 0] = (char) (x >>> 23 & 1 | 48);
    FMT_TEMP[ 1] = (char) (x >>> 22 & 1 | 48);
    FMT_TEMP[ 2] = (char) (x >>> 21 & 1 | 48);
    FMT_TEMP[ 3] = (char) (x >>> 20 & 1 | 48);
    FMT_TEMP[ 4] = (char) (x >>> 19 & 1 | 48);
    FMT_TEMP[ 5] = (char) (x >>> 18 & 1 | 48);
    FMT_TEMP[ 6] = (char) (x >>> 17 & 1 | 48);
    FMT_TEMP[ 7] = (char) (x >>> 16 & 1 | 48);
    FMT_TEMP[ 8] = (char) (x >>> 15 & 1 | 48);
    FMT_TEMP[ 9] = (char) (x >>> 14 & 1 | 48);
    FMT_TEMP[10] = (char) (x >>> 13 & 1 | 48);
    FMT_TEMP[11] = (char) (x >>> 12 & 1 | 48);
    FMT_TEMP[12] = (char) (x >>> 11 & 1 | 48);
    FMT_TEMP[13] = (char) (x >>> 10 & 1 | 48);
    FMT_TEMP[14] = (char) (x >>>  9 & 1 | 48);
    FMT_TEMP[15] = (char) (x >>>  8 & 1 | 48);
    FMT_TEMP[16] = (char) (x >>>  7 & 1 | 48);
    FMT_TEMP[17] = (char) (x >>>  6 & 1 | 48);
    FMT_TEMP[18] = (char) (x >>>  5 & 1 | 48);
    FMT_TEMP[19] = (char) (x >>>  4 & 1 | 48);
    FMT_TEMP[20] = (char) (x >>>  3 & 1 | 48);
    FMT_TEMP[21] = (char) (x >>>  2 & 1 | 48);
    FMT_TEMP[22] = (char) (x >>>  1 & 1 | 48);
    FMT_TEMP[23] = (char) (x        & 1 | 48);
    return sb.append (FMT_TEMP, 0, 24);
  }  //fmtBin24(StringBuilder,int)

  //--------------------------------------------------------------------------------
  //16進数変換
  //
  //       x               00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
  //     9-x               09 08 07 06 05 04 03 02 01 00 ff fe fd fc fb fa
  //    (9-x)>>4           00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff
  //   ((9-x)>>4)&7        00 00 00 00 00 00 00 00 00 00 07 07 07 07 07 07
  //  (((9-x)>>4)&7)+48    30 30 30 30 30 30 30 30 30 30 37 37 37 37 37 37
  //  (((9-x)>>4)&7)+48+x  30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46
  //                        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
  //
  //       x                00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
  //     9-x                09 08 07 06 05 04 03 02 01 00 ff fe fd fc fb fa
  //    (9-x)>>4            00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff
  //   ((9-x)>>4)&39        00 00 00 00 00 00 00 00 00 00 27 27 27 27 27 27
  //  (((9-x)>>4)&39)+48    30 30 30 30 30 30 30 30 30 30 57 57 57 57 57 57
  //  (((9-x)>>4)&39)+48+x  30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66
  //                         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
  //
  //                c               30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 61 62 63 64 65 66
  //             64-c               10 0f 0e 0d 0c 0b 0a 09 08 07 ff fe fd fc fb fa df de dd dc db da
  //            (64-c)>>8           00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff
  //           ((64-c)>>8)&39       00 00 00 00 00 00 00 00 00 00 27 27 27 27 27 27 27 27 27 27 27 27
  //          (((64-c)>>8)&39)+48   30 30 30 30 30 30 30 30 30 30 57 57 57 57 57 57 57 57 57 57 57 57
  //   c|32                         30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 66 61 62 63 64 65 66
  //  (c|32)-((((64-c)>>8)&39)+48)  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0a 0b 0c 0d 0e 0f

  //c = fmtHexc (x)
  //a = fmtHex1 (a, o, x)
  //s = fmtHex1 (x)
  //sb = fmtHex1 (sb, x)
  //  1桁16進数変換
  public static char fmtHexc (int x) {
    x &= 15;
    return (char) ((((9 - x) >> 4) & 7) + 48 + x);
  }  //fmtHexc(int)
  public static void fmtHex1 (char[] a, int o, int x) {
    x &= 15;
    a[o] = (char) ((((9 - x) >> 4) & 7) + 48 + x);
  }  //fmtHex1(char[],int,int)
  public static String fmtHex1 (int x) {
    x &= 15;
    return Character.toString ((char) ((((9 - x) >> 4) & 7) + 48 + x));
  }  //fmtHex1(int)
  public static StringBuilder fmtHex1 (StringBuilder sb, int x) {
    x &= 15;
    return sb.append ((char) ((((9 - x) >> 4) & 7) + 48 + x));
  }  //fmtHex1(StringBuilder,int)

  //fmtHex2 (a, o, x)
  //s = fmtHex2 (x)
  //sb = fmtHex2 (sb, x)
  //  2桁16進数変換
  //  byte用
  public static void fmtHex2 (char[] a, int o, int x) {
    int x0 = x        & 15;
    int x1 = x >>>  4 & 15;
    a[o    ] = (char) ((((9 - x1) >> 4) & 7) + 48 + x1);
    a[o + 1] = (char) ((((9 - x0) >> 4) & 7) + 48 + x0);
  }  //fmtHex2(char[],int,int)
  public static String fmtHex2 (int x) {
    //fmtHex2 (FMT_TEMP, 0, x);
    int x0 = x        & 15;
    int x1 = x >>>  4 & 15;
    FMT_TEMP[0] = (char) ((((9 - x1) >> 4) & 7) + 48 + x1);
    FMT_TEMP[1] = (char) ((((9 - x0) >> 4) & 7) + 48 + x0);
    return String.valueOf (FMT_TEMP, 0, 2);
  }  //fmtHex2(int)
  public static StringBuilder fmtHex2 (StringBuilder sb, int x) {
    int x0 = x        & 15;
    int x1 = x >>>  4 & 15;
    return (sb.
            append ((char) ((((9 - x1) >> 4) & 7) + 48 + x1)).
            append ((char) ((((9 - x0) >> 4) & 7) + 48 + x0)));
  }  //fmtHex2(StringBuilder,int)

  //fmtHex4 (a, o, x)
  //s = fmtHex4 (x)
  //sb = fmtHex4 (sb, x)
  //  4桁16進数変換
  //  word用
  public static void fmtHex4 (char[] a, int o, int x) {
    int t;
    t = (char) x >>> 12;
    a[o    ] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    a[o + 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    a[o + 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    a[o + 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
  }  //fmtHex4(char[],int,int)
  public static String fmtHex4 (int x) {
    //fmtHex4 (FMT_TEMP, 0, x);
    int t;
    t = (char) x >>> 12;
    FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return String.valueOf (FMT_TEMP, 0, 4);
  }  //fmtHex4(int)
  public static StringBuilder fmtHex4 (StringBuilder sb, int x) {
    //fmtHex4 (FMT_TEMP, 0, x);
    int t;
    t = (char) x >>> 12;
    FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return sb.append (FMT_TEMP, 0, 4);
  }  //fmtHex4(StringBuilder,int)

  //fmtHex6 (a, o, x)
  //s = fmtHex6 (x)
  //sb = fmtHex6 (sb, x)
  //  6桁16進数変換
  //  rgb用
  public static void fmtHex6 (char[] a, int o, int x) {
    int t;
    t =        x >>> 20 & 15;
    a[o    ] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 16 & 15;
    a[o + 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) x >>> 12;
    a[o + 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    a[o + 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    a[o + 4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    a[o + 5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
  }  //fmtHex6(char[],int,int)
  public static String fmtHex6 (int x) {
    //fmtHex6 (FMT_TEMP, 0, x);
    int t;
    t =        x >>> 20 & 15;
    FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 16 & 15;
    FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) x >>> 12;
    FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return String.valueOf (FMT_TEMP, 0, 6);
  }  //fmtHex6(int)
  public static StringBuilder fmtHex6 (StringBuilder sb, int x) {
    //fmtHex6 (FMT_TEMP, 0, x);
    int t;
    t =        x >>> 20 & 15;
    FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 16 & 15;
    FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) x >>> 12;
    FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return sb.append (FMT_TEMP, 0, 6);
  }  //fmtHex6(StringBuilder,int)

  //fmtHex8 (a, o, x)
  //s = fmtHex8 (x)
  //sb = fmtHex8 (sb, x)
  //  8桁16進数変換
  //  argb,long用
  public static void fmtHex8 (char[] a, int o, int x) {
    int t;
    t =        x >>> 28;
    a[o    ] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 24 & 15;
    a[o + 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 20 & 15;
    a[o + 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 16 & 15;
    a[o + 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) x >>> 12;
    a[o + 4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    a[o + 5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    a[o + 6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    a[o + 7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
  }  //fmtHex8(char[],int,int)
  public static String fmtHex8 (int x) {
    //fmtHex8 (FMT_TEMP, 0, x);
    int t;
    t =        x >>> 28;
    FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 24 & 15;
    FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 20 & 15;
    FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 16 & 15;
    FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) x >>> 12;
    FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    FMT_TEMP[6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    FMT_TEMP[7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return String.valueOf (FMT_TEMP, 0, 8);
  }  //fmtHex8(int)
  public static StringBuilder fmtHex8 (StringBuilder sb, int x) {
    //fmtHex8 (FMT_TEMP, 0, x);
    int t;
    t =        x >>> 28;
    FMT_TEMP[0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 24 & 15;
    FMT_TEMP[1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 20 & 15;
    FMT_TEMP[2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>> 16 & 15;
    FMT_TEMP[3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) x >>> 12;
    FMT_TEMP[4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  8 & 15;
    FMT_TEMP[5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x >>>  4 & 15;
    FMT_TEMP[6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        x        & 15;
    FMT_TEMP[7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return sb.append (FMT_TEMP, 0, 8);
  }  //fmtHex8(StringBuilder,int)

  public static StringBuilder fmtHex16 (StringBuilder sb, long x) {
    //fmtHex16 (FMT_TEMP, 0, x);
    int s, t;
    s = (int) (x >>> 32);
    t =        s >>> 28;
    FMT_TEMP[ 0] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>> 24 & 15;
    FMT_TEMP[ 1] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>> 20 & 15;
    FMT_TEMP[ 2] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>> 16 & 15;
    FMT_TEMP[ 3] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) s >>> 12;
    FMT_TEMP[ 4] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>>  8 & 15;
    FMT_TEMP[ 5] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>>  4 & 15;
    FMT_TEMP[ 6] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s        & 15;
    FMT_TEMP[ 7] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    s = (int)  x;
    t =        s >>> 28;
    FMT_TEMP[ 8] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>> 24 & 15;
    FMT_TEMP[ 9] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>> 20 & 15;
    FMT_TEMP[10] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>> 16 & 15;
    FMT_TEMP[11] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t = (char) s >>> 12;
    FMT_TEMP[12] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>>  8 & 15;
    FMT_TEMP[13] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s >>>  4 & 15;
    FMT_TEMP[14] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    t =        s        & 15;
    FMT_TEMP[15] = (char) ((((9 - t) >> 4) & 7) + 48 + t);
    return sb.append (FMT_TEMP, 0, 16);
  }  //fmtHex16(StringBuilder,long)

  //--------------------------------------------------------------------------------
  //10進数変換
  //  除算は遅いので逆数乗算で商と余りを求めて下位から充填する
  //  x/yを計算する代わりにceil(pow(2,n)/y)を掛けてから右にnビットシフトする
  //  m=((1<<n)+y-1)/yとおくと0<=x<=((((m-1)/(m*y-(1<<n))+1)<<n)-1)/mの範囲でx/yはm*x>>nに置き換えられる
  //    >perl -e "use GMP::Mpz qw(:all);$y=mpz(10);for($n=mpz(0);$n<=31;$n++){$m=((1<<$n)+$y-1)/$y;$l=(((($m-1)/($m*$y-(1<<$n))+1)<<$n)-1)/$m;printf'x*%s>>%s (0<=x<=%s)%c',$m,$n,$l,10;}"
  //    x*1>>0 (0<=x<=0)
  //    x*1>>1 (0<=x<=1)
  //    x*1>>2 (0<=x<=3)
  //    x*1>>3 (0<=x<=7)
  //    x*2>>4 (0<=x<=7)
  //    x*4>>5 (0<=x<=7)
  //    x*7>>6 (0<=x<=18)
  //    x*13>>7 (0<=x<=68)
  //    x*26>>8 (0<=x<=68)
  //    x*52>>9 (0<=x<=68)
  //    x*103>>10 (0<=x<=178)  2桁
  //    x*205>>11 (0<=x<=1028)  3桁
  //    x*410>>12 (0<=x<=1028)
  //    x*820>>13 (0<=x<=1028)
  //    x*1639>>14 (0<=x<=2738)
  //    x*3277>>15 (0<=x<=16388)  4桁
  //    x*6554>>16 (0<=x<=16388)
  //    x*13108>>17 (0<=x<=16388)
  //    x*26215>>18 (0<=x<=43698)
  //    x*52429>>19 (0<=x<=262148)  5桁。ここからlong
  //    x*104858>>20 (0<=x<=262148)
  //    x*209716>>21 (0<=x<=262148)
  //    x*419431>>22 (0<=x<=699058)
  //    x*838861>>23 (0<=x<=4194308)  6桁
  //    x*1677722>>24 (0<=x<=4194308)
  //    x*3355444>>25 (0<=x<=4194308)
  //    x*6710887>>26 (0<=x<=11184818)  7桁
  //    x*13421773>>27 (0<=x<=67108868)
  //    x*26843546>>28 (0<=x<=67108868)
  //    x*53687092>>29 (0<=x<=67108868)
  //    x*107374183>>30 (0<=x<=178956978)  8桁
  //    x*214748365>>31 (0<=x<=1073741828)  9桁
  //
  //  検算
  //    >perl -e "use GMP::Mpz qw(:all);$y=mpz(10);for($n=mpz(0);$n<=23;$n++){$m=((1<<$n)+$y-1)/$y;$l=(((($m-1)/($m*$y-(1<<$n))+1)<<$n)-1)/$m;for($x=mpz(0);$x<=$l+1;$x++){$t=$m*$x>>$n;$z=$x/$y;if($z!=$t){printf'n=%d,m=%d,l=%d,x=%d,y=%d,z=%d,t=%d%c',$n,$m,$l,$x,$y,$z,$t,10;}}}"
  //    n=0,m=1,l=0,x=1,y=10,z=0,t=1
  //    n=1,m=1,l=1,x=2,y=10,z=0,t=1
  //    n=2,m=1,l=3,x=4,y=10,z=0,t=1
  //    n=3,m=1,l=7,x=8,y=10,z=0,t=1
  //    n=4,m=2,l=7,x=8,y=10,z=0,t=1
  //    n=5,m=4,l=7,x=8,y=10,z=0,t=1
  //    n=6,m=7,l=18,x=19,y=10,z=1,t=2
  //    n=7,m=13,l=68,x=69,y=10,z=6,t=7
  //    n=8,m=26,l=68,x=69,y=10,z=6,t=7
  //    n=9,m=52,l=68,x=69,y=10,z=6,t=7
  //    n=10,m=103,l=178,x=179,y=10,z=17,t=18
  //    n=11,m=205,l=1028,x=1029,y=10,z=102,t=103
  //    n=12,m=410,l=1028,x=1029,y=10,z=102,t=103
  //    n=13,m=820,l=1028,x=1029,y=10,z=102,t=103
  //    n=14,m=1639,l=2738,x=2739,y=10,z=273,t=274
  //    n=15,m=3277,l=16388,x=16389,y=10,z=1638,t=1639
  //    n=16,m=6554,l=16388,x=16389,y=10,z=1638,t=1639
  //    n=17,m=13108,l=16388,x=16389,y=10,z=1638,t=1639
  //    n=18,m=26215,l=43698,x=43699,y=10,z=4369,t=4370
  //    n=19,m=52429,l=262148,x=262149,y=10,z=26214,t=26215
  //    n=20,m=104858,l=262148,x=262149,y=10,z=26214,t=26215
  //    n=21,m=209716,l=262148,x=262149,y=10,z=26214,t=26215
  //    n=22,m=419431,l=699058,x=699059,y=10,z=69905,t=69906
  //    n=23,m=838861,l=4194308,x=4194309,y=10,z=419430,t=419431

  //  4桁まではあらかじめテーブルに展開しておく
  public static final int[] FMT_BCD4 = new int[10000];
  public static final int[] FMT_DCB4 = new int[65536];

  //--------------------------------------------------------------------------------
  //fmtInit ()
  //  初期化
  public static void fmtInit () {
    Arrays.fill (FMT_DCB4, -1);
    int i = 0;
    int x = 0;
    for (int a = 0; a < 10; a++) {
      for (int b = 0; b < 10; b++) {
        for (int c = 0; c < 10; c++) {
          FMT_DCB4[FMT_BCD4[i    ] = x    ] = i;
          FMT_DCB4[FMT_BCD4[i + 1] = x + 1] = i + 1;
          FMT_DCB4[FMT_BCD4[i + 2] = x + 2] = i + 2;
          FMT_DCB4[FMT_BCD4[i + 3] = x + 3] = i + 3;
          FMT_DCB4[FMT_BCD4[i + 4] = x + 4] = i + 4;
          FMT_DCB4[FMT_BCD4[i + 5] = x + 5] = i + 5;
          FMT_DCB4[FMT_BCD4[i + 6] = x + 6] = i + 6;
          FMT_DCB4[FMT_BCD4[i + 7] = x + 7] = i + 7;
          FMT_DCB4[FMT_BCD4[i + 8] = x + 8] = i + 8;
          FMT_DCB4[FMT_BCD4[i + 9] = x + 9] = i + 9;
          i += 10;
          x += 1 << 4;
        }
        x += 6 << 4;
      }
      x += 6 << 8;
    }
  }  //fmtInit()

  //y = fmtBcd4 (x)
  //  xを0~9999にクリッピングしてから4桁のBCDに変換する
  public static int fmtBcd4 (int x) {
    //x = Math.max (0, Math.min (9999, x));
    //perl optdiv.pl 9999 10
    //  x/10==x*3277>>>15 (0<=x<=16388) [9999*3277==32766723]
    //int t = x * 3277 >> 15;  //x/10
    //int y = x - t * 10;  //1の位
    //x = t * 3277 >> 15;  //x/100
    //y |= t - x * 10 << 4;  //10の位
    //t = x * 3277 >> 15;  //x/1000
    //return t << 12 | x - t * 10 << 8 | y;  //1000の位,100の位
    return FMT_BCD4[Math.max (0, Math.min (9999, x))];
  }  //fmtBcd4(int)

  //y = fmtBcd8 (x)
  //  xを0~99999999にクリッピングしてから8桁のBCDに変換する
  public static int fmtBcd8 (int x) {
    x = Math.max (0, Math.min (99999999, x));
    //perl optdiv.pl 99999999 10000
    //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
    int q = (int) ((long) x * 109951163L >>> 40);  //x/10000。1.6ns@2000000000
    //int q = x / 10000;  //2.0ns@2000000000
    return FMT_BCD4[q] << 16 | FMT_BCD4[x - 10000 * q];
  }  //fmtBcd8(int)

  //y = fmtBcd12 (x)
  //  xを0~999999999999Lにクリッピングしてから12桁のBCDに変換する
  public static long fmtBcd12 (long x) {
    x = Math.max (0L, Math.min (999999999999L, x));
    int q = (int) ((double) x / 100000000.0);  //(int) (x / 100000000L);
    int r = (int) (x - 100000000L * q);
    //perl optdiv.pl 99999999 10000
    //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
    int rq = (int) ((long) r * 109951163L >>> 40);  //r/10000
    //int rq = r / 10000;
    return (long) FMT_BCD4[q] << 32 | 0xffffffffL & (FMT_BCD4[rq] << 16 | FMT_BCD4[r - 10000 * rq]);
  }  //fmtBcd12(long)

  //y = fmtBcd16 (x)
  //  xを0~9999999999999999Lにクリッピングしてから16桁のBCDに変換する
  public static long fmtBcd16 (long x) {
    x = Math.max (0L, Math.min (9999999999999999L, x));
    int q = x <= (1L << 53) ? (int) ((double) x / 100000000.0) : (int) (x / 100000000L);
    int r = (int) (x - 100000000L * q);
    //perl optdiv.pl 99999999 10000
    //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
    int qq = (int) ((long) q * 109951163L >>> 40);  //q/10000
    //int qq = q / 10000;
    //perl optdiv.pl 99999999 10000
    //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
    int rq = (int) ((long) r * 109951163L >>> 40);  //r/10000
    //int rq = r / 10000;
    return (long) (FMT_BCD4[qq] << 16 | FMT_BCD4[q - 10000 * qq]) << 32 | 0xffffffffL & (FMT_BCD4[rq] << 16 | FMT_BCD4[r - 10000 * rq]);
  }  //fmtBcd16(long)

  //--------------------------------------------------------------------------------
  //o = fmtCA02u (a, o, x)
  //sb = fmtSB02u (sb, x)
  //  %02u
  //  2桁10進数変換(符号なし,ゼロサプレスなし)
  public static int fmtCA02u (char[] a, int o, int x) {
    if (x < 0 || 99 < x) {
      x = 99;
    }
    x = FMT_BCD4[x];
    a[o    ] = (char) ('0' | x >>> 4);
    a[o + 1] = (char) ('0' | x        & 15);
    return o + 2;
  }  //fmtCA02u(char[],int,int)
  public static StringBuilder fmtSB02u (StringBuilder sb, int x) {
    return sb.append (FMT_TEMP, 0, fmtCA02u (FMT_TEMP, 0, x));
  }  //fmtSB02u(StringBuilder,int)

  //o = fmtCA2u (a, o, x)
  //sb = fmtSB2u (sb, x)
  //  %2u
  //  2桁10進数変換(符号なし,ゼロサプレスあり)
  public static int fmtCA2u (char[] a, int o, int x) {
    if (x < 0 || 99 < x) {
      x = 99;
    }
    x = FMT_BCD4[x];
    if (x <= 0x000f) {  //1桁
      a[o++] = (char) ('0' | x);
    } else {  //2桁
      a[o++] = (char) ('0' | x >>>  4);
      a[o++] = (char) ('0' | x        & 15);
    }
    return o;
  }  //fmtCA2u(char[],int,int)
  public static StringBuilder fmtSB2u (StringBuilder sb, int x) {
    return sb.append (FMT_TEMP, 0, fmtCA2u (FMT_TEMP, 0, x));
  }  //fmtSB2u(StringBuilder,int)

  //o = fmtCA04u (a, o, x)
  //sb = fmtSB04u (sb, x)
  //  %04u
  //  4桁10進数変換(符号なし,ゼロサプレスなし)
  public static int fmtCA04u (char[] a, int o, int x) {
    if (x < 0 || 9999 < x) {
      x = 9999;
    }
    x = FMT_BCD4[x];
    a[o    ] = (char) ('0' | x >>> 12);
    a[o + 1] = (char) ('0' | x >>>  8 & 15);
    a[o + 2] = (char) ('0' | x >>>  4 & 15);
    a[o + 3] = (char) ('0' | x        & 15);
    return o + 4;
  }  //fmtCA04u(char[],int,int)
  public static StringBuilder fmtSB04u (StringBuilder sb, int x) {
    return sb.append (FMT_TEMP, 0, fmtCA04u (FMT_TEMP, 0, x));
  }  //fmtSB04u(StringBuilder,int)

  //o = fmtCA4u (a, o, x)
  //sb = fmtSB4u (sb, x)
  //  %4u
  //  4桁10進数変換(符号なし,ゼロサプレスあり)
  public static int fmtCA4u (char[] a, int o, int x) {
    if (x < 0 || 9999 < x) {
      x = 9999;
    }
    x = FMT_BCD4[x];
    if (x <= 0x000f) {  //1桁
      a[o++] = (char) ('0' | x);
    } else if (x <= 0x00ff) {  //2桁
      a[o++] = (char) ('0' | x >>>  4);
      a[o++] = (char) ('0' | x        & 15);
    } else if (x <= 0x0fff) {  //3桁
      a[o++] = (char) ('0' | x >>>  8);
      a[o++] = (char) ('0' | x >>>  4 & 15);
      a[o++] = (char) ('0' | x        & 15);
    } else {  //4桁
      a[o++] = (char) ('0' | x >>> 12);
      a[o++] = (char) ('0' | x >>>  8 & 15);
      a[o++] = (char) ('0' | x >>>  4 & 15);
      a[o++] = (char) ('0' | x        & 15);
    }
    return o;
  }  //fmtCA4u(char[],int,int)
  public static StringBuilder fmtSB4u (StringBuilder sb, int x) {
    return sb.append (FMT_TEMP, 0, fmtCA4u (FMT_TEMP, 0, x));
  }  //fmtSB4u(StringBuilder,int)

  //o = fmtCA08u (a, o, x)
  //sb = fmtSB08u (sb, x)
  //  %08u
  //  8桁10進数変換(符号なし,ゼロサプレスなし)
  public static int fmtCA08u (char[] a, int o, int x) {
    if (x < 0 || 99999999 < x) {
      x = 99999999;
    }
    //perl optdiv.pl 99999999 10000
    //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
    int h = (int) ((long) x * 109951163L >>> 40);  //x/10000
    return fmtCA04u (a, fmtCA04u (a, o, h), x - h * 10000);
  }  //fmtCA08u(char[],int,int)
  public static StringBuilder fmtSB08u (StringBuilder sb, int x) {
    return sb.append (FMT_TEMP, 0, fmtCA08u (FMT_TEMP, 0, x));
  }  //fmtSB08u(StringBuilder,int)

  //o = fmtCA8u (a, o, x)
  //sb = fmtSB8u (sb, x)
  //  %8u
  //  8桁10進数変換(符号なし,ゼロサプレスあり)
  public static int fmtCA8u (char[] a, int o, int x) {
    if (x < 0 || 99999999 < x) {
      x = 99999999;
    }
    if (x <= 9999) {  //1~4桁
      return fmtCA4u (a, o, x);
    } else {  //5~8桁
      //perl optdiv.pl 99999999 10000
      //  x/10000==x*109951163>>>40 (0<=x<=494389998) [99999999*109951163==10995116190048837]
      int h = (int) ((long) x * 109951163L >>> 40);  //x/10000
      return fmtCA04u (a, fmtCA4u (a, o, h), x - h * 10000);
    }
  }  //fmtCA8u(char[],int,int)
  public static StringBuilder fmtSB8u (StringBuilder sb, int x) {
    return sb.append (FMT_TEMP, 0, fmtCA8u (FMT_TEMP, 0, x));
  }  //fmtSB8u(StringBuilder,int)

  //o = fmtCAd (a, o, x)
  //sb = fmtSBd (sb, x)
  //  %d
  //  10進数変換(符号あり,ゼロサプレスあり)
  public static int fmtCAd (char[] a, int o, long x) {
    if (x < 0L) {
      x = -x;
      a[o++] = '-';
    }
    if (x <= 99999999L) {  //1~8桁
      return fmtCA8u (a, o, (int) x);
    } else if (x <= 9999999999999999L) {  //9~16桁
      long h = x / 100000000L;
      return fmtCA08u (a, fmtCA8u (a, o, (int) h), (int) (x - h * 100000000L));
    } else {  //17~19桁
      long hh = x / 10000000000000000L;
      x -= hh * 10000000000000000L;
      long h = x / 100000000L;
      return fmtCA08u (a, fmtCA08u (a, fmtCA4u (a, o, (int) hh), (int) h), (int) (x - h * 100000000L));
    }
  }  //fmtCAd(char[],int,long)
  public static StringBuilder fmtSBd (StringBuilder sb, long x) {
    return sb.append (FMT_TEMP, 0, fmtCAd (FMT_TEMP, 0, x));
  }  //fmtSBd(StringBuilder,long)

  //o = fmtCAnd (a, o, n, x)
  //sb = fmtSBnd (sb, n, x)
  //  %*d
  //  n桁10進数変換(符号あり,ゼロサプレスあり)
  //  n桁に収まらないとき右側にはみ出すのでバッファのサイズに注意
  public static int fmtCAnd (char[] a, int o, int n, long x) {
    int t = fmtCAd (a, o, x);  //現在の末尾
    n += o;  //必要な末尾
    if (t < n) {  //余っている
      int i = n;
      while (o < t) {  //右から順に右にずらす
        a[--i] = a[--t];
      }
      while (o < i) {  //左にできた隙間を' 'で埋める
        a[--i] = ' ';
      }
      t = n;
    }
    return t;
  }  //fmtnu(char[],int,int,long)
  public static StringBuilder fmtSBnd (StringBuilder sb, int n, int x) {
    return sb.append (FMT_TEMP, 0, fmtCAnd (FMT_TEMP, 0, n, x));
  }  //fmtSBnu(StringBuilder,int,long)

  //--------------------------------------------------------------------------------
  //10進数文字列解析

  //x = fmtParseInt (s, i, min, max, err)
  //  文字列sのインデックスiから基数10で整数xを読み取る
  //x = fmtParseIntRadix (s, i, min, max, err, radix)
  //  文字列sのインデックスiから基数radixで整数xを読み取る
  //  基数radixは2,8,10,16のいずれかに限る
  //  1文字も読み取れないかmin<=x&&x<=maxでないときはerrを返す
  //  先頭の空白を読み飛ばす
  //  数値の先頭の'$'は16進数の強制指定とみなす
  //  数値の後のゴミは無視する
  public static int fmtParseInt (String s, int i, int min, int max, int err) {
    return fmtParseIntRadix (s, i, min, max, err, 10);
  }  //fmtParseInt(String,int,int,int,int)
  public static int fmtParseIntRadix (String s, int i, int min, int max, int err, int radix) {
    if (s == null) {
      return err;
    }
    int l = s.length ();
    int c = i < l ? s.charAt (i++) : -1;
    //空白を読み飛ばす
    while (c == ' ' || c == '\t') {
      c = i < l ? s.charAt (i++) : -1;
    }
    //符号を読み取る
    int n = 0;
    if (c == '+') {
      c = i < l ? s.charAt (i++) : -1;
    } else if (c == '-') {
      n = 1;
      c = i < l ? s.charAt (i++) : -1;
    }
    //基数を読み取る
    //        2進数の範囲        8進数の範囲       10進数の範囲        16進数の範囲
    //  +    0x3fffffff*2+1     0x0fffffff*8+7     214748364*10+7     0x07ffffff*16+15
    //  -  -(0x40000000*2+0)  -(0x10000000*8+0)  -(214748364*10+8)  -(0x08000000*16+ 0)
    int o;
    int p;
    if (c == '$') {  //16進数
      o = 0x07ffffff + n;
      p = 15 + n & 15;
      radix = 16;
      c = i < l ? s.charAt (i++) : -1;
    } else if (radix == 16) {  //16進数
      o = 0x07ffffff + n;
      p = 15 + n & 15;
    } else if (radix == 8) {  //8進数
      o = 0x0fffffff + n;
      p = 7 + n & 7;
    } else if (radix == 2) {  //2進数
      o = 0x3fffffff + n;
      p = 1 + n & 1;
    } else {  //10進数
      o = 214748364;
      p = 7 + n;
      radix = 10;
    }
    //数値を読み取る
    int x = Character.digit (c, radix);
    if (x < 0) {
      return err;
    }
    c = i < l ? Character.digit (s.charAt (i++), radix) : -1;
    while (c >= 0) {
      int t = x - o;
      if (t > 0 || t == 0 && c > p) {
        return err;
      }
      x = x * radix + c;
      c = i < l ? Character.digit (s.charAt (i++), radix) : -1;
    }
    if (n != 0) {
      x = -x;
    }
    return min <= x && x <= max ? x : err;
  }  //fmtParseIntRadix(String,int,int,int,int,int)



  //========================================================================================
  //$$MAT 数学関数

  //x = matMax3 (x1, x2, x3)
  //x = matMax4 (x1, x2, x3, x4)
  //x = matMax5 (x1, x2, x3, x4, x5)
  //  最大値
  public static long matMax3 (long x1, long x2, long x3) {
    return Math.max (Math.max (x1, x2), x3);
  }  //matMax3(long,long,long)
  public static long matMax4 (long x1, long x2, long x3, long x4) {
    return Math.max (Math.max (x1, x2), Math.max (x3, x4));
  }  //matMax4(long,long,long,long)
  public static long matMax5 (long x1, long x2, long x3, long x4, long x5) {
    return Math.max (Math.max (Math.max (x1, x2), Math.max (x3, x4)), x5);
  }  //matMax5(long,long,long,long,long)

  //x = matMin3 (x1, x2, x3)
  //x = matMin4 (x1, x2, x3, x4)
  //x = matMin5 (x1, x2, x3, x4, x5)
  //  最小値
  public static long matMin3 (long x1, long x2, long x3) {
    return Math.min (Math.min (x1, x2), x3);
  }  //matMin3(long,long,long)
  public static long matMin4 (long x1, long x2, long x3, long x4) {
    return Math.min (Math.min (x1, x2), Math.min (x3, x4));
  }  //matMin4(long,long,long,long)
  public static long matMin5 (long x1, long x2, long x3, long x4, long x5) {
    return Math.min (Math.min (Math.min (x1, x2), Math.min (x3, x4)), x5);
  }  //matMin5(long,long,long,long,long)



  //========================================================================================
  //$$STR 文字列

  //s = encodeUTF8 (s)
  //  UTF-8変換
  //  00000000 00000000 00000000 0xxxxxxx => 00000000 00000000 00000000 0xxxxxxx
  //  00000000 00000000 00000xxx xxyyyyyy => 00000000 00000000 110xxxxx 10yyyyyy
  //  00000000 00000000 xxxxyyyy yyzzzzzz => 00000000 1110xxxx 10yyyyyy 10zzzzzz
  //  00000000 000xxxyy yyyyzzzz zzxxxxxx => 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx
  public static String strEncodeUTF8 (String s) {
    StringBuilder sb = new StringBuilder ();
    int l = s.length ();
    for (int i = 0; i < l; i++) {
      int u = s.charAt (i);
      if (0xd800 <= u && u <= 0xdbff && i + 1 < l) {
        int v = s.charAt (i + 1);
        if (0xdc00 <= v && v <= 0xdfff) {  //surrogate pair
          u = 0x10000 + ((u & 0x3ff) << 10) + (v & 0x3ff);
          i++;
        }
      }
      if ((u & 0xffffff80) == 0) {  //7bit
        sb.append ((char) u);
      } else if ((u & 0xfffff800) == 0) {  //11bit
        u = (0x0000c080 |
             (u & 0x000007c0) << 2 |
             (u & 0x0000003f));
        sb.append ((char) (u >> 8)).append ((char) (u & 0xff));
      } else if ((u & 0xffff0000) == 0 && !(0xd800 <= u && u <= 0xdfff)) {  //16bit except broken surrogate pair
        u = (0x00e08080 |
             (u & 0x0000f000) << 4 |
             (u & 0x00000fc0) << 2 |
             (u & 0x0000003f));
        sb.append ((char) (u >> 16)).append ((char) ((u >> 8) & 0xff)).append ((char) (u & 0xff));
      } else if ((u & 0xffe00000) == 0) {  //21bit
        u = (0xf0808080 |
             (u & 0x001c0000) << 6 |
             (u & 0x0003f000) << 4 |
             (u & 0x00000fc0) << 2 |
             (u & 0x0000003f));
        sb.append ((char) ((u >> 24) & 0xff)).append ((char) ((u >> 16) & 0xff)).append ((char) ((u >> 8) & 0xff)).append ((char) (u & 0xff));
      } else {  //out of range or broken surrogate pair
        sb.append ((char) 0xef).append ((char) 0xbf).append ((char) 0xbd);  //U+FFFD REPLACEMENT CHARACTER
      }
    }
    return sb.toString ();
  }  //encodeUTF8(String)

  //s = decodeUTF8 (s)
  //  UTF-8逆変換
  //  00000000 00000000 00000000 0xxxxxxx => 00000000 00000000 00000000 0xxxxxxx
  //  00000000 00000000 110xxxxx 10yyyyyy => 00000000 00000000 00000xxx xxyyyyyy
  //  00000000 1110xxxx 10yyyyyy 10zzzzzz => 00000000 00000000 xxxxyyyy yyzzzzzz
  //  11110xxx 10yyyyyy 10zzzzzz 10xxxxxx => 00000000 000xxxyy yyyyzzzz zzxxxxxx
  public static String strDecodeUTF8 (String s) {
    StringBuilder sb = new StringBuilder ();
    int l = s.length ();
    for (int i = 0; i < l; i++) {
      int c = s.charAt (i) & 0xff;
      for (int k = ((c & 0x80) == 0x00 ? 0 :  //0xxxxxxx 7bit
                    (c & 0xe0) == 0xc0 ? 1 :  //110xxxxx 11bit
                    (c & 0xf0) == 0xe0 ? 2 :  //1110xxxx 16bit
                    (c & 0xf8) == 0xf0 ? 3 :  //11110xxx 21bit
                    -1);  //not supported
           --k >= 0; ) {
        c = c << 8 | (i + 1 < l ? s.charAt (++i) & 0xff : 0);
      }
      int u = ((c & 0xffffff80) == 0x00000000 ? c :
               (c & 0xffffe0c0) == 0x0000c080 ? ((c & 0x00001f00) >> 2 |
                                                 (c & 0x0000003f)) :
               (c & 0xfff0c0c0) == 0x00e08080 ? ((c & 0x000f0000) >> 4 |
                                                 (c & 0x00003f00) >> 2 |
                                                 (c & 0x0000003f)) :
               (c & 0xf8c0c0c0) == 0xf0808080 ? ((c & 0x07000000) >> 6 |
                                                 (c & 0x003f0000) >> 4 |
                                                 (c & 0x00003f00) >> 2 |
                                                 (c & 0x0000003f)) :
               0xfffd);  //U+FFFD REPLACEMENT CHARACTER
      if (u <= 0x0000ffff) {
        sb.append (0xd800 <= u && u <= 0xdfff ? '\ufffd' :  //U+FFFD REPLACEMENT CHARACTER
                   (char) u);
      } else if (u <= 0x0010ffff) {
        u -= 0x000010000;
        sb.append ((char) (0xd800 + ((u >> 10) & 0x3ff))).append ((char) (0xdc00 + (u & 0x3ff)));
      }
    }
    return sb.toString ();
  }  //decodeUTF8(String)

  //uri = strEncodeURI (s)
  //  URI変換
  //  UTF-8変換を行ってからRFC3986のPercent-Encodingを行う
  //  フォームの送信に使用されるapplication/x-www-form-urlencodedではない。" "は"+"ではなく"%20"に変換される
  public static final int[] IsURIChar = {  //URIに使える文字。RFC3986のUnreserved Characters。[-.0-9A-Z_a-z~]
    //00000000 00000000 11111111 11111111
    //01234567 89abcdef 01234567 89abcdef
    0b00000000_00000000_00000000_00000000,  //0x00..0x1f
    0b00000000_00000110_11111111_11000000,  //0x20..0x3f [-.0-9]
    0b01111111_11111111_11111111_11100001,  //0x40..0x5f [A-Z_]
    0b01111111_11111111_11111111_11100010,  //0x60..0x7f [a-z~]
  };
  public static String strEncodeURI (String s) {
    s = strEncodeUTF8 (s);  //UTF-8変換
    StringBuilder sb = new StringBuilder ();
    int l = s.length ();
    for (int i = 0; i < l; i++) {
      int c = s.charAt (i);
      if (c < 0x80 && IsURIChar[c >> 5] << c < 0) {  //URIに使える文字
        sb.append ((char) c);
      } else {
        fmtHex2 (sb.append ('%'), c);
      }
    }
    return sb.toString ();
  }  //encodeURI(String)

  //s = strDecodeURI (s)
  //  URI逆変換
  //  RFC3986のPercent-Encodingの逆変換を行ってからUTF-8逆変換を行う
  //  フォームの送信に使用されるapplication/x-www-form-urlencodedではない。"+"は" "に変換されない
  public static final byte[] strIsHexChar = {  //16進数に使えるASCII文字。[0-9A-Fa-f]
    // 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //0x00..0x1f
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,  //0x20..0x3f [0-9]
    -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //0x40..0x5f [A-F]
    -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  //0x60..0x7f [a-f]
  };
  public static String strDecodeURI (String s) {
    StringBuilder sb = new StringBuilder ();
    int l = s.length ();
    for (int i = 0; i < l; i++) {
      int c = s.charAt (i);
      if (c == '%' && i + 2 < l) {
        int d = s.charAt (i + 1);
        int e = s.charAt (i + 2);
        if (d < 0x80 && (d = strIsHexChar[d]) >= 0 &&
            e < 0x80 && (e = strIsHexChar[e]) >= 0) {
          sb.append ((char) (d << 4 | e));
        } else {
          sb.append ((char) c);
        }
      } else {
        sb.append ((char) c);
      }
    }
    return sb.toString ();
  }  //decodeURI(String)



  //========================================================================================
  //$$IMG イメージ

  //image = createImage (width, height, pattern, rgb, ...)
  //  イメージを作る
  public static BufferedImage createImage (int width, int height, String pattern, int... rgbs) {
    BufferedImage image = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB);
    int[] bitmap = ((DataBufferInt) image.getRaster ().getDataBuffer ()).getData ();
    int length = width * height;
    for (int i = 0; i < length; i++) {
      char c = pattern.charAt (i);
      bitmap[i] = rgbs[c < '0' ? 0 : Character.digit (c, 16)];
    }
    return image;
  }  //createImage(int,int,String,int...)

  //icon = createImageIcon (width, height, pattern, rgb, ...)
  //  イメージアイコンを作る
  public static ImageIcon createImageIcon (int width, int height, String pattern, int... rgbs) {
    return new ImageIcon (createImage (width, height, pattern, rgbs));
  }  //createImageIcon(int,int,String,int...)

  //paint = createTexturePaint (width, height, pattern, rgb, ...)
  //  テクスチャペイントを作る
  public static TexturePaint createTexturePaint (int width, int height, String pattern, int... rgbs) {
    return new TexturePaint (createImage (width, height, pattern, rgbs), new Rectangle (0, 0, width, height));
  }  //createTexturePaint(int,int,String,int...)

  //image = loadImage (name)
  //  イメージを読み込む
  public static BufferedImage loadImage (String name) {
    BufferedImage image = null;
    try {
      image = ImageIO.read (new File (name));
    } catch (Exception e) {
    }
    return image;
  }  //loadImage(String)

  //sucess = saveImage (image, name)
  //sucess = saveImage (image, name, quality)
  //  イメージを書き出す
  public static boolean saveImage (BufferedImage image, String name) {
    return saveImage (image, name, 0.75F);
  }  //saveImage(BufferedImage,String)
  public static boolean saveImage (BufferedImage image, String name, float quality) {
    int index = name.lastIndexOf (".");
    if (index < 0) {  //拡張子がない
      return false;
    }
    if (name.substring (index).equalsIgnoreCase (".ico")) {  //アイコンファイルの作成
      return saveIcon (name, image);
    }
    Iterator<ImageWriter> iterator = ImageIO.getImageWritersBySuffix (name.substring (index + 1));  //拡張子に対応するImageWriterがないときは空のIteratorを返す
    if (!iterator.hasNext ()) {  //拡張子に対応するImageWriterがない
      return false;
    }
    ImageWriter imageWriter = iterator.next ();
    ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam ();
    if (imageWriteParam.canWriteCompressed ()) {
      imageWriteParam.setCompressionMode (ImageWriteParam.MODE_EXPLICIT);
      imageWriteParam.setCompressionQuality (quality);
    }
    try {
      File file = new File (name);
      ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream (file);
      imageWriter.setOutput (imageOutputStream);
      imageWriter.write (null, new IIOImage (image, null, null), imageWriteParam);
      imageOutputStream.close ();
    } catch (Exception e) {
      //e.printStackTrace ();
      return false;
    }
    return true;
  }  //saveImage(BufferedImage,String,float)



  //========================================================================================
  //$$ICO アイコンファイル
  //  サイズの異なる複数のアイコンを格納することができる
  //  ワードサイズとロングサイズのデータはすべてリトルエンディアン
  //
  //  アイコンファイル(.ico)
  //    ファイルヘッダ
  //    エントリデータ0
  //           :
  //    エントリデータn-1
  //    イメージデータ0
  //           :
  //    イメージデータn-1
  //
  //  ファイルヘッダ
  //    0000  .iw  0=予約
  //    0002  .iw  1=アイコン
  //    0004  .iw  n=アイコン数
  //    0006
  //
  //  エントリデータ
  //    0000  .b   幅
  //    0001  .b   高さ
  //    0002  .b   色数(0=256以上)
  //    0003  .b   0=予約
  //    0004  .iw  1=プレーン数
  //    0006  .iw  ピクセル毎のビット数
  //    0008  .il  イメージデータの長さ
  //    000c  .il  ファイルヘッダからイメージデータまでのオフセット
  //    0010
  //
  //  イメージデータ
  //    イメージヘッダ
  //    パレットテーブル
  //    パターンデータ
  //    マスクデータ
  //
  //  イメージヘッダ
  //    0000  .il  40=イメージヘッダの長さ
  //    0004  .il  幅
  //    0008  .il  高さ*2
  //    000c  .iw  1=プレーン数
  //    000e  .iw  ピクセル毎のビット数
  //    0010  .il  0=無圧縮
  //    0014  .il  0=画像データサイズ(省略)
  //    0018  .il  0=横解像度(省略)
  //    001c  .il  0=縦解像度(省略)
  //    0020  .il  p=パレット数
  //    0024  .il  0=重要なパレットのインデックス(省略)
  //    0028
  //
  //  パレットテーブル
  //    0000  .il  パレット0(BGR0)
  //                   :
  //          .il  パレットp-1(BGR0)
  //    4*p
  //
  //  パターンデータ
  //    ピクセルの順序は左下から右上
  //    バイト内のビットの順序は上位から下位
  //    1ラインのデータ長は4の倍数
  //
  //  マスクデータ
  //    0=描画,1=透過
  //    ピクセルの順序は左下から右上
  //    バイト内のビットの順序は上位から下位
  //    1ラインのデータ長は4の倍数

  //success = saveIcon (name, image, ...);
  //  アイコンファイルを出力する
  public static boolean saveIcon (String fileName, BufferedImage... arrayImage) {
    int iconCount = arrayImage.length;
    int[][] arrayPaletTable = new int[iconCount][];  //パレットテーブル
    int[] arrayPaletCount = new int[iconCount];  //パレット数。0=パレットを使わない
    int[] arrayPixelBits = new int[iconCount];  //ピクセル毎のビット数。24,8,4,2,1のいずれか
    int[] arrayPatternLineSize = new int[iconCount];  //パターンデータの1ラインのバイト数
    int[] arrayMaskLineSize = new int[iconCount];  //マスクデータの1ラインのバイト数
    int[] arrayImageSize = new int[iconCount];  //イメージデータの長さ
    int[] arrayImageOffset = new int[iconCount];  //ファイルヘッダからイメージデータまでのオフセット
    int fileSize = 6 + 16 * iconCount;
    for (int iconNumber = 0; iconNumber < iconCount; iconNumber++) {
      BufferedImage image = arrayImage[iconNumber];
      int width = image.getWidth ();
      int height = image.getHeight ();
      //パレットテーブルを作る
      int[] paletTable = new int[256];
      int paletCount = 0;
    countPalet:
      for (int y = height - 1; y >= 0; y--) {
        for (int x = 0; x < width; x++) {
          int rgb = image.getRGB (x, y);
          if (rgb >>> 24 != 0xff) {  //alphaが0xffでなければred,green,blueを無視して透過色とみなす
            continue;
          }
          int l = 0;
          int r = paletCount;
          while (l < r) {
            int m = l + r >> 1;
            if (paletTable[m] < rgb) {
              l = m + 1;
            } else {
              r = m;
            }
          }
          if (l == paletCount || paletTable[l] != rgb) {  //新しい色
            if (paletCount == 256) {  //色数が多すぎる
              paletCount = 0;
              break countPalet;
            }
            for (int i = paletCount; i > l; i--) {
              paletTable[i] = paletTable[i - 1];
            }
            paletTable[l] = rgb;
            paletCount++;
          }
        }  //for x
      }  //for y
      int pixelBits = (paletCount == 0 ? 24 :
                       paletCount > 16 ? 8 :
                       paletCount > 4 ? 4 :
                       paletCount > 2 ? 2 :
                       1);
      int patternLineSize = pixelBits * width + 31 >> 5 << 2;
      int maskLineSize = width + 31 >> 5 << 2;
      int imageSize = 40 + 4 * paletCount + patternLineSize * height + maskLineSize * height;
      arrayPaletTable[iconNumber] = paletTable;
      arrayPaletCount[iconNumber] = paletCount;
      arrayPixelBits[iconNumber] = pixelBits;
      arrayPatternLineSize[iconNumber] = patternLineSize;
      arrayMaskLineSize[iconNumber] = maskLineSize;
      arrayImageSize[iconNumber] = imageSize;
      arrayImageOffset[iconNumber] = fileSize;
      fileSize += imageSize;
    }  //for iconNumber
    byte[] bb = new byte[fileSize];
    //ファイルヘッダ
    ByteArray.byaWiw (bb, 0, 0);
    ByteArray.byaWiw (bb, 2, 1);
    ByteArray.byaWiw (bb, 4, iconCount);
    for (int iconNumber = 0; iconNumber < iconCount; iconNumber++) {
      BufferedImage image = arrayImage[iconNumber];
      int width = image.getWidth ();
      int height = image.getHeight ();
      int[] paletTable = arrayPaletTable[iconNumber];
      int paletCount = arrayPaletCount[iconNumber];
      int pixelBits = arrayPixelBits[iconNumber];
      int patternLineSize = arrayPatternLineSize[iconNumber];
      int maskLineSize = arrayMaskLineSize[iconNumber];
      int imageSize = arrayImageSize[iconNumber];
      int imageOffset = arrayImageOffset[iconNumber];
      //エントリデータ
      int o = 6 + 16 * iconNumber;
      ByteArray.byaWb (bb, o, width);
      ByteArray.byaWb (bb, o + 1, height);
      ByteArray.byaWb (bb, o + 2, paletCount);
      ByteArray.byaWb (bb, o + 3, 0);
      ByteArray.byaWiw (bb, o + 4, 1);
      ByteArray.byaWiw (bb, o + 6, pixelBits);
      ByteArray.byaWil (bb, o + 8, imageSize);
      ByteArray.byaWil (bb, o + 12, imageOffset);
      //イメージヘッダ
      o = imageOffset;
      ByteArray.byaWil (bb, o, 40);
      ByteArray.byaWil (bb, o + 4, width);
      ByteArray.byaWil (bb, o + 8, height * 2);
      ByteArray.byaWiw (bb, o + 12, 1);
      ByteArray.byaWiw (bb, o + 14, pixelBits);
      ByteArray.byaWil (bb, o + 16, 0);
      ByteArray.byaWil (bb, o + 20, 0);
      ByteArray.byaWil (bb, o + 24, 0);
      ByteArray.byaWil (bb, o + 28, 0);
      ByteArray.byaWil (bb, o + 32, paletCount);
      ByteArray.byaWil (bb, o + 36, 0);
      //パレットテーブル
      o += 40;
      for (int i = 0; i < paletCount; i++) {
        ByteArray.byaWil (bb, o, paletTable[i] & 0x00ffffff);
        o += 4;
      }
      //パターンデータ
      for (int y = height - 1; y >= 0; y--) {
        for (int x = 0; x < width; x++) {
          int rgb = image.getRGB (x, y);
          if (rgb >>> 24 != 0xff) {  //alphaが0xffでなければred,green,blueを無視して透過色とみなす
            continue;
          }
          if (pixelBits == 24) {  //パレットなし
            bb[o + 3 * x] = (byte) rgb;  //blue
            bb[o + 3 * x + 1] = (byte) (rgb >> 8);  //green
            bb[o + 3 * x + 2] = (byte) (rgb >> 16);  //red
            continue;
          }
          int l = 0;
          int r = paletCount;
          while (l < r) {
            int m = l + r >> 1;
            if (paletTable[m] < rgb) {
              l = m + 1;
            } else {
              r = m;
            }
          }
          if (l != 0) {
            if (pixelBits == 8) {
              bb[o + x] = (byte) l;
            } else if (pixelBits == 4) {
              bb[o + (x >> 1)] |= (byte) (l << ((~x & 1) << 2));
            } else if (pixelBits == 2) {
              bb[o + (x >> 2)] |= (byte) (l << ((~x & 3) << 1));
            } else {
              bb[o + (x >> 3)] |= (byte) (l << (~x & 7));
            }
          }
        }  //for x
        o += patternLineSize;
      }  //for y
      //マスクデータ
      for (int y = height - 1; y >= 0; y--) {
        for (int x = 0; x < width; x++) {
          int rgb = image.getRGB (x, y);
          if (rgb >>> 24 != 0xff) {  //alphaが0xffでなければred,green,blueを無視して透過色とみなす
            bb[o + (x >> 3)] |= (byte) (1 << (~x & 7));
          }
        }
        o += maskLineSize;
      }
    }  //for iconNumber
    return rscPutFile (fileName, bb, 0, fileSize);
  }  //saveIcon(String,BufferedImage...)



}  //class XEiJ


1 2