
#include <stdio.h>
#include <stdlib.h>

typedef unsigned short word;
typedef unsigned int   uint;
typedef unsigned char  byte;

enum {
  SCALElog = 15,
  SCALE    = 1<<SCALElog,
  eSCALE = 16*SCALE,
  hSCALE = SCALE/2,
  mSCALE = SCALE-1
};

struct Rangecoder_SH1m {

  enum {
    NUM   = 4,
    sTOP  = 0x01000000U,
    gTOP  = 0x00010000U,
    Thres = 0xFF000000U,
    Threg = 0x00FF0000U
  };

  int   ProcMode; 
  uint  low;  
  uint  Carry;
  uint  code; 
  uint  FFNum;
  uint  Cache;
  uint  range;
  int   cflag;

  struct DefaultIO {
    FILE* CodeFile;
    unsigned char get(void) { return getc(CodeFile); }
    void put( int c ) { putc( c, CodeFile ); }
  };
  DefaultIO io;
  unsigned char get(void) { return io.get(); }
  void put( int c ) { if( cflag ) io.put(c); cflag=1; }

  void Renorm( int DECODE ) {
    if( DECODE ) {

      if( range<gTOP ) range<<=16, (code<<=16)+=(get()<<8)+get(); 
      else if( range<sTOP ) range<<=8, (code<<=8)+=get();
    } else {

      if( range<gTOP ) range<<=16, ShiftLow2(); 
      else if( range<sTOP ) range<<=8, ShiftLow();
    }
  }

  int BProcess( int DECODE, int bit, uint freq ) { 
     uint rnew = freq*(range>>SCALElog);
    if( DECODE ) {
      if( code<rnew ) { 
        range = rnew;
        Renorm(DECODE);
        return 0;
      } else {
        range -= rnew;
        code -= rnew;
        Renorm(DECODE);
        return 1;
      } 
    } else {
      if( bit==0 ) { 
        range = rnew;
      } else {
        range -= rnew;
Carry += (low+rnew<low);
        low  += rnew;
     }
      Renorm(DECODE);
      return 0;
    }
  }

  void ShiftLow( void ) {
    if( low<Thres || Carry ) {
      put( Cache+Carry );
      for (;FFNum != 0;FFNum--) put( Carry-1 ); 
      Cache = low>>24;
      Carry = 0;
    } else FFNum++;
    low<<=8;
  }

  void ShiftLow2( void ) {
    if( low<Thres || Carry ) {
      put( Cache+Carry );
      for (;FFNum != 0;FFNum--) put( Carry-1 ); 
      Cache = low>>24;
      Carry = 0;
    } else FFNum++;
    low &= sTOP-1;
    if( low<Threg ) {
      put( Cache );
      for(; FFNum!=0; FFNum-- ) put( 0xFF ); 
      Cache = low>>16;
    } else FFNum++;
    low<<=16;
  }

  void rcInit( void ) { 
    range = 0xFFFFFFFF;
    low   = 0;
    FFNum = 0;
    Carry = 0;    
    Cache = 0; cflag=0;
  }
  
  void Init( int mode=0, FILE* f=0 ) {
    ProcMode = mode;
    io.CodeFile = f;
    rcInit();
    if( ProcMode==1 ) {
      for(int _=0; _<NUM; _++) code=(code<<8)+get(); 
    }
  }

  void Quit( void ) {
    if( ProcMode==0 ) {
      range--;
      do {
        ShiftLow(); range=(range<<8)+255;
      } while( low || (range+1) );

      uint h=low+range; if( h<low ) h=0xFFFFFFFF;
      if( (low|0xFF)<h ) low|=0xFF;
      if( (low|0xFFFF)<h ) low|=0xFFFF;
      if( (low|0xFFFFFF)<h ) low|=0xFFFFFF;
      if( (low|0xFFFFFFFF)<=h ) low|=0xFFFFFFFF;

      int f1=1,f2=1;

      if( low==0xFFFFFFFF ) {
        f1=f2=0;
        if( Carry && (Cache==0xFE) && (FFNum==0) ) {
        } else if( (Carry==0) && (Cache==0xFF) ) {
        } else {
          f1=1;
          if( Carry ) f2=1;
        }
      };

      if( f1 ) put( Cache+Carry );
      if( f2 ) for (;FFNum != 0;FFNum--) put( Carry-1 ); 

      while( low!=0xFFFFFFFF ) { 
        put( low>>24 );
        low=(low<<8)+0xFF;
      }
    }
  }

};

const int CNUM=256;

struct Node2j {
  word P;  
  void Update( int c, const int wr1, const int Mw ) {
    int dp = P + Mw-SCALE + ((SCALE-2*Mw)&(-c));
    int q = P - ((dp*wr1)>>SCALElog);

    P = q;
  }
};

enum {
  M_m1W0 = (3862)*8,
  M_m2W0 = (4095)*8,
  M_m3W0 = (1538)*8,
  M_m4W0 = (128)*8,
  M_m5W0 = (1344)*8,
  M_m6W0 = (4082)*8,
  M_m7W0 = (2322)*8,
  M_m1wr = 35708,
  M_m2wr = 25053,
  M_m3wr = 35938,
  M_m4wr = 65520,
  M_m5wr = 31872,
  M_m6wr = 63530,
  M_m7wr = 32128,
  M_m1wq = 19904,
  M_m2wq = 1068,
  M_m3wq = 4098,
  M_m4wq = 5938,
  M_m5wq = 11328,
  M_m6wq = 23456,
  M_m7wq = 3856,
  M_f0wr = 16*32768/(0+16),
  M_f0mw = 8348+1,
  M_f1wr = 16*32768/(191+16),
  M_f1mw = 991+1,
  M_f1Awr = 16*32768/(480+16),
  M_f1Amw = 1087+1,
  M_g0wr = 16*32768/(294+16),
  M_g0mw = 18492+1,
  M_g1wr = 16*32768/(48+16),
  M_g1mw = 32760+1,
  M_g1Awr = 16*32768/(16+16),
  M_g1Amw = 32767+1,
  M_g2wr = 16*32768/(0+16),
  M_g2mw = 5628+1,
  M_g3wr = 16*32768/(56+16),
  M_g3mw = 1027+1,
  M_f2wr = 16*32768/(608+16),
  M_f2mw = 4166+1,
  M_f3wr = 16*32768/(260+16),
  M_f3mw = 2120+1,
  U_stem00 = 0,
  U_stem01 = 2315,
  U_stem02 = 4176,
  U_stem03 = 3,
  U_stem04 = 4,
  U_stem05 = 5,
  U_stem06 = 16,
  U_stem07 = 8,
  U_stem08 = 3,
  U_stem09 = 66,
  U_stem10 = 3329,
  U_stem11 = 128,
  U_stem12 = 81,
  U_stem13 = 96,
  U_stem14 = 1031,
  U_stem15 = 1032,
  U_stem16 = 1035,
  U_stem17 = 1080,
  U_stem18 = 1272,
  U_stem19 = 2052,
  U_stem20 = 1996,
  U_stem21 = 3072,
  U_stem22 = 3602,
  U_stem23 = 5632,
  U_stem24 = 6048,
  U_stem25 = 6592,
  U_stem26 = 7554,
  U_stem27 = 8981,
  U_stem28 = 9701,
  U_stem29 = 11272,
  U_stem30 = 12931,
  U_stem31 = 15328,
  W_stem00 = 2048,
  W_stem01 = 8,
  W_stem02 = 0,
  W_stem03 = 0,
  W_stem04 = 1,
  W_stem05 = 4,
  W_stem06 = 15,
  W_stem07 = 28,
  W_stem08 = 62,
  W_stem09 = 104,
  W_stem10 = 161,
  W_stem11 = 256,
  W_stem12 = 385,
  W_stem13 = 544,
  W_stem14 = 708,
  W_stem15 = 944,
  W_stem16 = 1183,
  W_stem17 = 1540,
  W_stem18 = 1960,
  W_stem19 = 2436,
  W_stem20 = 2928,
  W_stem21 = 3588,
  W_stem22 = 4368,
  W_stem23 = 5120,
  W_stem24 = 6147,
  W_stem25 = 7015,
  W_stem26 = 8208,
  W_stem27 = 9385,
  W_stem28 = 10860,
  W_stem29 = 12201,
  W_stem30 = 13696,
  W_stem31 = 15108
};

static const byte M_f0x_f0mask0[256]={ 0,0,1,2,3,4,5,6,7,7,8,8,9,9,10,10,11,12,11,12,13,14,13,14,15,16,15,16,17,18,17,18,19,20,21,22,19,20,21,22,23,24,25,26,23,24,25,26,27,28,29,30,27,28,29,30,31,32,33,34,31,32,33,34,35,35,36,36,37,37,38,38,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,47,47,48,48,49,49,50,50,51,52,51,52,53,54,53,54,55,56,55,56,57,58,57,58,51,52,51,52,53,54,53,54,55,56,55,56,57,58,57,58,59,60,59,60,61,62,61,62,63,64,63,64,65,66,65,66,59,60,59,60,61,62,61,62,63,64,63,64,65,66,65,66,67,68,67,68,69,70,69,70,71,72,71,72,73,74,73,74,67,68,67,68,69,70,69,70,71,72,71,72,73,74,73,74,75,76,75,76,77,78,77,78,79,80,79,80,81,82,81,82,75,76,75,76,77,78,77,78,79,80,79,80,81,82,81,82 };
static const byte M_f2x_f2mask0[256]={ 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29,30,30,30,30,31,32,31,32,31,32,31,32,33,34,33,34,33,34,33,34,35,36,35,36,35,36,35,36,37,38,37,38,37,38,37,38,39,40,39,40,39,40,39,40,41,42,41,42,41,42,41,42,43,44,43,44,43,44,43,44,45,46,45,46,45,46,45,46,47,47,48,48,47,47,48,48,47,47,48,48,47,47,48,48,49,49,50,50,49,49,50,50,49,49,50,50,49,49,50,50,51,51,52,52,51,51,52,52,51,51,52,52,51,51,52,52,53,53,54,54,53,53,54,54,53,53,54,54,53,53,54,54,55,55,56,56,55,55,56,56,55,55,56,56,55,55,56,56,57,57,58,58,57,57,58,58,57,57,58,58,57,57,58,58,59,59,60,60,59,59,60,60,59,59,60,60,59,59,60,60,61,61,62,62,61,61,62,62,61,61,62,62,61,61,62,62 };
static const byte M_g0x_g0mask0[256]={ 0,0,1,1,2,3,2,3,4,4,5,5,4,4,5,5,6,7,6,7,8,9,8,9,6,7,6,7,8,9,8,9,10,11,12,13,10,11,12,13,14,15,16,17,14,15,16,17,10,11,12,13,10,11,12,13,14,15,16,17,14,15,16,17,18,19,20,21,22,23,24,25,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,26,27,28,29,30,31,32,33,18,19,20,21,22,23,24,25,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65 };
static const byte M_g2x_g2mask0[256]={ 0,0,1,1,2,3,2,3,4,5,6,7,4,5,6,7,8,9,10,11,12,13,14,15,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127 };
static const byte M_m1x_m1mask0[256]={ 0,0,1,1,2,2,2,2,3,4,3,4,3,4,3,4,5,5,6,6,5,5,6,6,5,5,6,6,5,5,6,6,7,7,7,7,8,8,8,8,7,7,7,7,8,8,8,8,7,7,7,7,8,8,8,8,7,7,7,7,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12 };
static const byte M_m2x_m2mask0[256]={ 0,0,1,1,2,2,2,2,3,4,3,4,3,4,3,4,5,5,6,6,5,5,6,6,5,5,6,6,5,5,6,6,7,8,7,8,9,10,9,10,7,8,7,8,9,10,9,10,7,8,7,8,9,10,9,10,7,8,7,8,9,10,9,10,11,11,12,12,11,11,12,12,13,13,14,14,13,13,14,14,11,11,12,12,11,11,12,12,13,13,14,14,13,13,14,14,11,11,12,12,11,11,12,12,13,13,14,14,13,13,14,14,11,11,12,12,11,11,12,12,13,13,14,14,13,13,14,14,15,15,15,15,16,16,16,16,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,17,17,17,17,18,18,18,18,15,15,15,15,16,16,16,16,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,17,17,17,17,18,18,18,18,15,15,15,15,16,16,16,16,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,17,17,17,17,18,18,18,18,15,15,15,15,16,16,16,16,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,17,17,17,17,18,18,18,18 };
static const byte M_m7x_m7mask0[256]={ 0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,63,64,64,65,65,66,66,67,67,68,68,69,69,70,70,71,71,72,72,73,73,74,74,75,75,76,76,77,77,78,78,79,79,80,80,81,81,82,82,83,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,91,91,92,92,93,93,94,94,95,95,95,95,96,96,96,96,97,97,97,97,98,98,98,98,99,99,99,99,100,100,100,100,101,101,101,101,102,102,102,102,103,103,103,103,104,104,104,104,105,105,105,105,106,106,106,106,107,107,107,107,108,108,108,108,109,109,109,109,110,110,110,110,111,111,111,111,112,112,112,112,113,113,113,113,114,114,114,114,115,115,115,115,116,116,116,116,117,117,117,117,118,118,118,118,119,119,119,119,120,120,120,120,121,121,121,121,122,122,122,122,123,123,123,123,124,124,124,124,125,125,125,125,126,126,126,126 };

static const uint M_f0x_Volume = 1ULL* 83; 
static const uint M_f1x_Volume = 1ULL* (1<<4)* 256; 
static const uint M_f2x_Volume = 1ULL* (1<<3)* (1<<2)* 63; 
static const uint M_f3x_Volume = 1ULL* (1<<4)* 256; 
static const uint M_g0x_Volume = 1ULL* 66; 
static const uint M_g1x_Volume = 1ULL* (1<<7)* 256; 
static const uint M_g2x_Volume = 1ULL* (1<<6)* (1<<7)* 128; 
static const uint M_g3x_Volume = 1ULL* (1<<2)* 256; 
static const uint M_m1x_Volume = 1ULL* 13; 
static const uint M_m2x_Volume = 1ULL* (1<<1)* (1<<3)* 19; 
static const uint M_m3x_Volume = 1ULL* (1<<7)* 256; 
static const uint M_m4x_Volume = 1ULL* (1<<4)* 256; 
static const uint M_m5x_Volume = 1ULL* (1<<2)* (1<<3)* 256; 
static const uint M_m6x_Volume = 1ULL* (1<<3)* 256; 
static const uint M_m7x_Volume = 1ULL* (1<<1)* (1<<5)* 127; 

word coeffsU[32] = {
  U_stem00, U_stem01, U_stem02, U_stem03, U_stem04, U_stem05, U_stem06, U_stem07,
  U_stem08, U_stem09, U_stem10, U_stem11, U_stem12, U_stem13, U_stem14, U_stem15,
  U_stem16, U_stem17, U_stem18, U_stem19, U_stem20, U_stem21, U_stem22, U_stem23,
  U_stem24, U_stem25, U_stem26, U_stem27, U_stem28, U_stem29, U_stem30, U_stem31
};

word coeffsW[32] = {
  W_stem00, W_stem01, W_stem02, W_stem03, W_stem04, W_stem05, W_stem06, W_stem07,
  W_stem08, W_stem09, W_stem10, W_stem11, W_stem12, W_stem13, W_stem14, W_stem15,
  W_stem16, W_stem17, W_stem18, W_stem19, W_stem20, W_stem21, W_stem22, W_stem23,
  W_stem24, W_stem25, W_stem26, W_stem27, W_stem28, W_stem29, W_stem30, W_stem31
};

struct valmap {

  word stems[32+1];
  word sq[hSCALE+1];
  word st[hSCALE+1];

  valmap( word* coeffs ) {
    int i,j,c, k,r;

    for( i=0; i<32; i++ ) stems[i]=coeffs[i];
    for( i=32-2; i>=0; i-- ) if( stems[i]>stems[i+1] ) stems[i]=stems[i+1];
    stems[32] = hSCALE;

    enum {
      STEM_COUNT = 33, 
      DELTA = hSCALE/(STEM_COUNT-1)
    };

    for( i=0,k=0; i<hSCALE; i+=DELTA,k++ )
      for( r=0; r<=DELTA; r++ ) sq[i+r] = ((DELTA-r)*stems[k+0] + r*stems[k+1])/DELTA;

    for( i=0; i<hSCALE; i++ ) for( j=sq[i]; j<sq[i+1]; j++ ) st[j]=hSCALE-i;
    st[0] = hSCALE;
  }

  int Stretch( int x ) { return x<hSCALE ? -st[x] : st[SCALE-x]; }

  int Squash0( int x ) { return x>=0 ? sq[x] : 0; }
  int Squash( int x )  { 
    return x>=0 ? SCALE-Squash0(hSCALE-x) : Squash0(hSCALE+x);
  }

};

valmap U(coeffsU);

valmap W(coeffsW);

struct iMixer {
  word w;  

  void Init( int w0 ) { 
    w = w0 + hSCALE;
  }

  int rdiv( int x, int a, int d ) {  

    return (x+a)>>d;
  }

  static int st( int p ) { return U.Stretch(p); }
  static int sq( int p ) { return W.Squash(p);  }

  int Mixup( int s0, int s1, int wr ) {
    int x = s1 + rdiv((w-hSCALE)*(s0-s1),1<<(SCALElog-1),SCALElog);
    x = rdiv( (x*wr), 1<<(SCALElog-1), SCALElog );
    return x;
  }

  void Update( int y, int p0,int p1, int wq, int pm ) {
    int py = SCALE - (y<<SCALElog);
    int e = (py-pm);
    int d = rdiv( e*(p0-p1), 1<<(SCALElog-1), SCALElog );
    d = rdiv( d*wq, 1<<(SCALElog-1), SCALElog );
    w += d;
  }
};



uint flen( FILE* f ) {
  fseek( f, 0, SEEK_END );
  uint len = ftell(f);
  fseek( f, 0, SEEK_SET );
  return len;
}



struct M_T {
  Node2j M_f0[M_f0x_Volume];
  Node2j M_f1[M_f1x_Volume];
  Node2j M_f2[M_f2x_Volume];
  Node2j M_f3[M_f3x_Volume];
  Node2j M_g0[M_g0x_Volume];
  Node2j M_g1[M_g1x_Volume];
  Node2j M_g2[M_g2x_Volume];
  Node2j M_g3[M_g3x_Volume];
  iMixer M_m1[M_m1x_Volume];
  iMixer M_m2[M_m2x_Volume];
  iMixer M_m3[M_m3x_Volume];
  iMixer M_m4[M_m4x_Volume];
  iMixer M_m5[M_m5x_Volume];
  iMixer M_m6[M_m6x_Volume];
  iMixer M_m7[M_m7x_Volume];
  
  M_T( void ) {
    int i;
    for( i=0; i<M_f0x_Volume; i++ ) M_f0[i].P=hSCALE;
    for( i=0; i<M_f1x_Volume; i++ ) M_f1[i].P=hSCALE;
    for( i=0; i<M_f2x_Volume; i++ ) M_f2[i].P=hSCALE;
    for( i=0; i<M_f3x_Volume; i++ ) M_f3[i].P=hSCALE;
    for( i=0; i<M_g0x_Volume; i++ ) M_g0[i].P=hSCALE;
    for( i=0; i<M_g1x_Volume; i++ ) M_g1[i].P=hSCALE;
    for( i=0; i<M_g2x_Volume; i++ ) M_g2[i].P=hSCALE;
    for( i=0; i<M_g3x_Volume; i++ ) M_g3[i].P=hSCALE;
    for( i=0; i<M_m1x_Volume; i++ ) M_m1[i].Init( M_m1W0 );
    for( i=0; i<M_m2x_Volume; i++ ) M_m2[i].Init( M_m2W0 );
    for( i=0; i<M_m3x_Volume; i++ ) M_m3[i].Init( M_m3W0 );
    for( i=0; i<M_m4x_Volume; i++ ) M_m4[i].Init( M_m4W0 );
    for( i=0; i<M_m5x_Volume; i++ ) M_m5[i].Init( M_m5W0 );
    for( i=0; i<M_m6x_Volume; i++ ) M_m6[i].Init( M_m6W0 );
    for( i=0; i<M_m7x_Volume; i++ ) M_m7[i].Init( M_m7W0 );
  }
};

struct Model : public M_T {

  void Flush( void ) {
    this->~Model();
    new(this) Model();
  }
  void* operator new( size_t N, void* p ) { return p; }

  int f1( int pp, int p, int ctx, int b ) {
    int f1x;

    f1x = 0;
    f1x = (f1x<<4) + (((p)>>1)&15); 
    f1x = (f1x*256) + (ctx); 
    return f1x;
  }

  int g1( int pp, int p, int ctx, int b ) {
    int g1x;

    g1x = 0;
    g1x = (g1x<<7) + (((pp)>>1)&96) + ((pp)&31); 
    g1x = (g1x*256) + (ctx); 
    return g1x;
  }

  int process( int DECODE, int bit, Rangecoder_SH1m& rc, int pp, int p, int ctx, int b ) {
    int f0x,f1x,f2x,f3x, f1y;
    int g0x,g1x,g2x,g3x, g1y;

    f1y = f1(p,pp,ctx,b);
    g1y = g1(p,pp,ctx,b);


    f0x = 0;
    f0x = (f0x*83) + M_f0x_f0mask0[ctx]; 

    f1x = 0;
    f1x = (f1x<<4) + (((p)>>1)&15); 
    f1x = (f1x*256) + (ctx); 

    f2x = 0;
    f2x = (f2x<<3) + (((pp)>>5)&4) + (((pp)>>3)&3); 
    f2x = (f2x<<2) + (((p)>>3)&3); 
    f2x = (f2x*63) + M_f2x_f2mask0[ctx]; 

    f3x = 0;
    f3x = (f3x<<4) + (((p)>>2)&15); 
    f3x = (f3x*256) + (ctx); 

    g0x = 0;
    g0x = (g0x*66) + M_g0x_g0mask0[ctx]; 

    g1x = 0;
    g1x = (g1x<<7) + (((pp)>>1)&96) + ((pp)&31); 
    g1x = (g1x*256) + (ctx); 

    g2x = 0;
    g2x = (g2x<<6) + ((pp)&63); 
    g2x = (g2x<<7) + ((p)&127); 
    g2x = (g2x*128) + M_g2x_g2mask0[ctx]; 

    g3x = 0;
    g3x = (g3x<<2) + (((p)>>4)&3); 
    g3x = (g3x*256) + (ctx); 

    int m1x,m2x,m3x,m4x,m5x,m6x,m7x;

    m1x = 0;
    m1x = (m1x*13) + M_m1x_m1mask0[ctx]; 

    m2x = 0;
    m2x = (m2x<<1) + (((pp)>>6)&1); 
    m2x = (m2x<<3) + (((p)>>3)&4) + (((p)>>2)&3); 
    m2x = (m2x*19) + M_m2x_m2mask0[ctx]; 

    m3x = 0;
    m3x = (m3x<<7) + ((p)>>1); 
    m3x = (m3x*256) + (ctx); 

    m4x = 0;
    m4x = (m4x<<4) + (((p)>>4)&8) + (((p)>>2)&6) + (((p)>>1)&1); 
    m4x = (m4x*256) + (ctx); 

    m5x = 0;
    m5x = (m5x<<2) + ((pp)>>6); 
    m5x = (m5x<<3) + ((p)>>5); 
    m5x = (m5x*256) + (ctx); 

    m6x = 0;
    m6x = (m6x<<3) + ((p)>>5); 
    m6x = (m6x*256) + (ctx); 

    m7x = 0;
    m7x = (m7x<<1) + (((pp)>>5)&1); 
    m7x = (m7x<<5) + ((p)>>3); 
    m7x = (m7x*127) + M_m7x_m7mask0[ctx]; 

    int p1 = M_m1[m1x].st(M_f0[f0x].P);
    int p2 = M_m1[m1x].st(M_g0[g0x].P);
    int p3 = M_m2[m2x].st(M_f1[f1x].P);
    int p4 = M_m2[m2x].st(M_g1[g1x].P);
    int p5 = M_m4[m4x].st(M_g2[g2x].P);
    int p6 = M_m4[m4x].st(M_g3[g3x].P);
    int p7 = M_m6[m6x].st(M_f2[f2x].P);
    int p8 = M_m6[m6x].st(M_f3[f3x].P);
    int pA = M_m1[m1x].Mixup( p1, p2, M_m1wr );
    int pB = M_m2[m2x].Mixup( p3, p4, M_m2wr );
    int pC = M_m4[m4x].Mixup( p5, p6, M_m4wr );
    int p9 = M_m6[m6x].Mixup( p7, p8, M_m6wr );
    int pD = M_m3[m3x].Mixup( pA, pB, M_m3wr );
    int pE = M_m5[m5x].Mixup( p9, pC, M_m5wr );
    int pF = M_m7[m7x].Mixup( pD, pE, M_m7wr );

    int p0 = M_m7[m7x].sq(pF);


    p0 -= (p0-1)&((p0-1)>>16);
    p0 += (mSCALE-p0)&((mSCALE-p0)>>16);

    int dbit = bit;
    if( DECODE ) {
      dbit = rc.BProcess(1,1, p0 );
      if( dbit ) { M_m1[m1x].Update( 1, p1, p2, M_m1wq, M_m1[m1x].sq(pA) ); M_m2[m2x].Update( 1, p3, p4, M_m2wq, M_m2[m2x].sq(pB) ); M_m4[m4x].Update( 1, p5, p6, M_m4wq, M_m4[m4x].sq(pC) ); M_m6[m6x].Update( 1, p7, p8, M_m6wq, M_m6[m6x].sq(p9) ); M_m3[m3x].Update( 1, pA, pB, M_m3wq, M_m3[m3x].sq(pD) ); M_m5[m5x].Update( 1, p9, pC, M_m5wq, M_m5[m5x].sq(pE) ); M_m7[m7x].Update( 1, pD, pE, M_m7wq, p0 ); M_f0[f0x].Update( 1, M_f0wr, M_f0mw ); M_f1[f1x].Update( 1, M_f1wr, M_f1mw ); M_f1[f1y].Update( 1, M_f1Awr, M_f1Amw ); M_f2[f2x].Update( 1, M_f2wr, M_f2mw ); M_f3[f3x].Update( 1, M_f3wr, M_f3mw ); M_g0[g0x].Update( 1, M_g0wr, M_g0mw ); M_g1[g1x].Update( 1, M_g1wr, M_g1mw ); M_g1[g1y].Update( 1, M_g1Awr, M_g1Amw ); M_g2[g2x].Update( 1, M_g2wr, M_g2mw ); M_g3[g3x].Update( 1, M_g3wr, M_g3mw ); } else { M_m1[m1x].Update( 0, p1, p2, M_m1wq, M_m1[m1x].sq(pA) ); M_m2[m2x].Update( 0, p3, p4, M_m2wq, M_m2[m2x].sq(pB) ); M_m4[m4x].Update( 0, p5, p6, M_m4wq, M_m4[m4x].sq(pC) ); M_m6[m6x].Update( 0, p7, p8, M_m6wq, M_m6[m6x].sq(p9) ); M_m3[m3x].Update( 0, pA, pB, M_m3wq, M_m3[m3x].sq(pD) ); M_m5[m5x].Update( 0, p9, pC, M_m5wq, M_m5[m5x].sq(pE) ); M_m7[m7x].Update( 0, pD, pE, M_m7wq, p0 ); M_f0[f0x].Update( 0, M_f0wr, M_f0mw ); M_f1[f1x].Update( 0, M_f1wr, M_f1mw ); M_f1[f1y].Update( 0, M_f1Awr, M_f1Amw ); M_f2[f2x].Update( 0, M_f2wr, M_f2mw ); M_f3[f3x].Update( 0, M_f3wr, M_f3mw ); M_g0[g0x].Update( 0, M_g0wr, M_g0mw ); M_g1[g1x].Update( 0, M_g1wr, M_g1mw ); M_g1[g1y].Update( 0, M_g1Awr, M_g1Amw ); M_g2[g2x].Update( 0, M_g2wr, M_g2mw ); M_g3[g3x].Update( 0, M_g3wr, M_g3mw ); }
    } else {
      rc.BProcess(0,bit, p0 );
      M_m1[m1x].Update( bit, p1, p2, M_m1wq, M_m1[m1x].sq(pA) ); M_m2[m2x].Update( bit, p3, p4, M_m2wq, M_m2[m2x].sq(pB) ); M_m4[m4x].Update( bit, p5, p6, M_m4wq, M_m4[m4x].sq(pC) ); M_m6[m6x].Update( bit, p7, p8, M_m6wq, M_m6[m6x].sq(p9) ); M_m3[m3x].Update( bit, pA, pB, M_m3wq, M_m3[m3x].sq(pD) ); M_m5[m5x].Update( bit, p9, pC, M_m5wq, M_m5[m5x].sq(pE) ); M_m7[m7x].Update( bit, pD, pE, M_m7wq, p0 ); M_f0[f0x].Update( bit, M_f0wr, M_f0mw ); M_f1[f1x].Update( bit, M_f1wr, M_f1mw ); M_f1[f1y].Update( bit, M_f1Awr, M_f1Amw ); M_f2[f2x].Update( bit, M_f2wr, M_f2mw ); M_f3[f3x].Update( bit, M_f3wr, M_f3mw ); M_g0[g0x].Update( bit, M_g0wr, M_g0mw ); M_g1[g1x].Update( bit, M_g1wr, M_g1mw ); M_g1[g1y].Update( bit, M_g1Awr, M_g1Amw ); M_g2[g2x].Update( bit, M_g2wr, M_g2mw ); M_g3[g3x].Update( bit, M_g3wr, M_g3mw );
    }

    return dbit;
  }

} M;


void process( int mode, FILE* f, FILE* g, uint f_len ) {
  int b,bit,c,i,j,k,p,pp,pq;

  static Rangecoder_SH1m rc;
  if( rc.cflag==0 ) rc.Init( mode, g );

  pq = pp = p = 0;
  for( i=0; i<f_len; i++ ) {

    if( mode==0 ) c = getc( f );

    uint ctx=1;
    for( b=4; b>=0; b-- ) {
      if( ((ctx+ctx+1)<<b) > ( 32+0x19 ) ) {
        ctx += ctx;
      } else {
        if( mode ) {
          bit = M.process(1,1,rc,pp,p,ctx,b);
          ctx += ctx + bit;
        } else {
          if( (c&(1<<b))==0 ) {
            M.process(0,0,rc,pp,p,ctx,b);
            ctx += ctx;
          } else {
            M.process(0,1,rc,pp,p,ctx,b);
            ctx += ctx + 1;
          }
        }
      }
    }

    c = ctx&0x1F;

    if( mode==1 ) putc( c, f );

    pq = pp; pp = p; p = c;
  }

  rc.Quit();
}

int main( int argc, char** argv ) {

  int mode = argc<2 ? 1 : argv[1][0]!='d';
  FILE* f = fopen( argc<3 ? mode ? "book1bwt"     : "book1bwt.ari" : argv[2], "rb" );
  FILE* g = fopen( argc<4 ? mode ? "book1bwt.ari" : "book1bwt.unp" : argv[3], "wb" );
  if( (f==0) || (g==0) ) return 1;

  if( mode ) {
uint f_len = 1674;

    process( 0, f, g, f_len );

  } else {
    uint f_len;
f_len = 1674;

    process( 1, g, f, f_len );
  }
 
  fclose(f);
  fclose(g);

  return 0;
}
