var Via1ORB=0x9120;var Via1IRB=0x9120;var Via1ORA=0x9121;var Via1IRA=0x9121;var Via1DDRB=0x9122;var Via1DDRA=0x9123;var Via1T1C_L=0x9124;var Via1T1C_H=0x9125;var Via1T1L_L=0x9126;var Via1T1L_H=0x9127;var Via1T2C_L=0x9128;var Via1T2C_H=0x9129;var Via1SR=0x912A;var Via1ACR=0x912B;var Via1PCR=0x912C;var Via1IFR=0x912D;var Via1IER=0x912E;var Via1ORA_nohs=0x912F;var Via1IRA_nohs=0x912F;var Via2ORB=0x9110;var Via2IRB=0x9110;var Via2ORA=0x9111;var Via2IRA=0x9111;var Via2DDRB=0x9112;var Via2DDRA=0x9113;var Via2T1C_L=0x9114;var Via2T1C_H=0x9115;var Via2T1L_L=0x9116;var Via2T1L_H=0x9117;var Via2T2C_L=0x9118;var Via2T2C_H=0x9119;var Via2SR=0x911A;var Via2ACR=0x911B;var Via2PCR=0x911C;var Via2IFR=0x911D;var Via2IER=0x911E;var Via2ORA_nohs=0x911F;var Via2IRA_nohs=0x911F;var keysdown=[0,0,0,0,0,0,0,0];var writeReg1,writeValue1;var pins_ira1=0,pins_irb1=0,t2l_l1=0;var inhibitT1Interrupt1=0,inhibitT2Interrupt1=0;var isvia1interrupt=0;var pins_ira2=0,pins_irb2=0,t2l_l2=0;var inhibitT1Interrupt2=0,inhibitT2Interrupt2=0;var isvia2Nmi=0;function Via1(){pins_ira1=pins_irb1=t2l_l1=writeReg1=writeValue1=0;inhibitT1Interrupt1=inhibitT2Interrupt1=1;pins_ira2=pins_irb2=t2l_l2=0;inhibitT1Interrupt2=inhibitT2Interrupt2=1;}function Via1clock(ccc){if(writeReg1){switch(writeReg1){case Via1ORA:case Via1ORA_nohs:m[Via1ORA]=m[Via1ORA_nohs]=writeValue1;updateJoystickAndKeyboard();break;case Via1T1C_L:m[Via1T1L_L]=writeValue1;break;case Via1T1C_H:m[Via1T1L_H]=m[Via1T1C_H]=writeValue1;m[Via1T1C_L]=m[Via1T1L_L];m[Via1IFR]&=~0x40;isvia1interrupt=m[0x912E]&m[0x912D]&127;inhibitT1Interrupt1=0;break;case Via1T2C_L:t2l_l1=writeValue1;break;case Via1T2C_H:m[Via1T2C_H]=writeValue1;m[Via1T2C_L]=t2l_l1;m[Via1IFR]&=~0x20;isvia1interrupt=m[0x912E]&m[0x912D]&127;inhibitT2Interrupt1=0;break;case Via1IFR:m[Via1IFR]&=~writeValue1;isvia1interrupt=m[Via1IER]&m[Via1IFR]&127;break;case Via1IER:if(writeValue1>127)m[Via1IER]|=writeValue1;else m[Via1IER]&=~writeValue1;isvia1interrupt=m[0x912E]&m[0x912D]&127;break;case Via2ORA:case Via2ORA_nohs:m[Via2ORA]=m[Via2ORA_nohs]=writeValue1;break;case Via2T1C_L:m[Via2T1L_L]=writeValue1;break;case Via2T1C_H:m[Via2T1L_H]=m[Via2T1C_H]=writeValue1;m[Via2T1C_L]=m[Via2T1L_L];m[Via2IFR]&=~0x40;isvia2Nmi=m[0x911E]&m[0x911D]&127;inhibitT1Interrupt2=0;break;case Via2T2C_L:t2l_l1=writeValue1;break;case Via2T2C_H:m[Via2T2C_H]=writeValue1;m[Via2T2C_L]=t2l_l1;m[Via2IFR]&=~0x20;isvia2Nmi=m[0x911E]&m[0x911D]&127;inhibitT2Interrupt1=0;break;case Via2IFR:m[Via2IFR]&=~writeValue1;isvia2Nmi=m[Via2IER]&m[Via2IFR]&127;break;case Via2IER:if(writeValue1>127)m[Via2IER]|=writeValue1;else m[Via2IER]&=~writeValue1;isvia2Nmi=m[0x911E]&m[0x911D]&127;break;case Via1DDRA:case Via1DDRB:case Via1ORB:m[writeReg1]=writeValue1;updateJoystickAndKeyboard();break;default:m[writeReg1]=writeValue1;}}var acr=m[0x912B];if((m[0x9124]-=ccc)<0){m[0x9124]&=255;m[0x9125]--;if(m[Via1T1C_H]==-1){m[Via1T1C_H]=255;if(acr&0x40){m[Via1T1C_L]=m[Via1T1L_L];m[Via1T1C_H]=m[Via1T1L_H];m[Via1IFR]|=0x40;isvia1interrupt=m[0x912E]&m[0x912D]&127;}else if(!inhibitT1Interrupt1){m[Via1IFR]|=0x40;inhibitT1Interrupt1=1;isvia1interrupt=m[0x912E]&m[0x912D]&127;}}}if((acr&0x20)==0){m[0x9128]-=ccc;if(m[0x9128]<0){m[0x9128]&=255;m[0x9129]--;if(m[0x9129]==-1){m[0x9129]=255;if(!inhibitT2Interrupt1){m[0x912D]|=0x20;inhibitT2Interrupt1=1;isvia1interrupt=m[0x912E]&m[0x912D]&127;}}}}var acr=m[0x911B];if((m[0x9114]-=ccc)<0){m[0x9114]&=255;m[0x9115]--;if(m[Via2T1C_H]==-1){m[Via2T1C_H]=255;if(acr&0x40){m[Via2T1C_L]=m[Via2T1L_L];m[Via2T1C_H]=m[Via2T1L_H];m[Via2IFR]|=0x40;isvia2Nmi=m[0x911E]&m[0x911D]&127;}else if(!inhibitT1Interrupt2){m[Via2IFR]|=0x40;inhibitT1Interrupt2=1;isvia2Nmi=m[0x911E]&m[0x911D]&127;}}}if((acr&0x20)==0){m[0x9118]-=ccc;if(m[0x9118]<0){m[0x9118]&=255;m[0x9119]--;if(m[0x9119]==-1){m[0x9119]=255;if(!inhibitT2Interrupt2){m[0x911D]|=0x20;inhibitT2Interrupt2=1;isvia2Nmi=m[0x911E]&m[0x911D]&127;}}}}writeReg1=0;}function updateJoystickAndKeyboard(){if(fire)pins_ira2|=32;else pins_ira2&=~32;if(left)pins_ira2|=16;else pins_ira2&=~16;if(up)pins_ira2|=4;else pins_ira2&=~4;if(down)pins_ira2|=8;else pins_ira2&=~8;var column=~(m[Via1ORB]&m[Via1DDRB]),row=~(m[Via1ORA]&m[Via1DDRA]);pins_ira1=pins_irb1=0;for(var i=0;i<8;i++){if((column&(1<<i))!=0)pins_ira1|=keysdown[i];pins_irb1|=((keysdown[i]&row)!=0)?(1<<i):0;}if((m[Via1DDRB]&0x80)==0){if(right)pins_irb1|=0x80;else pins_irb1&=~0x80;}}function Via1Read(regnum,type){switch(regnum){case Via1IRA:case Via1IRA_nohs:return(~pins_ira1&~m[Via1DDRA])&255;case Via1IRB:{var ddrb=m[Via1DDRB];var pins_in=~pins_irb1&~ddrb;var reg_in=m[Via1ORB]&ddrb;return(pins_in|reg_in)&255;}case Via1T1C_L:{m[Via1IFR]&=~0x40;isvia1interrupt=m[0x912E]&m[0x912D]&127;inhibitT1Interrupt1=0;return m[regnum];}case Via1T2C_L:{m[Via1IFR]&=~0x20;isvia1interrupt=m[0x912E]&m[0x912D]&127;inhibitT2Interrupt1=0;return m[regnum];}case Via1IFR:{var result=m[Via1IFR]&0x7F;if(result!=0)result|=0x80;return result;}case Via1IER:return m[Via1IER]|0x80;case Via2IRA:case Via2IRA_nohs:return(~pins_ira2&~m[Via2DDRA])&255;case Via2IRB:{var ddrb=m[Via2DDRB];var pins_in=~pins_irb2&~ddrb;var reg_in=m[Via2ORB]&ddrb;return(pins_in|reg_in)&255;}case Via2T1C_L:{m[Via2IFR]&=~0x40;isvia2Nmi=m[0x911E]&m[0x911D]&127;inhibitT1Interrupt1=0;return m[regnum];}case Via2T2C_L:{m[Via2IFR]&=~0x20;isvia2Nmi=m[0x911E]&m[0x911D]&127;inhibitT2Interrupt1=0;return m[regnum];}case Via2IFR:{var result=m[Via2IFR]&0x7F;if(result!=0)result|=0x80;return result;}case Via2IER:return m[Via2IER]|0x80;default:return m[regnum];}}function Via1Write(regnum,value){writeReg1=regnum;writeValue1=value;}

/**
 * Copyright 2009 matsondawson@gmail.com
 * 
 * No reproducible in any way without permission. 
 *    
 */

// Debug counters
var compiledSectionsCount = 0;
var compiledInstructionsCount = 0;
var loopsOptimizedCount = 0;
var lsrsOptimizedCount = 0;
var aslsOptimizedCount = 0;

/**
 * Returns maximum value out of a and b.
 */ 
function max(a,b) { return (a>b)?a:b; }

/**
 * 6502 Vectors.
 */ 
var NMI_VECTOR = 0xFFFA;
var RESET_VECTOR = 0xFFFC;
var IRQ_VECTOR = 0xFFFE;

/**
 * 6502 Flags
 */ 
var N = 1 << 7, V = 1 << 6, R = 1 << 5, B = 1 << 4,
        D = 1 << 3, I = 1 << 2, Z = 1 << 1, C = 1;

/**
 * i is the cycle counter within a frame
 */ 
var i=0;

/**
 * Read value from offset in memory, or peripheral.
 */ 
function read(offset) {
    return (offset>0x912F || offset<0x9110)
      ?m[offset]
      :Via1Read(offset);
}

/**
 * Write value to offset in memory, or peripheral.
 */ 
var ramMax = 0x2000;

/**
 * 1 if has 3k expansion memory at 0x400.
 */ 
var has3k = 0;

/**
 * Returns 1 if code execution is to continue, else 0.
 */ 
function write(offset, value) {
    // No memory above 0x2000, and cannot write to ROM
		if ((!has3k && offset>=0x400 && offset<0x1000) || offset==ramMax) return;// || (offset>=0x6000 && offset<0x9000)) return;
		
		if (m[offset]==value) return;
    m[offset]=value;

    // Writing to ram
    if (offset<0x9110 || offset>0x912F) {
      // May be dynamic code so have to clear out any precompiled code within range of this memory location.
			switch(coderange[offset]) {
        case -3: // -3 = non-compiled/data
					modCount[offset>>3]++;
        case -1: // -1 = dynamic value
					return;
    		case -2:
    		  // Needs recompile to dynamic immediates
          coderange[offset] = -1; // -1 means immediate is now dynamic
          
          // Find instruction this byte belongs to
          while(coderange[offset]<0) offset--;
  
          // Compile from offset to change to dynamic, possibly breaking up an existing code block
          uncompiledCodeHandler(offset,0x10000);

          // Compile any other code blocks that previously contained the dynamic ones
          var minAffectedCodeBlock = offset-coderange[offset];
          for(var loop=offset-1; loop>=minAffectedCodeBlock; loop--) {
            if (compiled[loop]!=uncompiledCodeHandler) {
              uncompiledCodeHandler(loop,offset);
            }
    			}
      		// If this recompiled the code we are executing, we need to stop execution.
      		return !(pc<minAffectedCodeBlock || pc>offset);
      		
    		default: // >=0 = instruction
    		  var minAffectedCodeBlock = offset-coderange[offset];

          // when an inst is modified convert all related code blocks to data
          // and exit write if within same block.
          // This allows for a return to static code blocks and merging of split dynamic blocks
          for(var loop=minAffectedCodeBlock; loop<=offset; loop++) {
            coderange[loop]=-3;
            compiled[loop]=uncompiledCodeHandler;
    			}
    			// also erase instruction at offsets immediates
    			loop++;
          while(coderange[loop]==-2 || coderange[loop]==-1) {
            coderange[loop++]=-3;
          }
    			
      		// If this the code changed is the code being executed, we need to stop execution.
      		return !(pc<minAffectedCodeBlock || pc>=offset);
      }
      
		}
		// Via
    else Via1Write(offset,value);
}

/**
 * Push v onto the stack and decrement the stack pointer.
 */ 
function push(v) { m[0x100 + sp]=v,sp=(sp-1)&255; }

/**
 * Inline version of push.
 */ 
function rp_push(v) {
	return "m[0x100+sp]=_v_,sp=(sp-1)&255;".replace(/_v_/,v);
}

/**
 * Increment the stack pointer and pull a value off the stack.
 */ 
function pop() {
	return m[0x100 + (sp=(sp+1)&0xFF)];
}

/**
 * Inline version of pop.
 */ 
var st_pop = "m[0x100 + (sp=(sp+1)&255)]";

/**
 * Add a value to a.
 */ 
function adc(b) {
  if (p & 8) { // D=8
      var sum = (a & 0xF) + (b & 0xF) + (p & 1); // C=1
      if (sum > 0x09) sum += 0x06;
      if (sum > 0x1F) sum -= 0x10;

      sum += (a & 0xF0) + (b & 0xF0);
      p = (p&60) | (((~(a ^ b) & (a ^ sum)) & 128) >> 1); // N = 128
      a = sum & 0xFF;
      p |= (a & 128) | (a?0:2);
      if (sum >= 0xA0) {
          a = (a+0x60)&0xFF;
          p |= 1; // C=1
      }
  } else {
      var sum2 = a + b + (p&1);//(p & C);
      p = (p&60) | (((~(a ^ b) & (a ^ sum2)) & 128) >> 1) | ((sum2 >> 8) & 1); // N = 128, C=1
      a = sum2 & 0xFF;
      p |= (a?0:2)|(a&128)
  }
}

/**
 * Subtract a value from a.
 */ 
function sbc(b) {
  if (p & 8) { // D=8
      var sumadd = 0, sum = (a & 0xF) - (b & 0xF) - (~p & 1);//C=1
      if (sum < -10) sumadd = 10;
      else if (sum < 0) sumadd = -6;

      sum += (a & 0xF0) - (b & 0xF0);
      p = (p&60) | ((sum&0xFF)?0:2) | ((sum & 128) | (((a ^ b) & (a ^ sum)) & 128) >> 1); // N=128
      sum += sumadd;
      if (sum < 0) {
          sum += 0xA0;
      } else {
          if (sum >= 0xA0) {
              sum -= 0x60;
          }
          p |= 1; //C=1
      }

      a = sum & 0xFF;
  } else {
      var sum = a - b - (~p & 1); // C=1
      p = (p&60) | ((((a ^ b) & (a ^ sum)) & 128) >> 1) | (((~sum) >> 8) & 1) | (sum & 128); // N=128, V=1
      a = sum & 0xFF;
      if (a == 0) {
          p |= 2;  //Z=2
      }
  }
}

/**
 * These are place holders for setting nz flags.
 * They are used for optimisation and string replaced at the end of 
 * uncompiledCodeHandler. 
 */ 
var nz_a = "NZA", nz_y = "NZY", nz_x = "NZX", nz_b = "NZB";

/**
 * Inline code for rotate left.
 */ 
function rp_rol(v) {
	return "(nb=(((b="+v+")<<1)&255)|(p&"+C+")),p=(nb?0:"+Z+")|(nb&"+N+")|(b>>7)|(p&"+(~(N|Z|C)&255)+")/*NZA*/";
}

/**
 * Inline code for rotate right.
 */ 
function rp_ror(v) {
	return "(nb=((b="+v+")>>1)|((p&"+C+")<<7)),p=(nb?0:"+Z+")|(nb&"+N+")|(b&"+C+")|(p&"+(~(N|Z|C)&255)+")/*NZA*/";
}

/**
 * Inline code for bit.
 */ 
function rp_bit(v) {
	return "p=((a&(b="+v+"))?0:"+Z+")|(b&"+(N|V)+")|(p&"+(~(N|V|Z)&255)+")/*NZA*/";
}

/**
 * Inline code for logic shift right.
 */ 
function rp_lsr(v) {
  return ("(b=_v_)>>1,p=((b&254)?0:"+Z+")|(b&"+C+")|(p&"+(~(N|Z|C)&255)+")/*NZA*/").replace(/_v_/g,v);
}
function rp_lsr_multiple(v,howmany) {
  return ("(b=_v_>>"+(howmany-1)+")>>1,p=((b&254)?0:"+Z+")|(b&"+C+")|(p&"+(~(N|Z|C)&255)+")/*NZA*/").replace(/_v_/g,v);
}

/**
 * Inline code for arithmetic shift left.
 */ 
function rp_asl(v) {
	return ("(b=_v_<<1)&255,p=((b&255)?0:"+Z+")|(b>>8)|(b&"+N+")|(p&"+(~(N|Z|C)&255)+")/*NZA*/").replace(/_v_/g,v);
}
function rp_asl_multiple(v,howmany) {
  return ("(b=_v_<<"+howmany+")&255,p=((b&255)?0:"+Z+")|((b>>8)&1)|(b&"+N+")|(p&"+(~(N|Z|C)&255)+")/*NZA*/").replace(/_v_/g,v);
}

function isInteger(s) {
  return (s.toString().search(/^-?[0-9]+$/) == 0);
}

/**
 * Inline code for setting nzc flags with non constant.
 */ 
function rp_nzc(r,v) {
	return "p&="+(~(Z|C|N)&0xFF)+";var rv="+r+"-"+v+";p=((rv==0)?(p&"+(~N&0xFF)+"|"+Z+"):(p&"+(~(N|Z)&0xFF)+"|(rv&"+N+")))&0xFF;if(rv>=0)p|="+C+";/*NZA*/";
}

/**
 * Replace occurrences of a _value_ in a string with passed v.
 */ 
function rp(st,v) {
	return st.replace(/_value_/g,v);
}

function rp_bra(cond,rel,offset) {

  var imoff = (isInteger(rel))
    ?((rel>127?(rel-256):rel)+2+offset)
    :"(((b="+rel+")>127?(b-256):b)+"+(offset+2)+")";
  var isNeg = (cond!=1 && cond!=2 && cond!=4 && cond!=8 && cond!=16 && cond!=32 && cond!=64 && cond!=128);
  if (isNeg) cond=~cond;
  
  return "pc=("+(isNeg?"~p":"p")+"&"+cond+")?"+imoff+":"+(offset+2)+";";
}

/**
 * Uh-oh, somethings not right.  Warn the user.
 */ 
function halt(v) {                                                     
	if (v<0 || v>0xFFFF) {
		alert("Emulator fault pc out of range "+v);
	} else {
		alert("Unknown/Unimplemented instruction at "+v.toString(16)+": "+m[v].toString(16)); 
	}
	exit(); // Yeh, I know this ins't a method, but it has the same effect.
}

/**
 * Compile the instruction at offset and return the equivalent source code. 
 */ 
function compileInstruction(offset) {
  var dyn1 = coderange[offset+1]==-1;
  var dyn2 = dyn1 || (coderange[offset+2]==-1);
  
	var inst = m[offset];
	var immi = m[offset+1];
  var imm = dyn1?"m["+(offset+1)+"]":immi; 
	var imm_plus_1 = dyn1?(imm+"+1"):(imm+1);
	var zp_plus_1 = dyn1?("((m["+(offset+1)+"]+1)&255)"):(m[offset+1]+1)&255; 
	var addy =  dyn2?("("+imm+"|(m["+(offset+2)+"]<<8))"):(m[offset+1] | (m[offset+2]<<8)); 
	var addyi = m[offset+1] | (m[offset+2]<<8);
	var addyPlus1Overflow = dyn2?"(("+addy+">>8)<<8)|(("+addy+"+1)&0xFF)"
                                    :((addyi>>8)<<8)|((addyi+1)&0xFF); // Note JSR (ind) page boundry bug
  var isVolatileMem = dyn2 || (addyi>=0x9110 && addyi<0x9130);
	var isVolatileMemPossible = dyn2 || ((addyi+255)>=0x9110 && addyi<0x9130);
  

  var isImm0 = isInteger(imm) && imm==0;
  
	// ORA $zp
	var mem_zp_r = "m["+imm+"]";
	// ROR $zp
	var mem_zp_w = "if (write("+imm+",_value_)) { pc="+(offset+2)+"; return; }";

	// ORA $zp,x
	var mem_zpx_r = isImm0?"m[x]":"m[("+imm+"+x)&255]";
	// ROR $zp,x
	var mem_zpx_w = isImm0?"if (write(x,_value_)) { pc="+(offset+2)+"; return; }"
                        :"if (write(("+imm+"+x)&255,_value_)) { pc="+(offset+2)+"; return; }";
  
	// ORA $zp,y
	var mem_zpy_r = isImm0?"m[y]":"m[("+imm+"+y)&255]";
	// ROR $zp,y
	var mem_zpy_w = isImm0?"if (write(y,_value_)) { pc="+(offset+1)+"; return; }"
                        :"if (write(("+imm+"+y)&255,_value_)) { pc="+(offset+2)+"; return; }";

	// ORA $abs
	var mem_abs_r = isVolatileMem?"read("+addy+")":"m["+addy+"]";
	
	var mem_abs_r_plus_1 = isVolatileMem?"read("+addyPlus1Overflow+")":"m["+addyPlus1Overflow+"]";
	// ROR $abs
	var mem_abs_w = "if (write("+addy+",_value_)) { pc="+(offset+3)+"; return; }";
	var memi_abs_r = "("+mem_abs_r+"|("+mem_abs_r_plus_1+"<<8))";

	// ORA $abs,x
	var mem_absx_r = isVolatileMemPossible?"read("+addy+"+x)":"m["+addy+"+x]";
	// ROR $abs,x
	var mem_absx_w = "if (write("+addy+"+x,_value_)) { pc="+(offset+3)+"; return; }";

	// ORA $abs,y
	var mem_absy_r = isVolatileMemPossible?"read("+addy+"+y)":"m["+addy+"+y]";
	// ROR $abs,y
	var mem_absy_w = "if (write("+addy+"+y,_value_)) { pc="+(offset+3)+"; return; }";

	// ($zp)
	var mem_os_zp = isImm0?"(m[0]|(m[1]<<8))":"(m["+imm+"]|(m["+zp_plus_1+"]<<8))";
	
	var os_zp_y = mem_os_zp+"+y";
	// ORA ($zp),y
	var mem_os_zp_y_r = isVolatileMemPossible?"read("+os_zp_y+")":"m["+os_zp_y+"]";
	// ROR ($zp),y
	var mem_os_zp_y_w = "if (write("+os_zp_y+",_value_)) { pc="+(offset+2)+"; return; }";
	
	var os_zpx = isImm0?"(m[x]|(m[(x+1)&255]<<8))":"(m[("+imm+"+x)&255]|(m[("+imm_plus_1+"+x)&255]<<8))";
	// ORA ($zp,x)
	var mem_os_zpx_r = isVolatileMemPossible?"read("+os_zpx+")":"m["+os_zpx+"]";
	// ROR ($zp,x)
	var mem_os_zpx_w = "if (write("+os_zpx+",_value_)) { pc="+(offset+2)+"; return; }"; 
	
	var result = "halt("+offset+");";
	pcp = 1, cyc=1;

	switch(inst) {
		// BRK
		case 0x00: result="/*BRK*/"+rp_push((offset+1)>>8)+rp_push((offset+1)&255)+rp_push("p|"+B)
        +"p|="+I+";pc=m["+IRQ_VECTOR+"]|(m["+(IRQ_VECTOR+1)+"]<<8);"; cyc=7; pcp=2; break;
		// JSR abs
		case 0x20: result="/*JSR abs*/"+rp_push((offset+2)>>8)+rp_push((offset+2)&255)+"pc="+addy+";";
          cyc=6; pcp=3;
          break;
		// RTI
		case 0x40: result="/*RTI*/"+"p="+st_pop+"|"+R+";pc="+st_pop+"|("+st_pop+"<<8);"; cyc=6; pcp=1; break;
		// RTS
		case 0x60: result="/*RTS*/"+"pc=("+st_pop+"|("+st_pop+"<<8))+1;"; cyc=6; pcp=1; break;
		// LDY #
		case 0xA0: {
			if (isInteger(imm)) {
        if (imm==0) {
  				result="y=0;p=p&"+(~N&255)+"|"+Z+";";
  			}
  			else if(imm>127) {
  				result="y="+imm+";p=p&"+(~Z&255)+"|"+N+";";
  			}
  			else {
  				result="y="+imm+";p&="+(~(Z|N)&255)+";";
  			}
  			result = "/*LDY #imm*/"+result+"/*NZY*/";
  		}
  		else {
        result="/*LDY #imm*/y="+imm+";NZY";
			}
			cyc=2; pcp=2;
		}
		break;
		// CPY #
		case 0xC0: result="/*CPY #*/"+rp_nzc("y",imm)+";"; cyc=2; pcp=2; break;
		// CPX #
		case 0xE0: result="/*CPX #*/"+rp_nzc("x",imm)+";"; cyc=2; pcp=2; break;

		// LDX #
		case 0xA2:  {
		  if (isInteger(imm)) {
      	if (imm==0) {
  				result="x=0;p=p&"+(~N&255)+"|"+Z+";";
  			}
  			else if(imm>127) {
  				result="x="+imm+";p=p&"+(~Z&255)+"|"+N+";";
  			}
  			else {
  				result="x="+imm+";p&="+(~(Z|N)&255)+";";
  			}
  			result = "/*LDX #imm*/"+result+"/*NZX*/";
  		}
  		else {
  		  result="/*LDX #imm*/x="+imm+";NZX";
      }
			cyc=2; pcp=2;
		}
		break;
		// BIT zpg 
		case 0x24: result="/*BIT zpg*/"+rp_bit(mem_zp_r)+";"; cyc=3; pcp=2; break;
		// STY zpg
		case 0x84: result="/*STY zpg*/"+rp(mem_zp_w,"y"); cyc=3; pcp=2; break;
		// STY zpg,x
		case 0x94: result="/*STY zpg,x*/"+rp(mem_zpx_w,"y"); cyc=4; pcp=2; break;
		// LDY zpg
		case 0xA4: result="/*LDY zpg*/"+"y="+mem_zp_r+";"+nz_y; cyc=3; pcp=2; break;
		// LDY zp,x
		case 0xB4: result="/*LDY zp,x*/"+"y="+mem_zpx_r+";"+nz_y; cyc=4; pcp=2; break;
		// CPY zp
		case 0xC4: result="/*CPY zp*/"+rp_nzc("y",mem_zp_r)+";"; cyc=3; pcp=2; break;
		// CPX zp
		case 0xE4: result="/*CPX zp*/"+rp_nzc("x",mem_zp_r)+";"; cyc=3; pcp=2; break;

		// ORA (zp,x)
		case 0x01: result="/*ORA (zp,x)*/"+"a|="+mem_os_zpx_r+";"+nz_a; cyc=6; pcp=2; break;
		// AND (zp,x)
		case 0x21: result="/*AND (zp,x)*/"+"a&="+mem_os_zpx_r+";"+nz_a; cyc=6; pcp=2; break;
		// EOR (zp,x)
		case 0x41: result="/*EOR (zp,x)*/"+"a^="+mem_os_zpx_r+";"+nz_a; cyc=6; pcp=2; break;
		// ADC (zp,x)
		case 0x61: result="/*ADC (zp,x)*/"+"adc("+mem_os_zpx_r+");/*NZA*/"; cyc=6; pcp=2; break;
		// STA (zp,x)
		case 0x81: result="/*STA (zp,x)*/"+rp(mem_os_zpx_w,"a"); cyc=6; pcp=2; break;
		// LDA (zp,x)
		case 0xA1: result="/*LDA (zp,x)*/"+"a="+mem_os_zpx_r+";"+nz_a; cyc=6; pcp=2; break;
		// CMP (zp,x)
		case 0xC1: result="/*CMP (zp,x)*/"+rp_nzc("a",mem_os_zpx_r)+";"; cyc=6; pcp=2; break;
		// SBC (zp,x)
		case 0xE1: result="/*SBC (zp,x)*/"+"sbc("+mem_os_zpx_r+");/*NZA*/"; cyc=6; pcp=2; break;
		
		// ORA zp
		case 0x05: result="/*ORA zp*/"+"a|="+mem_zp_r+";"+nz_a; cyc=3; pcp=2; break;
		// AND zp
		case 0x25: result="/*AND zp*/"+"a&="+mem_zp_r+";"+nz_a; cyc=3; pcp=2; break;
		// EOR zp
		case 0x45: result="/*EOR zp*/"+"a^="+mem_zp_r+";"+nz_a; cyc=3; pcp=2; break;
		// ADC zp
		case 0x65: result="/*ADC zp*/"+"adc("+mem_zp_r+");/*NZA*/"; cyc=3; pcp=2; break;
		// STA zp
		case 0x85: result="/*STA zp*/"+rp(mem_zp_w,"a"); cyc=3; pcp=2; break;
		// LDA zp
		case 0xA5: result="/*LDA zp*/"+"a="+mem_zp_r+";"+nz_a; cyc=3; pcp=2; break;
		// CMP zp
		case 0xC5: result="/*CMP zp*/"+rp_nzc("a",mem_zp_r)+";"; cyc=3; pcp=2; break;
		// SBC zp
		case 0xE5: result="/*SBC zp*/"+"sbc("+mem_zp_r+");/*NZA*/"; cyc=3; pcp=2; break;

		// ASL zp 
		case 0x06: result="/*ASL zp*/"+rp(mem_zp_w,rp_asl(mem_zp_r)); cyc=5; pcp=2; break;
		// ASL zp,x 
		case 0x16: result="/*ASL zp,x*/"+rp(mem_zpx_w,rp_asl(mem_zpx_r)); cyc=5; pcp=2; break;
		// ROL zp 
		case 0x26: result="/*ROL zp*/"+rp(mem_zp_w,rp_rol(mem_zp_r)); cyc=5; pcp=2; break;
		// ROL zp,x 
		case 0x36: result="/*ROL zp,x*/"+rp(mem_zpx_w,rp_rol(mem_zpx_r)); cyc=5; pcp=2; break;
		// LSR zp 
		case 0x46: result="/*LSR zp*/"+rp(mem_zp_w,rp_lsr(mem_zp_r)); cyc=5; pcp=2; break;
		// LSR zp,x 
		case 0x56: result="/*LSR zp,x*/"+rp(mem_zpx_w,rp_lsr(mem_zpx_r)); cyc=5; pcp=2; break;
		// ROR zp
		case 0x66: result="/*ROR zp*/"+rp(mem_zp_w,rp_ror(mem_zp_r)); cyc=5; pcp=2; break;
		// ROR zp,x 
		case 0x76: result="/*ROR zp,x*/"+rp(mem_zpx_w,rp_ror(mem_zpx_r)); cyc=5; pcp=2; break;
		// STX zpg
		case 0x86: result="/*STX zp*/"+rp(mem_zp_w,"x"); cyc=3; pcp=2; break;
		// STX zpg,y
		case 0x96: result="/*STX zp,x*/"+rp(mem_zpy_w,"x"); cyc=4; pcp=2; break;
		// LDX zpg
		case 0xA6: result="/*LDX zp*/"+"x="+mem_zp_r+";"+nz_x; cyc=3; pcp=2; break;		
		// LDX zpg,y
		case 0xB6: result="/*LDX zp,x*/"+"x="+mem_zpy_r+";"+nz_x; cyc=4; pcp=2; break;
		// DEC zpg
		case 0xC6: result="/*DEC zp*/"+rp(mem_zp_w,"b=("+mem_zp_r+"-1)&255")+nz_b; cyc=5; pcp=2; break;
		// DEC zpg,x
		case 0xD6: result="/*DEC zp,x*/"+rp(mem_zpx_w,"b=("+mem_zpx_r+"-1)&255")+nz_b; cyc=5; pcp=2; break;
		// INC zpg
		case 0xE6: result="/*INC zp*/"+rp(mem_zp_w,"b=("+mem_zp_r+"+1)&255")+nz_b; cyc=5; pcp=2; break;
		// INC zpg,x
		case 0xF6: result="/*INC zp,x*/"+rp(mem_zpx_w,"b=("+mem_zpx_r+"+1)&255")+nz_b; cyc=5; pcp=2; break;
		
		// PHP
		case 0x08: result="/*PHP*/"+rp_push("p"); cyc=3; pcp=1; break;
		// CLC
		case 0x18: result="/*CLC*/"+"p&="+(~C&255)+";"; cyc=2; pcp=1;  break;
		// PLP
		case 0x28: result="/*PLP*/"+"p="+st_pop+"|"+R+";/*NZA*/"; cyc=4; pcp=1;  break;
		// SEC
		case 0x38: result="/*SEC*/"+"p|="+C+";"; cyc=2; pcp=1; break;
		// PHA
		case 0x48: result="/*PHA*/"+rp_push("a"); cyc=3; pcp=1; break;
		// CLI
		case 0x58: result="/*CLI*/"+"p&="+(~I&255)+";"; cyc=2; pcp=1;  break;
		// PLA
		case 0x68: result="/*PLA*/"+"a="+st_pop+";"+nz_a; cyc=4; pcp=1; break;
		// SEI
		case 0x78: result="/*SEI*/"+"p|="+I+";"; cyc=2; pcp=1;  break;
		// DEY
		case 0x88: result="/*DEY*/"+"y=(y-1)&255;"+nz_y; cyc=2; pcp=1; break;
		// TYA
		case 0x98: result="/*TYA*/"+"a=y;"+nz_a; cyc=2; pcp=1; break;
		// TAY
		case 0xA8: result="/*TAY*/"+"y=a;"+nz_y; cyc=2; pcp=1; break;
		// CLV
		case 0xB8: result="/*CLV*/"+"p&="+(~V&255)+";"; cyc=2; pcp=1;  break;
		// INY
		case 0xC8: result="/*INY*/"+"y=(y+1)&255;"+nz_y; cyc=2; pcp=1; break;
		// CLD
		case 0xD8: result="/*CLD*/"+"p&="+(~D&255)+";"; cyc=2; pcp=1;  break;
		// INX
		case 0xE8: result="/*INX*/"+"x=(x+1)&255;"+nz_x; cyc=2; pcp=1; break;
		// SED
		case 0xF8: result="/*SED*/"+"p|="+D+";"; cyc=2; pcp=1;  break;

		// ORA #imm
		case 0x09: 
      if (isInteger(imm)) {
        if (imm==0) {
          result=nz_a;
        }
        else if(imm<128) {
          result="a|="+imm+";"+nz_a;
        }
        else {
          result="a|="+imm+";p=p&"+(~Z&255)+"|"+N+";"+"/*NZA*/";
        }
        result = "/*ORA #imm*/"+result;
      }
      else {
			 result="/*ORA #imm*/a|="+imm+";NZA";
			}
			cyc=2; pcp=2;
      break;
		// AND #imm
		case 0x29:
		  if (isInteger(imm)) {
		    if (imm==0) {
          result="a=0;p=p&"+(~N&255)+"|Z;"+"/*NZA*/";
        }
        else if(imm<128) {
        result="a&="+imm+";p=p&"+(~(N|Z)&255)+"|(a?0:"+Z+");"+"/*NZA*/";
        }
        else {
          result="a&="+imm+";"+nz_a;
        }
        result = "/*AND #imm*/"+result;
      }
      else {
        result="/*AND #imm*/a&="+imm+";NZA";
      }
			cyc=2; pcp=2;
      break;
		// EOR #imm
		case 0x49: result="/*EOR #imm*/"+(isImm0?"":"a^="+imm+";")+nz_a; cyc=2; pcp=2; break;
		// ADC #imm
		case 0x69: result="/*ADC #imm*/"+"adc("+imm+");/*NZA*/"; cyc=2; pcp=2; break;
		// NOP #imm
		case 0x89: result="/*NOP #imm*/"; cyc=2; pcp=2; break;
		// LDA #imm
		case 0xA9: {
		  if (isInteger(imm)) {
        if (imm==0) {
          result="a=0;p=p&"+(~N&255)+"|"+Z+";";
        }
        else if(imm>127) {
          result="a="+imm+";p=p&"+(~Z&255)+"|"+N+";";
        }
        else {
          result="a="+imm+";p&="+(~(Z|N)&255)+";";
        }
		  	result = "/*LDA #imm*/"+result+"/*NZA*/";
		  }
		  else {
        result="/*LDA #imm*/a="+imm+";"+nz_a;
      }
			cyc=2; pcp=2;
		}
		break;
		// CMP #imm
		case 0xC9: result="/*CMP #imm*/"+rp_nzc("a",imm)+";"; cyc=2; pcp=2; break;
		
		// SBC #imm
		case 0xEB:
		case 0xE9: result="/*SBC #imm*/"+"sbc("+imm+");/*NZA*/"; cyc=2; pcp=2; break;

		// ASL A         
		case 0x0A: result="/*ASL A*/"+"a="+rp_asl("a")+";"; cyc=2; pcp=1;  break;
		// NOP
		case 0x1A:
		case 0x3A:
		case 0x5A:
		case 0x7A:
		case 0xDA:
		case 0xEA:
		case 0xFA: result="/*NOP*/"; cyc=2; pcp=1; break;
		// ROL A
		case 0x2A: result="/*ROL A*/"+"a="+rp_rol("a")+";"; cyc=2; pcp=1;  break;
		// LSR A
		case 0x4A: result="/*LSR A*/"+"a="+rp_lsr("a")+";"; cyc=2; pcp=1;  break;
		// ROR A
		case 0x6A: result="/*ROR A*/"+"a="+rp_ror("a")+";"; cyc=2; pcp=1;  break;
		// TXA
		case 0x8A: result="/*TXA*/"+"a=x;"+nz_a; cyc=2; pcp=1; break;
		// TXS
		case 0x9A: result="/*TXS*/"+"sp=x;"; cyc=2; pcp=1; break;
		// TAX
		case 0xAA: result="/*TAX*/"+"x=a;"+nz_x; cyc=2; pcp=1; break;
		// TSX
		case 0xBA: result="/*TSX*/"+"x=sp;"+nz_x; cyc=2; pcp=1; break;
		// DEX
		case 0xCA: result="/*DEX*/"+"x=(x-1)&255;"+nz_x; cyc=2; pcp=1; break;

		// BIT abs
		case 0x2C: result="/*BIT abs*/"+rp_bit(mem_abs_r)+";"; cyc=4; pcp=3; break;
		// JMP abs
		case 0x4C: result="/*JMP abs*/"+"pc="+addy+";"; cyc=3; pcp=3; break;
		// JMP (abs)
		case 0x6C: result="/*JMP (abs)*/"+"pc="+memi_abs_r+";"; cyc=5; pcp=3; break;
		// STY abs
		case 0x8C: result="/*STY abs*/"+rp(mem_abs_w,"y"); cyc=4; pcp=3; break;
		// LDY abs
		case 0xAC: result="/*LDY abs*/"+"y="+mem_abs_r+";"+nz_y; cyc=4; pcp=3; break;
		// LDY abs,x
		case 0xBC: result="/*LDY abs,x*/"+"y="+mem_absx_r+";"+nz_y; cyc=4; pcp=3; break;
		// CPY abs
		case 0xCC: result="/*CPY abs*/"+rp_nzc("y",mem_abs_r)+";"; cyc=4; pcp=3; break;
		// CPX abs
		case 0xEC: result="/*CPX abs*/"+rp_nzc("x",mem_abs_r)+";"; cyc=4; pcp=3; break;

		// ORA $abs
		case 0x0D: result="/*ORA abs*/"+"a|="+mem_abs_r+";"+nz_a; cyc=4; pcp=3; break;
		// AND $abs
		case 0x2D: result="/*AND abs*/"+"a&="+mem_abs_r+";"+nz_a; cyc=4; pcp=3; break;
		// EOR $abs
		case 0x4D: result="/*EOR abs*/"+"a^="+mem_abs_r+";"+nz_a; cyc=4; pcp=3; break;
		// ADC $abs
		case 0x6D: result="/*ADC abs*/"+"adc("+mem_abs_r+");/*NZA*/"; cyc=4; pcp=3; break;
		// STA $abs
		case 0x8D: result="/*STA abs*/"+rp(mem_abs_w,"a")+";"; cyc=4; pcp=3; break;
		// LDA $abs
		case 0xAD: result="/*LDA abs*/"+"a="+mem_abs_r+";"+nz_a; cyc=4; pcp=3; break;
		// CMP $abs
		case 0xCD: result="/*CMP abs*/"+rp_nzc("a",mem_abs_r)+";"; cyc=4; pcp=3; break;
		// SBC $abs
		case 0xED: result="/*SBC abs*/"+"sbc("+mem_abs_r+");/*NZA*/"; cyc=4; pcp=3; break;

		// ASL abs
		case 0x0E: result="/*ASL abs*/"+rp(mem_abs_w,rp_asl(mem_abs_r))+nz_b; cyc=6; pcp=3; break;
		// ASL a,x
		case 0x1E: result="/*ASL abs,x*/"+rp(mem_absx_w,rp_asl(mem_absx_r))+nz_b; cyc=7; pcp=3; break;
		// ROL a
		case 0x2E: result="/*ROL abs*/"+rp(mem_abs_w,rp_rol(mem_abs_r))+nz_b; cyc=6; pcp=3; break;
		// ROL a,x
		case 0x3E: result="/*ROL abs,x*/"+rp(mem_absx_w,rp_rol(mem_absx_r))+nz_b; cyc=7; pcp=3; break;
		// LSR a
		case 0x4E: result="/*LSR abs*/"+rp(mem_abs_w,rp_lsr(mem_abs_r))+nz_b; cyc=6; pcp=3; break;
		// LSR a,x
		case 0x5E: result="/*LSR abs,x*/"+rp(mem_absx_w,rp_lsr(mem_absx_r))+nz_b; cyc=7; pcp=3; break;
		// ROR a
		case 0x6E: result="/*ROR abs*/"+rp(mem_abs_w,rp_ror(mem_abs_r))+nz_b; cyc=6; pcp=3; break;
		// ROR a,x
		case 0x7E: result="/*ROR abs,x*/"+rp(mem_absx_w,rp_ror(mem_absx_r))+nz_b; cyc=7; pcp=3; break;
		// STX $abs
		case 0x8E: result="/*STX abs*/"+rp(mem_abs_w,"x"); cyc=4; pcp=3; break;
		// 9E = SHX
		// LDX $abs
		case 0xAE: result="/*LDX abs*/"+"x="+mem_abs_r+";"+nz_x; cyc=4; pcp=3; break;
		// LDX $abs,y
		case 0xBE: result="/*LDX abs,y*/"+"x="+mem_absy_r+";"+nz_x; cyc=4; pcp=3; break;
		// DEC $abs
		case 0xCE: result="/*DEC abs*/"+"b=("+mem_abs_r+"-1)&255;"+rp(mem_abs_w,"b")+nz_b; cyc=4; pcp=3; break;
		// DEC $abs,x
		case 0xDE: result="/*DEC abs,x*/"+"b=("+mem_absx_r+"-1)&255;"+rp(mem_absx_w,"b")+nz_b; cyc=7; pcp=3; break;
		// INC $abs
		case 0xEE: result="/*INC abs*/"+"b=("+mem_abs_r+"+1)&255;"+rp(mem_abs_w,"b")+nz_b; cyc=4; pcp=3; break;
		// INC $abs,x
		case 0xFE: result="/*INC abs,x*/"+"b=("+mem_absx_r+"+1)&255;"+rp(mem_absx_w,"b")+nz_b; cyc=7; pcp=3; break;

		// BPL rel 
		case 0x10: result="/*BPL rel*/"+rp_bra(~N,imm,offset); cyc=3; pcp=2; break;
		// BMI rel
		case 0x30: result="/*BMI rel*/"+rp_bra(N,imm,offset); cyc=3; pcp=2; break;
		// BVC rel
		case 0x50: result="/*BVC rel*/"+rp_bra(~V,imm,offset); cyc=3; pcp=2; break;
		// BVS rel
		case 0x70: result="/*BVS rel*/"+rp_bra(V,imm,offset); cyc=3; pcp=2; break;
		// BCC rel
		case 0x90: result="/*BCC rel*/"+rp_bra(~C,imm,offset); cyc=3; pcp=2; break;
		// BCS rel
		case 0xB0: result="/*BCS rel*/"+rp_bra(C,imm,offset); cyc=3; pcp=2; break;
		// BNE rel
		case 0xD0: result="/*BNE rel*/"+rp_bra(~Z,imm,offset); cyc=3; pcp=2; break;
		// BEQ rel
		case 0xF0: result="/*BEQ rel*/"+rp_bra(Z,imm,offset); cyc=3; pcp=2; break;

		// ORA (zp),y
		case 0x11: result="/*ORA (zp),y*/"+"a|="+mem_os_zp_y_r+";"+nz_a; cyc=3; pcp=2; break;
		// AND (zp),y
		case 0x31: result="/*AND (zp),y*/"+"a&="+mem_os_zp_y_r+";"+nz_a; cyc=3; pcp=2; break;
		// EOR (zp),y
		case 0x51: result="/*EOR (zp),y*/"+"a^="+mem_os_zp_y_r+";"+nz_a; cyc=3; pcp=2; break;
		// ADC (zp),y
		case 0x71: result="/*ADC (zp),y*/"+"adc("+mem_os_zp_y_r+");/*NZA*/"; cyc=3; pcp=2; break;
		// STA (zp),y
		case 0x91: result="/*STA (zp),y*/"+rp(mem_os_zp_y_w,"a"); cyc=3; pcp=2; break;
		// LDA (zp),y
		case 0xB1: result="/*LDA (zp),y*/"+"a="+mem_os_zp_y_r+";"+nz_a; cyc=3; pcp=2; break;
		// CMP (zp),y
		case 0xD1: result="/*CMP (zp),y*/"+rp_nzc("a",mem_os_zp_y_r)+";"; cyc=3; pcp=2; break;
		// SBC (zp),y
		case 0xF1: result="/*SBC (zp),y*/"+"sbc("+mem_os_zp_y_r+");/*NZA*/"; cyc=3; pcp=2; break;

		// ORA zp,x
		case 0x15: result="/*ORA zp,x*/"+"a|="+mem_zpx_r+";"+nz_a; cyc=4; pcp=2; break;
		// AND zp,x
		case 0x35: result="/*AND zp,x*/"+"a&="+mem_zpx_r+";"+nz_a; cyc=4; pcp=2; break;
		// EOR zp,x
		case 0x55: result="/*EOR zp,x*/"+"a^="+mem_zpx_r+";"+nz_a; cyc=4; pcp=2; break;
		// ADC zp,x
		case 0x75: result="/*ADC zp,x*/"+"adc("+mem_zpx_r+");/*NZA*/"; cyc=4; pcp=2; break;
		// STA zp,x
		case 0x95: result="/*STA zp,x*/"+rp(mem_zpx_w,"a"); cyc=4; pcp=2; break;
		// LDA zp,x
		case 0xB5: result="/*LDA zp,x*/"+"a="+mem_zpx_r+";"+nz_a; cyc=4; pcp=2; break;
		// CMP zp,x
		case 0xD5: result="/*CMP zp,x*/"+rp_nzc("a",mem_zpx_r)+";"; cyc=4; pcp=2; break;
		// SBC zp,x
		case 0xF5: result="/*ADC zp,x*/"+"sbc("+mem_zpx_r+");/*NZA*/"; cyc=4; pcp=2; break;

		// ORA abs,y
		case 0x19: result="/*ORA abs,y*/"+"a|="+mem_absy_r+";"+nz_a; cyc=4; pcp=3; break;
		// AND abs,y
		case 0x39: result="/*AND abs,y*/"+"a&="+mem_absy_r+";"+nz_a; cyc=4; pcp=3; break;
		// EOR abs,y
		case 0x59: result="/*EOR abs,y*/"+"a^="+mem_absy_r+";"+nz_a; cyc=4; pcp=3; break;
		// ADC abs,y
		case 0x79: result="/*ADC abs,y*/"+"adc("+mem_absy_r+");/*NZA*/"; cyc=4; pcp=3; break;
		// STA abs,y
		case 0x99: result="/*STA abs,y*/"+rp(mem_absy_w,"a"); cyc=4; pcp=3;  break;
		// LDA abs,y
		case 0xB9: result="/*LDA abs,y*/"+"a="+mem_absy_r+";"+nz_a; cyc=4; pcp=3; break;
		// CMP abs,y
		case 0xD9: result="/*CMP abs,y*/"+rp_nzc("a",mem_absy_r)+";"; cyc=4; pcp=3; break;
		// SBC abs,y
		case 0xF9: result="/*SBC abs,y*/"+"sbc("+mem_absy_r+");/*NZA*/"; cyc=4; pcp=3;  break;

		// ORA abs,x
		case 0x1D: result="/*ORA abs,x*/"+"a|="+mem_absx_r+";"+nz_a; cyc=4; pcp=3; break;
		// AND abs,x
		case 0x3D: result="/*AND abs,x*/"+"a&="+mem_absx_r+";"+nz_a; cyc=4; pcp=3; break;
		// EOR abs,x
		case 0x5D: result="/*EOR abs,x*/"+"a^="+mem_absx_r+";"+nz_a; cyc=4; pcp=3; break;
		// ADC abs,x
		case 0x7D: result="/*ADC abs,x*/"+"adc("+mem_absx_r+");/*NZA*/"; cyc=4; pcp=3; break;
		// STA abs,x
		case 0x9D: result="/*STA abs,x*/"+rp(mem_absx_w,"a"); cyc=4; pcp=3; break;
		// LDA abs,x
		case 0xBD: result="/*LDA abs,x*/"+"a="+mem_absx_r+";"+nz_a; cyc=4; pcp=3; break;
		// CMP abs,x
		case 0xDD: result="/*CMP abs,x*/"+rp_nzc("a",mem_absx_r)+";"; cyc=4; pcp=3; break;
		// SBC abs,x
		case 0xFD: result="/*SBC abs,x*/"+"sbc("+mem_absx_r+");/*NZA*/"; cyc=4; pcp=3; break;
	};

	return result;
}

/**
 * Length of instructions.
 * Used by dynamic code detection routine.  
 */ 
var instsize = [
  2,2,1,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3,
  3,2,1,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3,
  1,2,1,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3,
  1,2,1,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3,
  2,2,2,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,3,2,2,2,2,1,3,1,3,3,3,3,3,
  2,2,2,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3,
  2,2,2,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3,
  2,2,2,2,2,2,2,2,1,2,1,2,3,3,3,3,
  2,2,1,2,2,2,2,2,1,3,1,3,3,3,3,3
];

/**
 * Main memory, peripheral memory (shared).
 */ 
var m = new Array(65536);

/**
 * Compiled code array.
 */ 
var compiled = new Array(65536);

/**
 * Array used to handle dynamic code.
 * The value inside the array represents how many previous
 * memory locations must be cleared if this memory location is cleared.
 */ 
var coderange = new Array(65536);

var modCount = new Array(8192);

/**
 * 1 if optimizations are to be applied such as:
 * - delay loop removal
 * - multiple logic shift grouping
 * - removing unused flag settings    
 */
var isOptimising = 1;

/**
 * This is the default handler for code locations not compiled yet.
 */ 
function uncompiledCodeHandler(offset,setMaxPc) {
  if (!offset) offset=pc;
  
  // pcNext will walk through code from pc.     
	var pcNext = offset;
	
	// Used to fill coderange table with correct range to code block start. 
	var range=0;
	
	// Count of cycles in this code block.
	var cyct=0;
	
	// True if the last instruction in the code block modifys the pc, else 0.
  var lastWasPcModifyingInstruction = 0;
	
	// Compiled code to return
	var compiledCode="";
	
	// If maxPc is about to be passed then a new code block is created.
  var maxPc = setMaxPc?setMaxPc:0x10000;

	
	// String to replace useless NZ flag setting tags with.
  var repstr = "";

	// Little optimisation hack for code that uses decrement branch loops for delays.
	if (isOptimising) {
		// This instruction
		var inst = m[pcNext];
		// The next instruction, if inst was 8 bits
		var nextInst = m[pcNext+1];
		// The relative offset if next isInst is a branch
		var rel = m[pcNext+2];

		if (nextInst==0xD0 && rel==(-3+256)) {
			if (inst==0x88) { // DEY
	      // // Reset y to minimum so only one loop is performed. 
				compiledCode += "/* Wait Loop using Y Optimized *"+"/oy=y;y=1;";
				cyct = "(oy + oy<<2)+"; // 5 is the number of cycles it takes to do a decrement, branch
				loopsOptimizedCount++;
			}
	    else if (inst==0xCA) { // DEX
	      // Reset x to minimum so only one loop is performed.
				compiledCode += "/* Wait Loop using X Optimized *"+"/ox=x;x=1;";
				cyct = "(ox + ox<<2)+"; // 5 is the number of cycles it takes to do a decrement, branch
				loopsOptimizedCount++;
			}
		}
		// SBC #1
		else if ((inst==0xEB || inst==0xE9) && nextInst==1 ) {
			nextInst = m[pcNext+2];
			// The relative offset if next isInst is a branch
			var rel = m[pcNext+3];
			
			if (nextInst==0xD0 && rel==(-4+256)) {
				// Reset a to minimum so only one loop is performed.
				compiledCode += "/* Wait Loop using A Optimized *"+"/oa=a;a=1;";
				cyct = "(oa + oa<<2)+"; // 5 is the number of cycles it takes to do a sbc #1, branch
				loopsOptimizedCount++;
			}
		}
	}

  // Convert multiple instructions to a javascript code block
	do {

    // This instruction
		var inst = m[pcNext];
		// It's immediate/zp/pc.l value
		var imm = m[pcNext+1];
		// It's full address if an absolute instruction
		var addy = imm | (m[pcNext+2]<<8);
		// True if you should use read() instead of m[] to read the value.
		var isVolatileMemPossible = (addy+255)>=0x9110 && addy<0x9130;
		
		// If this instruction is a load/store from a peripheral then update the Vias first.
		var ia15 = inst&15;
		// All absolute load/store operations
		var isLoadStoreOperation = (ia15==0x1||ia15==0x3||(ia15==0x9&&((inst>>4)&1)==1)||(ia15==0xB && ((inst>>4)&1)==1)||ia15>=0xC)
		// true if via must be called before instruction 
		var isAddVia = isLoadStoreOperation && isVolatileMemPossible;
	
    var nextInstCompiled = "";


		if (isOptimising) {
			// LSR A multiple test

      var pcTest = pcNext;
      var count=0;
      while(m[pcTest++]==0x4a) count++;
      if (isOptimising && count>1) {
        nextInstCompiled = "/* LSR"+count+" */ a="+rp_lsr_multiple("a",count)+";";
        cyc = count<<1;
        lsrsOptimizedCount += (pcp = count); 
      }

			// ASL A multiple test
			if (count==0) {			
				pcTest = pcNext;
	      while(m[pcTest++]==0x0a) count++;
	      if (isOptimising && count>1) {
	        nextInstCompiled = "/* ASL"+count+" *"+"/ a="+rp_asl_multiple("a",count)+";";
	        cyc = count<<1;
	        aslsOptimizedCount += (pcp = count); 
	      }
			}
    }
    
    // If instruction hasn't already been created by optimizer then do a normal compile
    if (nextInstCompiled=="") {
      nextInstCompiled = compileInstruction(pcNext);
    }

    // Update total cycle count.
    cyct += cyc;
    
    // Add the via call if need be
		if (isAddVia) {
      // Call via and update global cycle count
      compiledCode+="Via1clock("+cyct+");"+((cyct==0)?"":"tcyc+="+cyct+";");
      // Reset total cycle count.
      cyct=0;
    }

		// Generate the code
		compiledCode += nextInstCompiled;

		// Update the code range array from pCnext to pcNext + instruction size
		coderange[pcNext] = max(coderange[pcNext],range);
		range+=pcp;
    for(var jj=pcNext+1; jj<pcNext+pcp; jj++) {
			coderange[jj] = max(coderange[jj],-2); // -2 means this is an instruction immediate, -1 means this is a dynamic instruction immediate
		}

		// Update pcNext to point to next instruction
		pcNext += pcp;

    // Update debug value
    compiledInstructionsCount++;
    
    // True if last instruction modified the program counter.
		lastWasPcModifyingInstruction = (inst==0 || inst==0x20 || inst==0x40 || inst==0x4C || inst==0x6C || inst==0x60 || inst==0x10 || inst==0x30 || inst==0x50 || inst==0x70 || inst==0x90 || inst==0xB0 || inst==0xD0 || inst==0xF0);
	} while(pcNext<maxPc && !lastWasPcModifyingInstruction);//); // last inst is not a branch/jump/jsr/brk/rts

  // Optimise out unused flag setting code.
  // TODO handle flags optimization when there is a PHP
  if (isOptimising && compiledCode.indexOf("/*PHP*/")==-1) {
  	var idx = compiledCode.lastIndexOf("NZ");
  	if(idx!=-1) {
  		compiledCode = compiledCode.substring(0,idx).replace(/NZ./g,"")+compiledCode.substring(idx);
  	}
  	
    // Replace flag modification placeholders with real code.
  	if (compiledCode.indexOf("NZA")!=-1) compiledCode = compiledCode.replace(/NZA/g,"p=(a?(a&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");");
  	else if (compiledCode.indexOf("NZY")!=-1) compiledCode = compiledCode.replace(/NZY/g,"p=(y?(y&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");");
  	else if (compiledCode.indexOf("NZX")!=-1) compiledCode = compiledCode.replace(/NZX/g,"p=(x?(x&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");");
  	else if (compiledCode.indexOf("NZB")!=-1) compiledCode = compiledCode.replace(/NZB/g,"p=(b?(b&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");");
	}
	else {
    // Replace flag modification placeholders with real code.
  	compiledCode = compiledCode.replace(/NZA/g,"p=(a?(a&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");")
  	       .replace(/NZY/g,"p=(y?(y&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");")
  	       .replace(/NZX/g,"p=(x?(x&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");")
  	       .replace(/NZB/g,"p=(b?(b&"+N+"):"+Z+")|(p&"+(~(N|Z)&255)+");");
	}

  // Genereate javascript code to create handler function / if last instruction didn't modify pc, then pc needs to be set.
	var compiledFunction = "compiled["+offset+"] = function() { "
      +compiledCode
      +"cyc="+cyct+";"
      +((pcNext<maxPc || lastWasPcModifyingInstruction)?"":"pc="+pcNext)
      +"}";

  // Insert the compiled code block
	eval(compiledFunction);

	// Excecute the code block, if setMaxPc is set then this is a recompile from a write, so don't execute
	if (!setMaxPc) compiled[offset]();

  compiledSectionsCount++;
}

/**
 * Reset the 6502.
 */ 
function Cpu6502Reset() {
  Via1();
  
  // reset debug values.
  compiledSectionsCount = compiledInstructionsCount =
    loopsOptimizedCount = lsrsOptimizedCount = aslsOptimizedCount = 0;
  
  // Init registers
  pc = a = x = y = sp = 0;
  p = R;
  
  // Reset peripheral memory
  for(var i=0x9000; i<0x9130; i++) {
  	m[i]=0;
  }
  for(var i=0; i<14; i++) {
		m[0x9110+i]=0xFF;
		m[0x9120+i]=0xFF;
	}
  // Reset compiled code and code range arrays.
  for(var i=0; i<65536; i++) {
  	compiled[i]=uncompiledCodeHandler;
  	coderange[i]=-3;
  }
  
	for(var i=0; i<8192; i++) {
  	modCount[i]=i;
  }

  // Reload reset vector.
  pc = m[RESET_VECTOR] | (m[RESET_VECTOR+1]<<8);
}

/**
 * Init the 6502.
 */ 
function Cpu6502() {
  // Init ram
  for(var i=0; i<65536; i++) {
  	m[i]=0xCE;
  }
  
  Cpu6502Reset();
  
  // Load roms
  loadCart(chardata,0x8000,0x9000);
  loadCart(basicdata,0xc000,0xe000);
  loadCart(kerneldata,0xe000,0x10000);
  
  // Load reset address
  pc = m[RESET_VECTOR] | (m[RESET_VECTOR+1]<<8);
}



var chardata="cIiSWxEIeAAGkIkfCJkQAwnIiwjIiwHAcICQABkIcAAekIiIiQCeA4HQAhHQA5HA.BEQ4BEQABAHiAkTCJCHAIkQC5nQCJEAcgACIgACcAgDEQABEQEOAIERIBHSEJEAABEQABEQ.BgQmplWCJkQAIkYSpkRCJEAYQiQCJEJYAAfCJEfABEQAgBJCJkSkoBA8JkQ8hERCBAPCBEPCIEPA4DCIgACIgAACJkQCJkQ8AgQCJEJkgBGAIkQCplWmJEACJEJYQiQCBgIiICHIgACA4nAEgBIA5HA8ACIgACI8AADQABPQAnbAwDBEQABEwDAAgAHqgACIgAAAABI!BCEAAAAAAAAAAAAIgACIAAAIAAJkQCAAAAAAQCJ.RifkQCAI4BKcoAPIAAAiRGCQYiRAADSIBjSEpDAEgAEAAAAAAABIABEQgABAACEIgACQACAIoCH.whKIAAAIggPIgAAAAAAAAAAIgAEAAAA.BAAAAAAAAAAAgBGAAgAEgAEgAEA8IkRaJmQ8AACYgCCIggPAwjQCwAMA5HA8IkAcIgQ8AABMQBJ.RABA4HQ4RgAEhDAcACQ8JkQ8AgfCRACQABEAwjQCxjQCxDA8IkQ.IAB4AAAAgAAAgAAAAAAIAAAIgAEOgBMgBDGOAAAA4HA.BAAAAHGMYADYAHA8IkAMABAQAAAAAAA!DAAAgAH.83fc4DAQABEQABEQABAAAw!AAAAAAAA!DAAAAAAA8PAAAAAAAAAAAAAA8PAAACIgACIgACIEQABEQABEQAAAAAAgDBCIgACIQwAAAAAIgACQAOAAAAgACIgACIg!DIQgABCEIQABIABIABIAB4!ACIgACIgA.fABEQABEQAAwjf.5nf8AAAAAAAAAw!AYzf!9nPcgAAABEQABEQABEAAAAADQACIEoQkgBGkIUgAwjQCJkQ8AACcoydqgACAIgACIgACIgAIwhP!5DHIAACIgAC!jACIAKUgCFoQBKUIgACIgACIgAAAEgPURBFA8!f!8xDHMQAAAAAAAAAAAA8wDP8wDP8wDAAAAw!!!!!!DAAAAAAAAAAAAAAAAAA!DIgACIgACIgqWlqVpaVqWVABEQABEQABAAAAAgqVpaV!7P!4DP4AD4ADMwADMwADgACIgwDIgACAAAAA8wDP8ACIgACPAAAAAAAAAA.IgACAAAAAAAA!!PAAAAAPgACIgACIgw!AAAAAAAAA8PCIgACIgAC4jACIAMwADMwADMwgDO4gDO4gD.BHcwBHcwBH8!!AAAAAAAA!!!!AAAAAAAAAAAAA8!!!HQABEQABEw!AAAAAAP8wD!DP8wDAAAAAgACIgA.AAAAwDP8wDAAAAA8wDP8P8wDPMe31m6sfH.!nvdvB2bv9.!gd39wd39g!Pe3!.7vdP.!Hud3d392H.fg!.7h!.bg!H4v!e4v!.7!j39vx2b3j!fv92bg92bv!P.93f!93P.!xv!.7v!uH!fv7e7j3ubv!!7v!.7v!G4!9mZpl2bv9.fvd2at52bv!f.292bvbf.!D2bvD.7v!.!5b3bv1ud5!PYv9O4t727!D37vD3fvD!fw3f!93f!9!3bv92bv9O8!92bvbv95n!fv92bplmZv!3bvbf.2927!d3d3jf!93!fg9v!5f!bg!P83f!93fP8!z!.7D!.jR.!w7v!.7v!w!!!9jX993f!9!!!7fD43v!!!!!!!!!!!!f!93f!!!f!!bv92!!!!!!!2bH42Bu92!ff4XPe9Df!!!35m3!e25.!z3e7z1ubx!v!9v!!!!!!!7f!7v!.97!!3vf!93!.3!ff1jH84Vf!!!f!9Bf!9!!!!!!!!!f!9v!!!!H4!!!!!!!!!!!!5n!!!9v!9v!9v!Pcv5Wan9O8!3f.13f!9B!!w92!8P!bg!Pcv9Pe!9O8!7P!6bH4.7!fg!e4.9v7x!P.3!OYv9O8!B27.3!.7v!!w927w927w!Pcv9Gc!7f8!!!!9!!!9!!!!!f!!!f!9vH!5P!5znH!!!!fg!H4!!!!jnPf.zf.j!Pcv9P!7!!.!!!!!!Dw!!!!9jHMgAOew!!.7v!.7v!.7!!!!A8!!!!!!!Dw!!!!!!!PA!!!!!!!!!!!!!!PA!!!3f!93f!93fv!.7v!.7v!.!!!!!!x73f!93f!.8!!!!f!93!.H!!!!!93f!93f!Bwf!.973vf!.7f!7f!7f!7fA83f!93f!9HA.7v!.7v!.!!wBGYgBO8!!!!!!!!!A8fyACIgBP.9!!7v!.7v!.7v!!!!!z!.3fvf9u95nvdv.9!w92bv9O8!3Pe1IW993!f!93f!93f!9f!4BDYwjf!!3f!93Dw93f!Xv.1rf96Xve!93f!93f!9!!v!Bv66r!PAACM4wjP!.!!!!!!!!!!!P8wDP8wDP8w!!!!!AAAAAAw!!!!!!!!!!!!!!!!!!Dwf!93f!93f!VlqVpaVqWlq.7v!.7v!.7!!!!!!VpaVqCQADcwDf8zf8zP!8zP!8z!93f!9wf!93!!!!!P8wDP83f!93D!!!!!!!!!!Hc!93!!!!!!!!DAA!!!!!D!93f!93f!9A8!!!!!!!!PA3f!93f!93fw93f!P!8zP!8zP!8xHf8xHf8xH4jP.4jP.4jPAA8!!!!!!!DAAA8!!!!!!!!!!!!PAAAg!.7v!.7v!A8!!!!!DP8wDwDP8w!!!!!!93f!9H8!!!!wDP8w!!!!!P8wDPAP8wDPHiokVMBiHAAAA4QAPEpDAABEXiJkYcBAAAwjQAJEPAIgA6YkQGpDAAAAPC5HQ8AADSABfQABEAAAA6YkR6IAPABEXiJkQCBACAgBCIgAHAQAAMQABEQEOABERIBFaEBAGIgACIgAHAAAA2lUSJlEAAAAXiJkQCBAAAwjQCJEPAAAAcJmYcBEQAAgOGZkOCIAAAwlYABEQAAAA.AEPCwHAQABfQAhEMAAAAIkQCZkOAAAACJkQkgBAAAQQJlUS2AAAAIEJYQiQAAAACJkR6IAPAAgfEgBI.BAPgACIgACPAwAEQwDEw5GA8QABEQAB8AAAIwhKIgACIAAAQAyfgABAAAAAAAAAAAACIgACAAACAQCJkAAAAAAAkQifk4HJkAACegCHKwDCAAgYkhAEmYEAwgESwoER6AABIABAAAAAAQACQABEIQAAgABCIgAEgAACqwhPcoCCAAACI4DCIAAAAAAAAAACIABAAAgfAAAAAAAAAAAAYgBAAIABIABIABAPCZkWiJEPAgAGogACI4DA8IkAMADQ.BAPCJAHCIEPAQADUQifEQAA.BEeEIAR4AAHgAEfCJEPA4nQEgAEQABA8IkQ8IkQ8AAPCJkPCQAOAAAAIAAAIAAAAAACAAACIAhDYADYwghDAAAA.BgfAAAAwhBDGwAGwBAPCJADQAAEAAAAAAw!AAAAYQiQ.JkQCBAfiICPiICfAwhIABEQiwBA4RiIiICJ4BgfABEeABkfA4HQAhHQABEAcICQOJkIcAgQCJkfCJkQAwBCIgACIwBAOQABEQAR4AgQEhEcIRkQAAEQABEQA5HACZmWaJkQCBgQiJlSGJkQAgBJCJkQkgBA8JkQ8BEQABAGkIkQKRiGAwnQCxHSEJEA8IEQ8IgQ8AgPIgACIgACAIkQCJkQCxDACJkQkQCGYAgQCJkWaZmQAIkQkgBJCJEAiIiIcgACIAgfCQAGgAkfAgACIgw!IgACgCFoQBKUgCFCIgACIgACIwMzzMDzMPzMMb2MZysZzkJAAAAAAAAAAAP8wDP8wDP8AAAAA8!!!!!!AAAAAAAAAAAAAAAAAAw!ACIgACIgACoqVpaVqWlqVFQABEQABEQAAAAAAoaVqWVmzYGzZOjZMPwADMwADMwAIgACI8ACIgAAAAAAP8wDPgACIgwDAAAAAAAAAgPCIgAAAAAAAAw!!DAAAAwDIgACIgACI8PAAAAAAAAA!jACIgACIgA.IgACADMwADMwADM4gDO4gDO4gfwBHcwBHcwB!!PAAAAAAAw!!!PAAAAAAAAAAAAA!!!!BIARIBFYABAAAAAAwDP8w!wDP8AAAAAAIgACIgPAAAA8wDP8AAAAAAP8wD!DP8wDj3dtpO73h!!!!f8.Dvbx!!7vj2ZvdO6!!!!w9.bvD!f!9Xcu9mbx!!!!D3bg!O8!z3.7D..7v!!!!Xcu5Wc!D!7vj2Zv927!3!!53f!9j!!.!P!.7v!uH!7v7e7rXu7!nf!93f!9j!!!!not2art!!!!j2Zv927!!!!w92bvD!!!!PandO6v!.!!FnbuF3f!!!!od.7v!.!!!H8vD3!g!!.7D..7tP!!!!fv92buF!!!!3bv9u95!!!!.art2m8!!!fvbf.29.!!!3bv5Wc!D!!!Bu!5fH4!D!93f!93D!!8v!.wv!Yk!P8.7v!.7P8!!f!4Vf!93f!!!!.3A.97!!!!!!!!!!!!3f!93!!!3!!2bv9!!!!!!v92Budgbv9!3H.1jX!w3!!!du59vndu!!8t3.ct7W8!7f!7!!!!!!!.3!.7vf!.!!973f!9v!9!3X94BPe13!!!3ffw3f!!!!!!!!!!3f!7!!!!B.!!!!!!!!!!!f.5!!f!7f!7f!7!D3bul2ZvD!!9nf993ffw!Pcv9P!z!G4!D3b!j3fvD!!.zv.2Bu!.!H4vHuf!7e8!j!9vD2bvD!fg9u!9v!.7!Pcv9Ocv9O8!D3bvB3!.H!!!!f!!!f!!!!!!3!!!3f!7xf.zf.85x!!!!H4!B.!!!!45zn!8n!4!D3b!z!.!v!!!!!!!A8!!!f.29GYv927!D2d3D3d3D.!4d!7v!294!f42d3d3bf4!B.7vH.7vB.fg!.7h!.7v!Pe3!GbvdP.!92bvB2bv9.!43f!93f!4!H!.7v!.7e8!9u7tPe7u9.!v!.7v!.bg!3bmlWav927!92Zr1mbv9.!5b3bv9u95!PYv9O4v!.7!nvdv9W72l!!g927g3ubv!Pcv!Oc!9O8!Bf!93f!93!fv92bv927w!3bv9u92nf.!92bvlWam9.fv9u95b3bv!3d3dP.93f!!B2!.n!9vB.!93f!9Ac!93!1rf96Xv.1r3f!93f!93f!MzwMzzMDzMPTmMb2MZysZ!!!!!!!!!!!DP8wDP8wDP8!!!!PAAAAAA8!!!!!!!!!!!!!!!!!!A83f!93f!93fVpaVqWlqVpq!.7v!.7v!.!!!!!fVqWlqmxcmzYGzZOD!8zP!8zP!8f!93fP83f!9!!!!!DP8wD!93f!9w!!!!!!!!!!B3f!9!!!!!!!!AAw!!!!!wf!93f!93fPA!!!!!!!!!Dw93f!93f!9Hc!93!zP!8zP!8zPf8xHf8xHf8B.4jP.4jP.4DAA!!!!!!!!AAAA!!!!!!!!!!!!!DAAA4f!7e7rf.7!!!!!!!wDP8A8wDP8!!!!!f!93f!B!!!!P8wDP8!!!!!DP8wDwDP8wD";var basicdata="4N.ZkPkQNJUQTl0QwgcQH3Rz3jMpL77yACdBMTayfiMcIfSycgsgIHNy6ksLIrUysgNZhLV4hFusTPC2!p8nKbFybacXGXoymEuuhPc46tcQGnD3MzNWcDAA9NtnTH33UCu6Z3.3hJOaiHr4LMeDYz31lRdrXv41sbNAXzy13cdephdeSh9eqo9eRs9f69NUo!sRl!cfz.tWT7MZVAdRORsRPJtTFhF1EFEVBnkTQVFVjmkTQVF1ElUzSVUQEzURUf0TU9sUV5cSGLVRTR1TSV8RPNVVCLVRUVlUOLVRNPFVPB9TOfVQJRNTPFExTFkVFbVRSlkRZTURGD1TLVMUSlkTUNKUSlkTUP0TORNTJNF1Dxk0D1ExTl10PBVROPETPNVxHVE1OV01UFkQoS1zG58UQNEqUhURO70TUPFVFB9qtq6reHkTE!k0.2LvTdkzJ5E1BJ00VNl0GJVxQ900TFl0S5ExM90xFhF0D900TlkzUFkzBRlzQVURLzUROPFVSRqVBxcQTN8QIJFpMVkRURqUJdESURaTJREpH9MAU90Tg0UQOlFIGlETFNtRJxURg8EUF5sRJxURg40TUByTQVkzGlETFBiTPRFIG9UVORMRFZVSDVEIO9EVgAlUFNVRORtTPRFIJ5EUVRFIGlETF70TUByTVRFUVRFIGlETF3USTNVSOdEIGlETFBiTB1UxJxETFdUQMBCRFZVSDVEIOVVTCVk0OVEWUByVJRFSPVFVgY0TSPVWORVQYLVRUVlUOByVJRFSPVFVgc0TTVlwPVFVg8kRgQUQUFcSMxURHFETgEVVB5EVJRV2PZVRSZETPd9TVRFIPZEINVUTPJV2V5ERFZ0JEByUUFEVF1URORtQBREITVlQTNkUJBF1SVERJ10JEBSQSJVQZTUSWl0UJ9kTgIUWgoVRS9cSMxURHFETgQUSSV0QUTVWQVEINl0UNFEVDh8UUJVSOdEIU90Tgw0TOdsRJxURgQUQUFsRPJVTVxUQgQ1TPByQP1EUMVE2DFkTnQFID9kTUlkTVVcVORURGdCRgYUVONEVJ9kzWVkUJZU2M9UQE7ZwsGctBLcwQHs4BDfw!HMECXiw1I8OC!kwaJsaCLnw!JMkC3pwqKsuCjswVLM5C3uwAMsDD7xwkM8gD3wTL1AANASRSJ1TSBAIJ5EIA0gCSVUQEllLNoAANogQSVUQLBAo6iO6ojevBEQyBCdIlqE0K0rABUYS9OQAFqU3DEA0HUaSdLQAwfgiYkmEqCN2gBCCEXYMEKDOlqV5fVoIoW6WlDmqojJ8jUqW4UuIFqFsDY8W4UKWlLShYBLCGnFkEErWRiFiQnfsaFJWGvlxZpM0yDmCp5Ds1UoI6SuIQ6CYETDkoANBFPDkigkoJgJS1elyQoPImUto3jWlhhOM6jGqoRMNQaA0FU8MwGAYiCBbAMgiKoavmMchi07JDX4Igw8!pCQhTAy1KDSRLDKAxKCSp8HIHtMyoBB9gonxpmGoDDiHLTqOID!AgIc3paHoDDiHLnKggA5!sJwAgAWxGqHh7BycAoK8wL6!GqDkGASeFzU4HDyaJDSeFT4CgMhxQSEoBE7XFOSptUoIlCWhlU6XIG!XYUWLF2ShkUqLp9fhuUOYqiTpfVeLoC7AobcJYUmIQOgxjgRsiEJJIDd.mPi5loM0yDSWGDyMF3KACAPiYUaLFqVZLUIWk6ChbBZAITYWgg7wlSBpV0o!Bw4!BUaMkKThtQoLkuAi5yfAR.FiQgPIZZMIzUMTAScprQKLFKChjgBoBErIw3BoEgcsiA9.IjZZioKoAEpIlOSaAgckiYoIFOCkdDmoAAyDhncDw3QnAIA6gnFkxL6FMdDxMpsysRwAmqHoEQ4D9CgAQcQy!DvPoDN9JDC83UICJLC8WRyDw1Sy!ANBpmJ0lkMMQSQy8AZHEGHoAQ4CIaoeKjM69CgA4kvnADf9JDI0wUwCkGH6In5.Bk7.BAvN4kuOwTQyJBtAF.AOpXF0fWIC9CgAw!dxIA!2In5.BgO0wbqemvAy52JwQofueCM002LACAhvZ2fAGvXq!XoegV6KmyCoBU4XGCWsfB!HIjcpVE9XQiB8DgI0JUKFIG9XQyA8KgYsfpKix.FsXjBYQ3fqAgakrgckrU6KYkmAF2SpskGAF6CIOacqAAdLgc.!leDp4U4MESTptQqLF.ChwUYMEKDIdgsoZYoFohKaiqvmIhJSpCQh.UIEghRprk2!FqXpsk2!FuHYQaA8Ek8qQnOIrlMITYMI5BA8Mk8qQ7IIzBAIrlM0GiGalSRBVAtBp.fhUUYFgGAhPE7XwPEIsgMIXrMyx.lqIH7XFXB0EQOFwLAssQYSg0c3pCCpJlyfgc0yJLC0GU6DJ9fhPgM8RE7XQDBqx.lqIH7XG.VhgBdtMRHxsZwAQcdy!D!0k8AMPjT6!pKhJB6!KDPCInrnADh.wUPy56JwwILIHtM01nKgFCBIlmMIKOM0FoYaPoqmohWqJAy.DDiBJjBmlpHSluXaAgUp6gUp5gUqkCy!ODSjNDiiNXqZJ8XJiVoYpuIoHXoIEOCTD5cq8Ca2gI62gkHAJnK0GAycAAiiNDyKcDCOOXqSIVaSIlagIBCLIXqekuHwCoO8EUYPE6DoAEreQPEoCEreYA9AMtEyIHreFmDyxqXh6gZZ6VoeQKg57xGCDAycAAS7HzkrHDPPpDIkRk8IwehCombDAjUuMAMSMNHAMVayJrD8WzECPn8SQnPIzBQqkCy!OzEoIjTprkeAkyCsBgYhBRoQgBS4!DbAYANPlqHp7ZqOoDPDF2Dh.UaOkqTh7QIPohWqBC6wQOATpRMT0RM0XIqGk6D0Dw0NEXaPFqHh7V6OkyTh5QoOghQqAACk!jC0DwUWGDCYGz0lIn6Ags!wluHSlqHSlqDSlmDSp2ISgkHAgAKyM56xgsWygkQy4UaOlTRp6UeFwuAm4UmemuHkHgOsEU6KmyCIXYMkeU6XpHQh6VKYpDQh7BG09n6!FqEIKOsmJ3I8LIKDsIaEMdDxMhwzohWh5gWh6gWh6hWh7BiBJjJGlpXh6BpAmvHYiqDLiCghHAKAEiQpIY6BFeghIErewjexIAP5InsIQPP8pDinNDSeAkciwXQqnCy!OXaYQXAIJkM87CSeAA7AMBKyM1.xg451IlcjwTQyJCdkGXG0EgGTvfMIzBAIrlcysAv7oBmoAYIFGWBs3n.LFeQpVUoIJnBsUXKFKYiIKYiIlRRhUUqIlVRhVYAFmURpUU2BFSBkCYeFgMHAMFXygsI0FmEhKlqsg8vzl6ASl2ASg4ZzopCIQ2M0YgGESAyGcDyvRDKAlSWkJhcplFZSgxE0bjGpKB83QzEImadyGAdPgCAhhRoZEGHIdoMIirt5xRacg0hygwA3qCfBorIItrNpxhMwGA93gIu2gsJ3mSGpjVaZMt9!xKCIACAkDwESSn.LM5X3gKQskVMNQeB0HgYskV8MQ6AplRsLQiA0NUKZF3CsHUKZkWGTopMoAELZgUH1lCFpRV4bECHI6ZdqhBKAFCFhRBy2WDKAxCVkJhcsQFZSIHLURmEYgYoyMV7yg451wXQqsAy!OjghTASFhjCTgqMIhsMI5BA81A!QJPK8QlspYA!SJzC83k8Ow7FIe2MJNAj3g0d3gcI1gEyygszyQPdqA0JACI6!gGQpTANEp2AIHtMJTARBpqAIHtcS!DGOgA!!YiT6LAL!J9faBAtFIgDIw!PhJAymXncKQnFKQagilnAkFoK6KDtBgMHAMJqygszyQLPIHSNImatqgCA6KDPvxKCIHtMyJ3A0zDS5KzEKLX6EwPQqgwSqdwSq!ASChny!gVaEwHBMEA6!QTQp!QKQFmDh6wECPX6EwXgoYw0NEnKDg2MIescp9QqPFqHh7BGImOdyjANEgMHAg451pyCI!7shTAyGhLaAgKQqA0YACkKQg8AzmOB0TAGIeedqsAy!Ob4EgsR4g48ylOBIM!voAY4EglsIQvAI96cq7Ay!ODSILDipTnKLN.fAgk!ylOB8NAyt!niAwbAI1uMT4jcrAIA0eU6EQPOIGkMT7jcpTAtBgU0ygszyMBWxmGEpClKmskKAFGhhDRIRgsI0FmEhKVqekuXhLRITmOEpEZoeEuHI5BA0gQSEQxAIhEejAIgo!DaAQzAM1V6EQPAIFtMI5vsh6R4egMHAk0AExQSEQlA6GqXqAU4BwzQhHksIwfQq6U4BpyCGFiQp6R6epBAkBgMINSNIifNIanMTRyMIzzdpOAiwJDSeAA!BJzC8DwUTLXqekuXhDRIRluEpMVoeEuHI5BA8tAS!OzUFMDiBJjsqQLhoNgcs6BPbIHreF.DyxqHyFCEI7jMI5BgqgPI0czUUMX6QkSkpRAxAMdCygCQsDB!ClOB0HkK!gyMTesMY!UEWUJVQgk0RO9kUFRUDA8jUFR0TgYkUP1EITRVQSRVDAANBgCA8DAyiQXYSEqEIKOM8FIqCMdDxaqIGpRASpZQhkgGoBAiobrbvJEQhmVaSkqEInhNIQvNoBASXcrLO9nQAwfRvPEQh50LEBUoO9KRAFqXvREQh7xkrHrYaRoqmgkHAJzC0xDycAACJNDinNjBJ4QSDwMAsDAGs9LqFMdDxmqH0CY8eGrnoAQCSKiUqBAy.DDygOnKAF2EI5BAOpHLkXk8AwORyBoSSBUUTF3EkhVYTgMHAMtbzm2E0sA7epdAk3VWDQPAT9Yda!XoIKUmIoiW2ACMsnBSjNjEIg4MakuEEXoK8WB9XG1giqYqeQLgx7ZseguRhNB91ZDIwwiEkZnrgAjUuBCMSgMjzl2ETp2MTI8cpm5LgAjKaFKi5igWhjgJSgsB3lWGSlSGSlOGSlKGSlGGSsJCAg.PawPSykB!Ag0YzEuEaKVoEoVYaoVoaoV4aoVIboVYboVobFZWhvVaYgxmCDkKAF2AIzBAsDw08cDyERD5AMhyzJ!P0PkKqg6MIiuNTzBggJ9g2hmsLw7dyrCPWJrK8RnsIQ!Qp6R6epBAkBgMIHSNTifdyoC9EgiB07AyvRXaZJ9PqlSWS!zUkTncpQPAT0Pdy0C5AMd6zgovzg4ZzpmCLpiCLpyCoAEteQPATzBgoLw0NEDaFohGT63MOlSW6AUaZpDMkIk6hlTWqjXeZgByiQXIZEWmpFRqRl2A8mkKAFCHIU8MkcAOVQjBwJDNFgQ4zE6FiEGHoGQYXgSCIo5NTvRNYk4AENAKAxSmqIHLZoqITRONIU8MktAOVQvBwJBdJgQ4zYKKoM9E3g49!GSGhjVYZgCAhiBG4TBtCATF0GAyt!zEPcXKZkWGTiutCIpKIzBA4PCJIgovzg4Zzg0vzg8YzopaplhUpkhkiIBinXjGqKiETW!MIx7Maomr6!WYV5u.vFaFIUBATN2Mo!zCoAQ4Cg8b0lSWRLU4BlWWRLUICgw!2g8b0lWWRLUCCFtAqlSWRLUyBFtATRONIQ2MsTUqbJ8XJqVoapmGoAAyWcrKThBdqAUYDG3EImadhhZoYEOWpsRabgoq1GyGhtpKOlHG8IkaAQSgphl6!FaGo!jOyKD9BmaGMPgBkMELbRLG8vL6!wKgoBguiqUiEwLQq!zEPcDS!OrKIQCNI5BA00DmoAASeAYIDFWEI5BAITENsDwECPLKAG2ghOAycAAZBgMR0QugqgMHAQuPITENs2nMJQbQq!XYDQDRylA9ElCB0QnKgF6QBFVYRKmAgqCycAYoR4UAEpjC0DwU0RDKAECRptYqLGCWhfROMQTQxvAvIlWU0fBNClaEyR!F89hIGl.VaHAZ4oDN3JHEkFk.W4kepghGSJrC0Fk6Eg.NYlWEpGlMVQvAwJD!7AnE0DwECPn8UQTAwUBf9l.CpwU4XECWpxQqMFqFhbhRaHAZAIXIWEmFI4OcpYRaWIX4LECDoAUaRR.FylaUkflKAIH5XIH5XIH5XIH5XIH5Xl.FGpJApgBZAIX4REiEYlugCpVQZfRKYQGAyFiFhZBGkACAAAAyvRXKZkWGYgMHAg4Zzg0YzlaGMNUaYJDJkJkapgGNIbxN06x0mcXKDF4ASl2ASgCAmIVqRIVaRIBisRjWhFhWhGhGq62rABgUvBEASlSWnCEQpl1ZABgMI5BQysAv0EuAI37MaF2AaF6QK!VIDm.SpwY4XFCWxyANBkHD85AKAx.FyFXE0GUqRR!F8WgcsfhRZfpKyx.VZgB51iKBLi6AT3QsoTUKDQfPIUGdpLAKBR!F0nzk6SDClRDCCEDKAEKnoFUaRR.FEBoMylaUkfBhAKrshxV6CIjMyR.loLkKAkwAUIgGGpFgqolGAIH5XIrYkfBCTTbYcFKHpiY8CQzdZZBbXFmFqKWGWQOAywLFIIQchxQoMpCg5yRacwXAiRiF07bcWGLH01beW4UaMl!FoCE5XlKDylDWkfVKDQLGyx.VhLkKAFGXhyhMaqWIZoVYZR!FkOAtBIrY0fB5BMVk0MVDxIXqcFEHGwrAIMNtilRmqYSqIlVmhxZ8CQrchyJaBlWEEBocpGBhAKrshokKAgU10KWGWFeEmllVhIhapHBGhiE7XFiCix.VhpkKEF2loAAKAKqgqYqCqwSqBxZicQuAGKWGKqiZZpgKsTacXQPOYl2A8DAipWDiJVjTpzUeMoWKNlLjoAYYDFKGhjJKkMRE34AC8!nKAwvup6gO0gKaFsI6GMdDxgE.0gY60govzpCYhQAyiQDSjNDy9Onqsg8vzIVKSIV6RIV6eIVqeIBC.Iz0TUnapg8vzJAYhQAikQXoTE.ETN2MIhPdpPhUpOhEIx7MIN2MaF6EaF.EoCErTFekqIHrTwnZhIhcsHhEiQoPpIBC1bX6eIVqeIFrTFqHyx6Uh7VKSIV6RIBiiNjWhOhWhPBSeAA!AMhwzoVoeoV4egCAaR6EaIHpTohckOhGyR6EaIHpTgBSjNDKAg8d3ohWq!DKAwLhpkRaZGCFhRBC9UboYEOWhhBmoiY4BGiQhvRIcFKGhjB6!IH7bwzQxHAPBFjA0znsIwHAGEGGml9WhxZKcQGA6GKXpwBPBJLA0LgJI1RtpvRKcggo1maB4iAdBimBT3QcphVJAlKWlBU6YVKAoAYIZEWGhwhIhNY4FojO6GaBYG9ASJ9POlNDp0AbAISsMQGB0EUcMQuQhzQINFWDh2oKagJKEl.AM2CiJVnKgF.AaQDtp3UKOGOTh0AKAE.EhOVaMmKThfZIYpmhoAUoIGOSxWAfBgcc1wffqHU4Ul2ipuUoIGOC5wANBF!C8FASvVD!8FilhZl6AFOVpYZaWkLD0HUcMQPATGYdhiY4IgCQsioKyxKCCIHrIlhVhYhcsiUWWFmFKQMtiwANyxKCoAoQaFUmIFKCkCY.ImOC5ZBNBFjF86CyxVD!8xKCM1gcsiABMIHrIwvCyxKiqIHrIFTDkGAtHkPDsaUMYQaB0EQ.XQChhfVIYlKipjUoTG.UpTVYVlOFGlJShiApAmPipjAKAgV6TF4E81XaVpQgSoWYVx6UZfVoWlCWaAU4WlOjp0UIWGmFI!OMpVhcpYFpTqaeWlmFyR6ETqUdplhUpkhEID6MIP2MaF.GaFCHoAE7bYEHZQWgoXw0NEDSdUDieWXKUkGFIqaNIMadpvRKcgoq1goM1MhbzgCQsvhEyx.mqIH7boimhiQ4IoCvCIhYsiEZNYCN.ohRZ1UYNQKg52AGIP2cpkRaZFKChjAy2WjAoAErIIhcsioKyxKCqohC0TQMNQ!A5zA9CIhRZzU4MQKg50gmhiQ4IgRMGQzQxXANCFaR6DU4FgCAYgE61KiUqBASfUjGoAEpYohGTKTNIhdd0QhJkEELUqiJSKiEI9RdpQRaUgoq1ohKaYUmIFKCkCY.IYCCjWzkyUDSYXjR8Ql0!MZw1p.fhlBSeAkcKwbAI97MIeeNIhdN8LpsiIhhoAEPUwabS!XcZQGbplBbrgcvzohKaFWFaohmqoVIUoVYUlWFSYiEoAoIYgI41MJ60gMq1iCghNgKYgI41wjAoAErIoykoTzESSDycAAiiNDCuRbKZQDvplxUeAAigXD9AMdP2mqHp7ZYcEKnpiYoeYUmIFSipjY4eQGA6GWCoAELJIhZkkASeAAy8cjGoAEJJmGHpyZoeEuHYgoYzgc!1g0vzM551laGMdWaYJHJsXCymcXKZkWGhUUYFgVaFIVKFIBy9XDKAxSBqoVIFoVYFMJ60gs.1KCKARSBYgs.1GmkoAASeAA!AgE!1GqEoAELFFpUJJBP.glaEg.NTnhNIMqdpml0!FaWRuV4blGGTqhNIZmNk8ACjaD9AMx!2mCnhWJaalmGqw7MOlHG8kApEEGGpuRoZJ9faAAKAEalohBNBgCAhwlc.wcMqlCnVBACsZTybQcFohBeawLAophTS!XmVFCXuEAQ9EUYZ5OAA1PQhklrAAUvAFOWuBAQ9BUoYwOAIHlNoAgJGmKG0KZ6YGKmpkZ4YmWmhkZKcGWGhwlGCJDC0knKAFGWhmBWZWVIclWWZtVYZlSWZsVIZlOWZrV4YlKWZqVoYMZT2pFgBwZSZmQmJjZiYQIPOlHGsHn0!pFQhhBpDmHG8CZmYmNmZkZWZmBHYlaWS!XoZlKWS!XoYlOWS!X4YlSWS!XIZlWWS!XYZlCXS!XIcmDH0OYeZQrg5kBtBmPG0CYuYgJ6DMdDxiWCtEQIc0OAlEQrAUOAtBQpAkiGlBkGCwgO8mnOCoWKcwShFBApA2HgdBYXA2JgdDYHBqhM0sjBYBCAAAAwA!5lVLnHgTs5CkBod4MpFCijq7ACg1Qw80EYNEMPNACIAAAAgxI3F4DyKcDvAQMATIJdphl.fIlKgFGWqWDa2gcG2puNoZDyDbnKvgmNIQhdqBDa2gAE4pCOoZDyZYjGI.1dqlDa2gwo2QPATLqNI3qdqAUoJFeShoUYKlCHIZpdplBSWaXKZgkl2lOGIZpdpiBiXaz0jbD9AMNY2KlAgoCZGYUaKl1WhpUKKlxWhoU6JltWhnUqJlpWhmYmJmdiZoYWKmBHmKBt1gVoIEOCoEErIF2GixKShshYsiU4aIGrIF6WRmV4bl6WCAWoaIGrIFmWphBWppB!HYUWYQSAMdgBLQQRaAWYYQPAT7jdpvVoZgVqZJ9PMFgGaMdP2M5X2gwA3qCPEYkmAwKvoAY4bgcH2mHG8nDGhgAAAAACDcna.gqtoAY4bgI62MJx2gwo2wbHIbwdqAgT5hVYYgcr2mHG86KK!pGApqRsYQDBprR8YQrApsRMZQTAptRcZIoCkJgelpAvMQQTqBgCsOYQbmwmJrZiawaOMODh4oWablXWhtVKblTWhsV6alPWhrVqalLWhqhJTPtdqABtzKogCKogCFCHKM942iSBT3QcpmUoYleShjVKKFSWppUYZMdN2FKChjAKBxKShlhYsiUIZIGrIFOGixKShmlAgFKGixKShhRIcgJKXsI6VgCA8EYaSkqEIbwthiQ4IgSQplFpIIWKZRKCilOWkigYpmlwflIWkigYphFpIECHYl6WhmJaB1iWlgpM05bIcgByGcLqB1CWlopM05bIcgVaYwvvBwB59g8W2QLPT4kdphBfClamKp.PsCkaAgByKcXoYpCQhjJKilKWS!rSqAUYZFSmhhVIcFaGTSjtRmBWhkQYJgCQskgsqwTcskUkZwIM5hBdIxSSCAWsYQnByxSSxjBtEIHLJFTG0Lgcq!VMcxSS5lBPKlaGkCk0!MFD3lGG8KhT6gSiZQkgqp.fhoBSTZroohlc.QYAIZmNhoBGqlaWKAakYFIWhiBCsZTIagVaYJDKsgAymcTIclaGhmlEgqkKoFGWplV4BMJN2FKWhjVIZFWGqgBKAiqAldpME7D5DJ3C0EY4ZwTQyrAdBgMHAQuVyuAvLJXE0wAycAA5FJvK8OkcLwrQyqCPCJvC8EA9BmBGIzBAkcRCYQ4QqAgT5exUSdb2Xk8FUDXqX4UeXF6F8SARCg4v2m7F05D!BgIu2G7F05X6ZwEAYMR73IRyXQIg5dBi4ajGOpDDI.1NTK0NSgwA3oBCPcXqbFZWhvZaYMpG2l6VyKAZCpSGJgBTEM5X2KoAGl5lCYAKAxpHOpDThexEMdvpP8.R!e62an0vnutGKAkacgOMIa3dp6YaOFKmhjJKk4ASScDy3dzkHLDaApCCJmBhAp2Sm!DQhmRYcInKMmGG0DwEBfnKAgDI8CAbCp2LodDCKan69F2Vq4Ca3gsF3w7BESk6sg2NIbxN8CAhDgIu2G3F0uDi!abeXQzNIJhNIbytoBUaXYkmCwkQyLArBp9vqpKAOpLQheZYXKCvAQMBpxlqLIn5!AoI8GkKMIn5!AQYcgCgoAWaZYkXGfXYZlSWeY8dhkV6Y5dx3FOWpilnFfXoYoDLBQ4NMCAj2KCJBJ9faKk2LIjMyIT4RkGHyqmyfZ.PAG3F0GkqLIn5!AQYckekiJ9fKAqKwkAPBAzD0mSac5.PAImMMwjfyuAfAIn6Km6F8uABCpCAOl7lqp2SmBEQqFlJABooovgD6prAs7nmOZOQAKmpABkKAZSQAwjQm!DQqAkJABkKAgGAYACAAAAg.K8BAAgplA.P89CMABYIo!!P2wDAADg.!!!PnAAAAK8!!!!!!frAgAMwSA!!!zBGAA4AE!!f!oCAAAwzvqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqgwA3pGBofDiobDPclmG0DwU.YLqTgCAIUvdpuBxDgwM3p6EoAAyWcD9AYS6Bg4!2YiEIqndqOBKAggi2g0.3opEkKUaYwbQpml0!FaGYBijq7kyBxRDW.YFdW43sbc3LuPeh61BhcoCfjlFWK4Xd9fuxAGjcYARgAAAAAk6vg.NIoodpwlGUQOAIjwdhWBC";var kerneldata="PwdphlMiQOAIUrNIMzdpHgRaBC!84keAIJaB1mGthVZYUmmyQUfpWVIcgMF2gQ73pSMofDiVgnKAF.Gagkr2gVYcEKHIKvdqXBCKaDiWgn6VgCAToodhxRocgc82xGXhnRacIjJ0CYucFGHpyBCKaXackKHGpVAkBgchxRocgcG2pyFoAY8ZQTOYYWDR6BAaoErRAAyKcDzNQDCIz!vhiQ4IgSQsiUoYIHrIFSGoIErIFOGyxKShlxE4gn6igCAIiudqKCK4ggi2p.IogDyZYbaZlKWhlZoYmOWpkV4YGSWqAUoZlGWhwlKgFGGIXjtoLCKAMR92JDP0HQIOGeDTjZsqQLgoew0NEDi0!DL6gByz!Dr4gBSy!DL3gBix!Dr1gBC5!DL0gBiiNDy9Xna4Il6QI16DDgUrMMgrNMArOMAKsRBAI0IDD4YDDwoDDgWjPMAYgEd4m2Cpuk6Kgg9!wWJYpGALpCQhKAS0hXqCmuCpsAS1!D7VlqA8aIKHgc7!pAB8Dw0NEXqeJLA8HkKZgOMTesMYgc7!p8L8FIaHMdDxluXyCAtDG2ChukqdgOMIesMTqUMIOaMT2ROIWIOIA!PsLAGIWIepJByw!DpxMZP4pCAI9.voBAKAgo7!gMg4gQl4gMg4g0f4gCghJBiu!DyAiDS!hrIqmmET6.PILIOTeeNI5BA0CgGagBS!ODSeAA99MhwzpCAI9.PIOIOIeethJpooBAKAgo7!gMg4g0f4GqEoAUaSgPAkBgII6.PIDIOI9HuioaqSlmEI6.PIDIOILIOIe2MIjatpiQ6IM17!p2NoiDyZYDCDcnq4gKupuByBbDCDcDCzcnKAF.GIThdqnDq4gAF2laGSQ0AIJhdpmBTClKRS!XoEgQ73peOoiDyZYjGEDACtfnK7gKOTABOIKvdqAUoEggm4i6EoAAy8gn6VgCAIiudqAUoZlKBIZLeqOBKAM9w2IxkmiHYSPotoDm0DaL6fAAAAAUAhmrRLbYIKHsP.HmJaJGwhjUz3hbYpddOKDm0DaLapmhEEDACtfXaYIlcgQeQq8Ca2g8w2puDojDCQgjWyBC5Bp2NoiDCUYjGEDwEtfD2C2N7g9OdeeQvp1v3g8DLE8xwHnpMfeP1yB3HFkBHT9dr6RpXfjBDi.5nkElpO.xEzRe8fqqqqTEIAAAAAgsF5gQ64gQA5iuvmMRHxmrH0CY.etCm6JrDsKkMIw!OOpDDOpDNYA.0xShVqMVIVFCQqIBq0FGAhCkakgOdhFQoBpqKoRX4AESgoc07hjX5cKDB.pOQhTlKAFiWhTUIGiGgj9Hgj8HgoZYoF4ACn!b4KEyCOgk5!GeDh4Y4MESDoAgZkrY.KQLg5sAWprQKLggAxpaDokDiHLX6N4U.KqWKOlzCIN3dqpAK5g4xyMRkxgIUWUV0UgYkUFVUDAMpKqoiKgMkQNBiQBNVSDBiVyAiKqoiKNAgOEPIx8VsGHT.xG6soL07Tk3JADoME3DGIM!fqAU4EgonxYxEdEHEIzUMT3Z8!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!frsEZKf3ILRCWrsEZCg0ILRCWrfEZzfEJ04rEYmmLTHZviQjQpDXorlSchvyka2Dy44D5AolKAM558!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!voQAakgJqFgeBYweghWT40gcY5maNpTDGI7WerIKQK9rgCJAYjFAZrIKQKCAPCpCYDCAZjCAZqA0YkCU4zpydjPKQqr3IkCkqCNmoANyoApaQjGKQqE04iCkKDF2chM3KiCkAgomKAqSZ2YkmFQGAyoDOGQPfq!XZ2iaBINquyQoPoAQ40EatpWX600mNMIgRaWU40KDB91mdKD0AiCUo092f7FGdqVgOtZDjBYkmFoDh9FWNYgsb5MFY5pOQhamKAFmpoQ074t35!PqM03DGr3JgoA0LeC05dCgO5GDd9GbMmYhBYgI05lachM3okCA!94V6zwzQpO76hCAKAE.MIhqOIPXeyDCNEimAeGacvz3en2JgyQfP8PncDQjMpVTI0xGdygA9AIC99ITIygCAjSKAhTTI1lmMMdYq1gkx5knM0UAtElqchTXMyQqAsChJSKiUpQDfkkOdsRru6qru6qru6qru6qru6qru6qru6qru6FedK!Yw1kcNECkAgQSgpUDNBwJQCAZ.0ggr5EjM0XkKAFCdqNYamgPA8GYqmgPA8DAiQnnaDFeNaqiGqledyeDtAp.PGglsIQjQpUnUAFSdqiAWCAZ6xwLQCAaK2wLgxY7qhCASoqDi6mjGqliN8CYE1opKaYgFYgoP6mPdpVX80weTyXBvKtKpAwPATwnupWD.FQeAI1luxWbq1WktVZz0WtnmFFWdtZDzAKDd.M5n6GbNIDjeqAU40gZq1QbghTjGaQXqyGaNIHWOpVT40ghUhXrISYiUqAUI0kOdpXDxAMBA6J3A0DwE2onMIQCRygBJBp8N0CkyPggr5Mds5miN8Dw0ymnMFQ7CmQbAItcOTfeOIojOiEONIyqOyxGNiRGNyxOPiROPyEXN0vnKIRGdrGKQkzDRTmSN8Dw0ymnsEQLQhHn8EQPAIBWeydA9FIDi.oT40ISc1QmgxWDywoDKAEONTcbeyRAdHYgZaWgq5WXc1QyO8qbs1pbBkEU40QjPIDjOTcbOISkOTh0u6qru6qru6qru6qru6qru6qru6qreK!l8fQLQqepu6qru6qnMIQOATFbeyNA9AMhN6mSN0!kMFQfDpVHb0JDC0EQ80QfAwXBPJg4e6kWNIyqOixGNyRGNixOPyROPiEPN0vnKIRGdrGKQkzbO2Mxt5miN8FkAQMts5JHB0WYq1wfjxWX604kuFQSQhTDhKgcY5QXSySANBpCQhHncHQLBmwnAIojOiEONTcbOItcOTcbeyTAtBg8V5Mxt5JAIISkOTw0uRJbq1oD.FQPAI1letZDB9GaNTHWuoAYI2GeshUb40gMM6Mxt5iSQqAU80wfAGpZhyQbPYGbNYiSQqVU80wfAGpZhyQbPYmaN4XAvAmbNYieQ3hkO8EoME4DmjGKAYQWAHfypHf457h.tphHr4yO.skTb51autnfL64meu6r7.7yPvs3r!.S4v3DM.bnf3q7tXgvV4dJOQwGWs4tdedbmt3BMcwHX8yJ!czTH91Vvd23X!lyKSl2KSl6KSl.KSi.vxWbcyGLP6g4n6gbBsM0r!tXIr1qNIWpOMsDSjqLKA1mdK!Rr2QIQCAWZ2oDuFQ!epvnAgF.epZDBxmbt5yn6.NCSktGSkJ7PCpefjgEJKQvAoAouyQzPiQnPhGbq1oV4roVoroVYroVIrgZq1oXb2QsvhyDuFw3AkLASdpbq8Kbs1M5w5lyKSl2KSl6KSl.KSiehyg4n6kLPkOAPD9yf7FyatYDiVqDj6g0o6iWB5yD5D1qdK!Rb2QIQCAWp2KDd7mKPIOcOaF.KaF6KaF2KaFyKYpMQDIKQhtCibqDaFxyakRHrrROPiQUPYgIr6lyahuWarpMQCUW4rg1b!tXY01mdKD0AiCUo0gBaFg4n6gIr6pCSkRnaAROPiQUPYomqAF2MIyqOmkOdkRrYkzDWpRX48lKdKDkAlFSPYgo.!lyM0pYczQXSqUUYzkOtRP76hCEb0wGh5PXozgIr6xOfjHKgrGKQpOnEggoq6t.RkpAE8LAKAECcrcEZCCAdClCM0N0KHRmS!s4RkwNQjcEJIesOLkEJaoimqoBUqA0YjCAKQEucjgEprhEJ4!DvXp6fjgEJoAkqXFWfqsXo9iiQrhEZzhEJ02rEsWgUs1ncBwyQyDAPCN0oAN2oAQIAhLjGyAHEsJoM0fjjLgEJ0Pz2jCQ6yxWvqEXM8HAKEMyoAQbTK!xiiCAjFwlUy!BfKJTB8MkMIwjQydAPBJHB01wKjCAfBOzoAQvizLKA0mAKBMuoAkaMiQwBpLTYxs2oAM6oAg!P8OoopGzeiCArBdenAoboxpefjgEJYt2oAJPA0s0sjCAv7tGpAwYl6qru6qru6qru6qru6qru6qru6tWAkJJQjFAp6qru6MNE7KkMCQSQqGou6qru6qru6qru6qru6qru6qru6qru6qru6qru6qru6qruq9aE7FWfvHxeh2zEdr7F7fyO4sPa7ex.nsnW7j2eItnW7p1.otHzM1cTOrwFFfdlUZlEUq0ABBR0RKx0OdMQAYZlTs8SEgo1QC1kLBUoATZESLpTPGGVRUV1TA51hyQjN4ATLTg4!hMSJnky2pS5XXLd2JDNwNSQwEfsyM3VnDGA2W7MP!EJoaPswN7TAJKw0Gj8yb1jiRXM1V!suevoIkYCKw09kM.fIjUyJpYKqU.1syerov.djEALrlWrtd15gB0rvqyzPRCar8.7p.EQiC46u0G6W9o4qxOKu5Sq3LKCJmgCMcPJj!nsDQvQqC0QBQ2YBQyE3mnsjQvQq93SBQ2YBQyE3mnMCQrQqA2QkC0YkCAz7JnA0rn6ftEpANGpAQEO61mdCAWZ2KXa1YwUFn!!!!!!!!!!!!Tw!!!!!!LenDGw!!!!!!HJo!!!!!7eAJKw!!!!!h3vi!!!!!!Psgvo80b!!w3.kM.Pkcw5HS8!!!bw!S8!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!Xwne4pk!!!!!XQGW4CAADAAAAAAAAAAAsBTPFERNIVVO1AAWwiQY5GhaCrxcLPCeQjSgZHjiirzknAQskAIgAW8IRClQoAOmNKIJ5uRUa0ooVYlgAK5J!D0DAChv36HRmAgN.Rkg047gAK5gY574BCokDiskrEshBChvTyoQwAIySuSQqPIySuSwqPIySuSQqPIN.eqIUYpt.RkN!RkQjvSKBJOmVJsFASqkD9AgAK5gQ47qru6q3KLRmy3JIQjsEpxlC90pSQjpEZrtEZKgA9CgIL5KB78YBWqAySqDAia.jFGQmUhVCCQu36HRmyfN.RkgVYlgAk74BSqkDSxuDChvDiskD7.YBGJUCTB4YGlQXASgkk7oVYlYAGIN.erfEZCA24HRm6Xsk6Pgwh7gUs7KK6CKDd!qCChvzEokjXqAUYpgQ47gIL5QuPIgSeqB0YKR2aLRmCIQfAIySOs0DJGlWK8FkqAMlr7gkK5gww7pCEIq5v5lCd1piQhl26HR28HRCN.KBZ9KZGpt.RkN!RkQjvSwWvxlC94gkK5lCJ8DACDvXKpYhBYtySkp0fjsEJYtySkJIQjsEJYpSQjpEZrtEZKgAf.gVKtwfEM!YktiCAkBosiF1bh9aMtwbgipASh1CWqgwClCAPFwwBcUUavQHgyGTbrTKAEjbMtQ!t50CN8l2L8tDt6wlOUmbOti.P0L3KlCoEkHwCIRCRHQ5RqAUYvFWrrYKgh0yanCwsnCA!Exmfh26enCAWqAxSqQ0wlC04lCkKQN6RkgJaCpCCLTKA8BoMUCosygZaqQ7ixoCfMw0QpnW0qFuqRnamqgZMqleK8i16kCoQqBUGqQ!eqQ2oHRWYqpCSjeEJYleK0vXYqgx6mCgMzcKA8qw4mCgYpq6KmCAeCwTgSoDN.RefqgwClCAfuwYbpnW0qwPAcuyCUrmaAskKBskKgskqANcpANepAMtF8lqK0xDP7MZ59FqZrUKgSQeSqCwCERCRHQ7RreEZKwAd.sARkwtfrQEZCC0IERyCERCXBwkPIWAPGgxqnCgMzdKA83zonCgYk5ziHRCVAg1amC0IFR2qmC0YFRmKwN6RkM5.7FmZrUKgSQiSKIAPJpKALQEJE!CfGs4RkwtfrQEZK93IER2KERmCBwnfqQ2oHRiBYt6RkpAD8yjBYsypAMvpAwbQs37OnCAWqAAGSt6RkwzQreEZKgBd.pCRjeEJag1QSv8EIFJlUPJFIj2wUFFkUDhUSOdEoG9kUg2AUSV0UTBCUMFUWg8kTgQVQQVMUSV0UTBiUFN0TSREImACUMFUWg8kTgQVQQVcDM9UQElkTH3wUBZVSOdEoNYVRSlkRZlkTH3gRPVlTEBaDPtUjk0JENkLdxjQK!Bi0!jMKQMPGgVamQjQpGDfb4x0zlnsAQjBhXCyTxT6lYAWpZC9ClOdhKXq1FmMTPZeyDAdCFCdpVXIyM9k5wiTyCA!PGeJIQJPsWgEIQJPsNAdBpCEIq5vxma6loBmqopopXCGIKiP0LACw4DbEpCQhmCP8xKLGgVKkwTQqNgBYMlx7gUg8wWQyAA!9YAGSlqZyDANBoxkQnDJBoxE5unsAwrCaF6JSKiEmIBii4DtDgMO.w6QqCAKARKLyEaapeGpsYgGqopKaQKQqAAGaGeJheCS7wb6lk6JGgByzzD!AMR49g898lqL8Wk8AwLBsUksAQPATWEvp5COYwPATNefhZiBYqCCFuXauQYAIT7OTBMPIO7uikAJEmzki3DyzzD!AMR49g898lqL0DwEk3n8Aw!AsRksAQPAT8Cvp5COYwrehaiBYqCyFuXauQUAIF7O0DACwurIJQCx5Mp49gQ98wLAGgBy3zrISlqL8Xl8AwPFsOlsAQnCagI78p2XjeEZqG0IERmq7NyRkgUn!liP8Bgcp6DfAInKAFifh6zEP1Xaup8A8eAST4nKAgAp8M9M5w6Sp5msYQvQqFAy53zUszDi22jmqGjJ5YCPFkiZuZJQnZJQujJQnjJQutJQntJAGglKAFCpimipywUR3ZJA04DWvZJQh427YCUou92mAFmLYpCQhYK6AkrJsDACBvTemwOAI27uhamKAFmJYmiL0DwUj3DyzzD9AMF49miJ4KA5AM539mjZp42ZWCUauJAWh52ZbCUqudOmAwrVyDAvVQWAIVSPkPlsAQPATHTPINhPsDwkl3Xaup8A0fACl4DrNgck9leL8KAyZ4DJGwjCTHePIveP8gAJDwSPI3iPsXkKBgc.9p.Lp5CMYwfAoAkqARKLmFaKGgVauwwCp3CPKlqLIX4ep5mA8gAs7lCJEFgGaMp49leL8MAKAxuLIk7OyEfL02DCBvjBYpaQjSEZjQEZqu3IHRCKAMepAEfL8KE7uZOpAIDMBQLPInAvjYKQrTKQKPANAKoava9vCo27W!rCSYmGyNmpAolGANqpAtSpAKBZCtCSkKA7AMZB8tupANypAt6pAN2pAgUn!liP0FgIh4b49lqP0FgIh6bY.4kK8Mtn!GOMhEzGMDU4kpCQhQWquQPATWefyDAf.Q6Gp3C9AMN59gwL5pCWh5CSl0XqugQh7lmLIO7OIZ8ehuWKkKpEsFBSGvX4rgEM5p2fJQWIkgE.!QPATLbPIZ8uqlCpSKBL6KS6kwzAoAEtrwjQqQAia.zSkuaurQLg5vSCkQtMI27OIabPk6x0h3nsAQPAT5CPINhPsDwkl3DCl4DLagck9leL8JAyZ4D5CwrFsZDyr3D!UwKdpQmCE4AtSgHA8RA.AQ3NoBErsFOMyxKbhEDLBlmL0vD6AxKLoBEvsqCKBxKLoCEvsoihilNchuiZZEX4rlOchBXKxFKMIqZPIJjPJYYqrk.KYl2JEeAKDgYe8leL8VA6FgYe8keL8MAKAxuLIS!PyEfL02DGoJV6kwLAoZxk4xborE.qq1CQhBXbAFKMbyMQp6C9AMZ59JPA85D5XpGWh5S6tQPATTePIVSPIocfp6CyFuXaugAs7gCAISvfpsCC5uXargQu7gER!waRssCC5uDS4!D9Bgot9pCAOgByG9Dd5gQw7kkLMRUqugch7lmbKvnA4gAs7gQw7YAWyCA9AMlL8g0E.QyII3iPslACK3L6AlmbKBAtAiGgigc.9wKBImjPsNUaupIA8GkaBgc.9kgBYl2JE7DaUgYe8Mll9iCg5iCtBmHK0CYOo4UqopHQphmuGlCa6PBpBGCqhhaoot.SkN!SkQjfhRCGelKqphSKo4VooGGKhgiFYlGZy.D9BIACz!XoxoAWqBwSqCwSqDwSqEwSqFwSqGwSqHwSqIwSqJgEIM!PoAQSnQpAImHPaIlAMgI9!ohDYlOJSgAM.oV4kwyCoAErsJXA8kkcAwjQyDAPBJTA0hrKJdCREgOGImHPoFErsgI9!IDcFQbPGICWheCST4DpXlKMSlGMSl.KSl6KSg.bqgEpsIC9.l6ZkyicpBHpsIXqwRKLyl6akyicpvGpsIT4ngCAheSqnEfL8ME7uk.Zkyaunm!J0uDCV4naaFuKIqjPqoVoroV4roVYwoVowYCmpyS6sALAYg0E.KWYwYkGwF6KmFKcaAU4rgByr3DbHgWAhfCKAE6Jx3CPExuLpfGtsQfu5ea.nk6J0sjBYg0E.mbKpmCMwgByq4DPHguBImHPILlPIriP04DqaMZe8pCELfEJ0DwyHRiBYgsK.wnPouA92pCQhQW4kgQF.gQJ.w.BepCQhqWItFCbheW4nFyZqCKqDQHBIUhfqUU4qgcL.wiGepCqoIA6fM6SkN6SkgAW8tSxAN.pAtWxANCqAgsP!pKQh.Cy273KHRmS!JwQjcEZhAL6!g.PiQ3vyQjfjpEJWtCqANXxAYA!HgsU.t2SkpAE8t3KFRCCN3z0L5DS4!jB0LAyz8jDaolKANCqAgZYslCrCKgRZwiRZxWYspCAJwCTAqYQsqYQsqoaroEZyVAZ.lFbjkEpitlSkNWSkYBmrpEJo!jZ7oEJ7pEJ0ybYsqyIKRyYKRiZ5xaYsKZWsKZWslCLGpxDLhEZxxCrSmyJ8DwUr6b6owshoAkGMlBbxxCLHonmJlBbxxC7FpxSZwWcsQOATgpfp0CfHFiK0ZYeqwKgxpiT6TUeslJZhSWKpJFQhkCfIGedp0CPGs0SkQNRqAUIplOKEwATyiaKIdlfpbC9wMZ1!lKJ8HAzAGDLLmDbqAUokkfN0PoI0qWaqwccyQA5wFaJs!qYRbW4mlSL8Sb8owUsRXb2viqNIdlPTW9fpWCPBlSL8EU6oQUoRxm6k4UeslBrCqCSX5bOnlSL0RUqlwbShomKAFaZqA3oLRWItlaZh1CfCpCQh0mKQN6Skl.bh9WKqFkah2ykV!Dy27XIniqNIdlfp.CvAFeaqPQiqQcRp1CNDm6ryQvQqIAia.DNBpCQhqykV!DXMQjRp1Cd9laL0xX6pKVavwMAkYgBsVkyDFqqxqCd3pCUhqCi07nKAFuK8QnKgFqK0KXatwrQqEAia.nKAMd5.gER!QOATVuvpnqM8tU6kwzAoAUavRzK8EkaAFabp2C!Si2D5eCpPm6Zpt2ZABUKrdCQAojuhey0h7b6nk7J81UKrdDQAQ7Spt2dABA9Jm!p5fW6kwvQp9CKARzK8XgMh2WqtwfQqQAia.DdClOJ0Fgap9GJrgsR!QrTqAWoqm6rywIgh.a8pwjQpeC9JF6L8jAyz8Di07DKAEuassW0qFuKIb0PIR0PkyX6qF1L8FkKIgom!MZ1!lKchtWawFyKYpiQhjmKAFSahoW4mFmKYl2rSpCGkCkKsiCQjoEpjpEZrgEZSI0IIRmCCghjZtCDPliK0SkKEiGAI1vP0vYOql2KEpwUl8XaqQnAIxvP0dYeqQnBIqvP0UUKpJFQhkC!Dl2bSBUYvpEQRbW4mMZ1!G1rxjW6owrDEzDy27jVplCvEiCghXbcpm6L4CAtAJAYh9Cd2gER!QqA0Raerledh9CrygCQssWYvFddhXDyG9D9uluZSBUYvMZ1!G7L0DACC9nKUFeqoIgHI7zP0qnKegM!.QPuxnC93gs9.GvKEYLqCgsP!YZ.ql6L8wAi07LaCGWK0FiAeggQ!p.XjuEZq33IIRmKQNuSkgkj!tCqAwnQjVMQrfKQjUMAKgByz8D!l9me!NSxA9qe!NWxAg1KHRmgDNyRkghTpsWurl2a5vCm5sCtAm3KYi.PeaiNI!0P0DwGAgCSj9DiU9DS.9DCGljFbAAsoF0LT939AgC9AKDd9gFEMDLczi2Go9jhhDTIxg.RuUMAsCE7wROcmUMAiQEPY!qu0.3q!KQvSzfs8JM!8z7g86JPc3Xf8vPv0.nU9FafqAoalA0JAC0JADgO01LKPgOghyS4sFGchX2YgCgaqEUowmHM0CYuwgEp!leJ8iAb8kKspBDMIQWCwhALCg6BjIKAT75fqS0ogCkKENioAQHPkPXqwNKoAFeZyRAJxgMc5Mte!oy!C8!r6Omfq!1oHR2oLRmKQNuSkpCUjbEZq.3IHRmq3NySkiCgjSEpo!7oIRKKAOOSkiCojTEpoA44HRCChvnqgN6Rkg047pCcjuEZqJ2IJRmqQNWSkgV4tGuLh8CWh4aouEmLYlqbyCA9CtepApCQjXKAYF2ZpQWAkFCJYNWoAgBpBuOoAsSoAOOoAMSoAgBpBuGoAsKoAOGoAMKoAgFbwqmaVRGc0BDNCqFZwRHM0BkKGKGZwghHbYMASKiEmI1aHRCBSt4RkqmiAw!BI!0P0DwmAgySERCCN3DS4!DdLgIV!gkf!ggR5sJAwt6RkJAISp.XjeEpipAE8UkqzFUbjcEZrUEJaN6RkgM67MZ1!KmCIwXSrQEZKBU4ptiRkpbRbZKQjYEZrZEZbaKQjZEJaN6RkgYD8MZ1!KmCEwXSrTKQKPANAKoava9fjYEZvb9fjZEZrQEJaJASKv3oHR6KmCYIqohKaqiGQSeCQaYcE05g7MUkBxLgRBgLAxBgKAgkiIhJS62LBBkCEwPAbWMAbUMw!!!!!!zkU9z0V9zkZ.zEwuzkzuz0c.zkg.zkHrz0b.zUGvzE5uzk9uzEBvz0FuzEFuz0V.zEU.zUS.zmGDwGHDwmHDwGIDwmIDwGJDwmJDwkQ1zUd2z0Z3zEY3zGKDwmKDwGLDwEN3zUBlzkClzEAl!!!!!fq.LS!y9P";
function binToArray(data){var bincodes="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.!";
	var v=0,cnt=0,out=[],ii=0;
	for(var i=0;i<data.length;i++){
		v+=bincodes.indexOf(data[i])<<cnt;
		cnt+=6;
		if(cnt>=8){
			out[ii++]=(v&255);cnt-=8;v>>=8;
		}
	}
	return out;
}
function loadCart(dataString,from,to){if(dataString==""){for(var i=from;i<to;i++){m[i]=0;}}else
{var bindata=binToArray(dataString);var i=from;for(var cnt=0;cnt<bindata.length;){m[i++]=bindata[cnt++];}}}

function loadPrgData(dataString){       
  var bindata = binToArray(dataString);
	var from = bindata[0]|(bindata[1]<<8);

  var endloc = from+bindata.length;

  for(var cnt=2;cnt<bindata.length;)  m[from+cnt-2]=bindata[cnt++];
  
  var bootStrap = [0x20, 0x33, 0xc5, // JSR $C533 / 50483; re-link
  		// line pointers
  		0xa9, endloc & 0xFF, 0x85, 45, // update variable pointer
  		// low
  		0xA9, endloc >> 8, 0x85, 46, // update variable pointer high
  		0x20, 0x59, 0xc6, // JSR $C659 / 50777 ); CLR, reset TXTPTR
  		0x4c, 0xae, 0xc7, // JMP $C7AE / 51118 ); execute next
  		// statement
  		0x60 // RTS
  ];
  for (var i = 0; i < bootStrap.length; i++) m[320 + i]=bootStrap[i];
}

function setPrgMemory(dataString) {
	var bindata = binToArray(dataString);
	var from = bindata[0]|(bindata[1]<<8);
  var endloc = from+bindata.length;	

  if (from<0x1000) has3k=1;
  if (from>=0x1200) ramMax=0x8000;
}

var pred=new Array(1024);function DisplayInit(){for(var i=0;i<1024;i++){pred[i]=i;}canvasEl=document.getElementById("canvas");if(!canvasEl.getContext)return;else{if(document.getElementById("badie"))document.getElementById("badie").style.display="none";}ctx=canvasEl.getContext("2d");cvsDat=cvsDatHash=null;linedat=null;fillHash=null;}var borderCols=[0,0xFFFFFF,0x891000,0x46bfcf,0x8614c6,0x45b705,0x2713d0,0xbed215,0x9a4600,0xFF9900,0xFFC0CB,0xE0FFFF,0x9370D8,0x90EE90,0xADD8E6,0xFFFFE0];function toHex(d,padding){var hex=d.toString(16);padding=typeof(padding)==="undefined"||padding===null?padding=2:padding;while(hex.length<padding)hex="0"+hex;return hex;}function DisplayRender(){var regCB=m[0x9005]&0xF;var chrom=((~regCB&8)<<12)+((regCB&7)<<10);var vb=m[0x9005]>>4;var cr2=m[0x9002];var scmem=((~vb&8)<<12)+((vb&7)<<10)+((cr2>>7)<<9);var colmem=0x9400+((cr2&128)<<2);var cols=m[0x9002]&0x7F;var rows=(m[0x9003]>>1)&0x3F;var cr3=m[0x9003];var charHeightBit=(cr3&1);var charHeightShift=3+charHeightBit;var charHeightShiftMul=8<<charHeightBit;var left=(m[0x9000]&127)<<2;var top=m[0x9001]<<1;if(cols!=0&&rows!=0){var newCvsDatHash=cols+","+rows+","+charHeightShiftMul;if(cvsDatHash!=newCvsDatHash){cvsDat=ctx.getImageData(0,0,cols*8*2,rows*charHeightShiftMul);linedat=ctx.getImageData(0,0,8*2,charHeightShiftMul);cvsDatHash=newCvsDatHash;for(var loop=0;loop<linedat.width*linedat.height*4;loop++)linedat.data[loop]=0xFF;}var borderColourBits=m[0x900f]&7;var borderColour=borderCols[borderColourBits];var newFillHash=newCvsDatHash+","+borderColour;if(newFillHash!=fillHash){ctx.fillStyle="#"+toHex(borderColour,6);ctx.fillRect(0,0,canvasEl.width,canvasEl.height);fillHash=newFillHash;}var b=m[0x900f]>>4;var bb=borderCols[b];var d=linedat.data;var rowadd=(cvsDat.width<<2)-62;var aux=m[0x900e]>>4;var multicol=[b,borderColourBits,0,aux];var sighash=borderColourBits+(cols*rows)+aux+b<<4;var xxxreset=(canvasEl.width-(cols<<4))>>1;var predc=0;var yyy=((canvasEl.height-(rows<<3<<charHeightBit))>>1);for(var yy=0;yy<rows;yy++){var xxx=xxxreset;for(var xx=0;xx<cols;xx++){var ch=m[scmem++];var co=chrom+(ch<<charHeightShift);if(co>=0x2000&&co<0x8000)co+=0x6000;var colb=m[colmem++];var sig=sighash^((modCount[(co>>3)]+(charHeightBit?(modCount[(co>>3)+1]<<8):0)))+(ch<<16)+colb<<2;if(pred[++predc]==sig){}else{var ix=0;pred[predc]=sig;if(colb&8){multicol[2]=colb&7;for(var k=0;k<8<<charHeightBit;k++){var cl=m[co++];var fc=borderCols[multicol[cl>>6]];d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;fc=borderCols[multicol[(cl>>4)&3]];d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;fc=borderCols[multicol[(cl>>2)&3]];d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;fc=borderCols[multicol[cl&3]];d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;d[ix++]=fc>>16;d[ix++]=fc>>8&0xFF;d[ix++]=fc&0xFF;ix++;}}else{var f=colb&7;var ff=borderCols[f];for(var k=0;k<8<<charHeightBit;k++){var cl=m[co++];var col=(cl&128)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&64)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&32)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&16)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&8)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&4)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&2)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;col=(cl&1)?ff:bb;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;d[ix++]=col>>16;d[ix++]=col>>8&0xFF;d[ix++]=col&0xFF;ix++;}}ctx.putImageData(linedat,xxx,yyy);}xxx+=16;}yyy+=charHeightShiftMul;}}}

var up, down, left, right, fire, isJoykeysEnabled;

function KeyboardInit() {
  isJoykeysEnabled = 0;
  up = down = left = right = fire = 0;
  keymap=[[50]/*2*/,[52]/*4*/,[54]/*6*/,[56]/*8*/,[48]/*0*/,[187,107,61]/*=*/,[36]/*Home*/,[115]/*F4(F7)*/,[81]/*q*/,[69]/*e*/,
    [84]/*t*/,[85]/*u*/,[79]/*o*/,[219,91]/*[*/,[-1]/*Up arr*/,[114]/*F3*/,[20]/*Caps(CBM)*/,
    [83]/*s*/,[70]/*f*/,[72]/*h*/,[75]/*k*/,[186,59]/*;*/,[220,92]/*\*/,[113]/*F2(F3)*/,[32]/* */,
    [90]/*z*/,[67]/*c*/,[66]/*b*/,[77]/*m*/,[190,46]/*.*/,[16]/*Shift*/,[112]/*F1*/,
    [9]/*Tab*/,[16]/*shift*/,[88]/*x*/,[86]/*v*/,[78]/*n*/,[188,44]/*,*/,[191,47]/*/*/,[40]/*down arrow*/,
    [17]/*Ctrl*/,[65]/*a*/,[68]/*d*/,[71]/*g*/,[74]/*j*/,[76]/*l*/,[222]/*'*/,[39]/*right arrow*/,
    [192,96]/*`*/,[87]/*w*/,[82]/*r*/,[89]/*y*/,[73]/*i*/,[80]/*p*/,[221,93]/*]*/,[13]/*Enter*/,
    [49]/*1*/,[51]/*3*/,[53]/*5*/,[55]/*7*/,[57]/*9*/,[189,109]/*-*/,[220,92]/*\*/,[8]/*Backspace*/];
}


function keyDown(e) {
if (e && e.preventDefault)
    e.preventDefault(); // DOM style
	applyKey(document.all? event.keyCode:e.which,false);
return false;
}

function keyUp(e) {
if (e && e.preventDefault)
    e.preventDefault(); // DOM style
	applyKey(document.all? event.keyCode:e.which,true);
return false;
}  

function applyKey(sym,keyup) {

  if (isJoykeysEnabled) {
    var isJoystick = true;
	
  	if (sym ==37)
			left = !keyup;
		else if (sym == 39)
			right = !keyup;
		else if (sym == 38)
			up = !keyup;
		else if (sym == 40)
			down = !keyup;
		else if (sym == 192 || sym==96)
			fire = !keyup;
		else
			isJoystick = false;
			
		if (isJoystick) {
			updateJoystickAndKeyboard();	
			return;
		}
  }
  
	for(var i=0; i<64; i++) {
	 for(var j=0; j<keymap[i].length; j++) {
			if(keymap[i][j]==sym) {
				if (keyup) keysdown[7-(i>>3)]&=~(1<<(i&7)); else keysdown[7-(i>>3)]|=(1<<(i&7));
				updateJoystickAndKeyboard();
				return;
			 }
		  }
		}
		if (sym==37) {
			if (keyup) {
				keysdown[3]&=~0x02; // SHIFT
				keysdown[2]&=~0x80;
			}
			else {
				keysdown[3]|=0x02; // SHIFT
				keysdown[2]|=0x80;
			}
			updateJoystickAndKeyboard();	
		}
		else if (sym==38) {
			if (keyup) {
				keysdown[3]&=~0x02; // SHIFT
				keysdown[3]&=~0x80;
			}
			else {
				keysdown[3]|=0x02; // SHIFT
				keysdown[3]|=0x80;
			}
			updateJoystickAndKeyboard();	
		}
}



// Load PRG example
var keysLeft;
function loadPrgFile(prgArray) {
  // Note: if you use different ram expansion here you'll need to change the start address.
  loadPrgData(prgArray);
  // Calls an internal routine to fix basic pointers and start the game
  keysLeft = 'SYS320\r\n';
  setTimeout("insertKeys()",50);
}

function insertKeys() {
  if (m[0xC6]==0) {
    var len = keysLeft.length;
    if (len>9) len=9;
    for(var i=0; i<len; i++) m[0x277+i] = keysLeft.charCodeAt(i);
    m[0xC6] = len;
    keysLeft = keysLeft.substr(len);
  }
  
  if (keysLeft.length!=0) setTimeout("insertKeys()",20);
}

function replaceAll(strin, oldval, newval) {
	 return strin.replace(oldval,newval);
}

function cvs() {
	var escCodes =  {"SPACE":"\x20", "WHT":"\x05", "RED":"\x1C", "GRN":"\x1E", "BLU":"\x1F", "BLK":"\x90",
	  "PUR":"\x9C", "YEL":"\x9E", "CYN":"\x9F", "HOME":"\x13", "DOWN":"\x11", "LEFT":"\x9D", "RIGHT":"\x1D", "UP":"\x91",  
	  "CLR":"\x93", "RVS ON":"\x12", "RVS OFF":"\x92", "RVS":"\x12" };

  initVic20();
	if (typeof(prgdata)=='string') {
		 setPrgMemory(prgdata);
	}
	else {          
	  keysLeft = keysLeft+"\r\n";
		for (var escCode in escCodes) {           
	    eval("keysLeft=keysLeft.replace(/{([^}]*)"+escCode+"([^}]*)}/g, \"{$1"+escCodes[escCode]+"$2}\");");
	  }  	
		keysLeft=keysLeft.replace(/{([^}]*),([^}]*)}/g,"{$1$2}")
		.replace(/{([^}]*) ([^}]*)}/g,"{$1$2}")
		.replace(/[{}]/g, "")
		.replace(/abccbax(..)/g,"\\$1");
		
	  if (keysLeft.indexOf("RUN")==-1) keysLeft=keysLeft+"RUN\r\n";
	  insertKeys();
  }
}



var shownJoykeysHelp = 0;
function joykeys(enabled) {
  isJoykeysEnabled = enabled;
  document.getElementById("joykeys").checked = isJoykeysEnabled;
	if(enabled && !shownJoykeysHelp) {
		alert("Use the arrow keys and tilde(~) for Joystick control.");
		shownJoykeysHelp=true;
	}
}

function initVic20() {
  Cpu6502();
  DisplayInit();
  KeyboardInit();
  
  if (canvasEl.getContext) {
    document.onkeydown=keyDown;
    document.onkeyup=keyUp;
    gameloop();
  }
}

tcyc=0;
var timingFramesCount=0;
var lastNmi=0;
var endTime = -1;
var canvas = document.getElementById("canvas");
var loadPrgCntr = 150;

function gameloop() {
	startTime = new Date().getTime();
	realStartTime = (endTime!=-1)?endTime:startTime;
	var lineCounter=0;
	// Vic Scan line counter
  m[0x9003]=m[0x9003]&(~128);
	m[0x9004]=0;
	// Do enough clock cycles for 1 frame (plus or minus)
  while(tcyc<17045) {
    var wasNmi = 0;
    if (lastNmi ^ isvia2Nmi) {
      if (isvia2Nmi) {
  			push(pc>>8);
  			push(pc&255);
  			pc=m[NMI_VECTOR]|(m[NMI_VECTOR+1]<<8);
  			push(p&255);
  			p |= 4; // I = 4
  			cyc=7;
  			wasNmi = 1;
			}
			lastNmi = isvia2Nmi;
		}
		
		if (!wasNmi) {
  		if (isvia1interrupt && (~p&4)) {// I = 4
  			push(pc>>8);
  			push(pc&255);
  			pc=m[IRQ_VECTOR]|(m[IRQ_VECTOR+1]<<8);
  			push(p&255);
  			p |= 4; // I = 4
  			cyc=7;
  		} else {
  			compiled[pc]();
  	  }
	  }
		tcyc+=cyc;
		Via1clock(cyc);
		
		// Update scan line counter
		if ((lineCounter+=cyc)>=65) {
  		if (!((m[0x9003]^=128)&128)) m[0x9004]++;
      lineCounter-=65; 
  	}
	}
	tcyc-=17045;
	
	if (loadPrgCntr--==0 && typeof(prgdata)=='string') {
		loadPrgFile(prgdata);
		prgdata = null;
	}
	
  if (timingFramesCount++&1) DisplayRender();	
  
	endTime = new Date().getTime();
 
	diffTime = 31-(endTime-realStartTime);
	if (diffTime<1) diffTime=1;
  setTimeout("gameloop()",diffTime);
}            		
