-
-
Save scottgwald/10947550 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.CPU = function(nes) { | |
this.nes = nes; | |
// Keep Chrome happy | |
this.mem = null; | |
this.REG_ACC = null; | |
this.REG_X = null; | |
this.REG_Y = null; | |
this.REG_SP = null; | |
this.REG_PC = null; | |
this.REG_PC_NEW = null; | |
this.REG_STATUS = null; | |
this.F_CARRY = null; | |
this.F_DECIMAL = null; | |
this.F_INTERRUPT = null; | |
this.F_INTERRUPT_NEW = null; | |
this.F_OVERFLOW = null; | |
this.F_SIGN = null; | |
this.F_ZERO = null; | |
this.F_NOTUSED = null; | |
this.F_NOTUSED_NEW = null; | |
this.F_BRK = null; | |
this.F_BRK_NEW = null; | |
this.opdata = null; | |
this.cyclesToHalt = null; | |
this.crash = null; | |
this.irqRequested = null; | |
this.irqType = null; | |
this.reset(); | |
}; | |
JSNES.CPU.prototype = { | |
// IRQ Types | |
IRQ_NORMAL: 0, | |
IRQ_NMI: 1, | |
IRQ_RESET: 2, | |
reset: function() { | |
// Main memory | |
this.mem = new Array(0x10000); | |
for (var i=0; i < 0x2000; i++) { | |
this.mem[i] = 0xFF; | |
} | |
for (var p=0; p < 4; p++) { | |
var i = p*0x800; | |
this.mem[i+0x008] = 0xF7; | |
this.mem[i+0x009] = 0xEF; | |
this.mem[i+0x00A] = 0xDF; | |
this.mem[i+0x00F] = 0xBF; | |
} | |
for (var i=0x2001; i < this.mem.length; i++) { | |
this.mem[i] = 0; | |
} | |
// CPU Registers: | |
this.REG_ACC = 0; | |
this.REG_X = 0; | |
this.REG_Y = 0; | |
// Reset Stack pointer: | |
this.REG_SP = 0x01FF; | |
// Reset Program counter: | |
this.REG_PC = 0x8000-1; | |
this.REG_PC_NEW = 0x8000-1; | |
// Reset Status register: | |
this.REG_STATUS = 0x28; | |
this.setStatus(0x28); | |
// Set flags: | |
this.F_CARRY = 0; | |
this.F_DECIMAL = 0; | |
this.F_INTERRUPT = 1; | |
this.F_INTERRUPT_NEW = 1; | |
this.F_OVERFLOW = 0; | |
this.F_SIGN = 0; | |
this.F_ZERO = 1; | |
this.F_NOTUSED = 1; | |
this.F_NOTUSED_NEW = 1; | |
this.F_BRK = 1; | |
this.F_BRK_NEW = 1; | |
this.opdata = new JSNES.CPU.OpData().opdata; | |
this.cyclesToHalt = 0; | |
// Reset crash flag: | |
this.crash = false; | |
// Interrupt notification: | |
this.irqRequested = false; | |
this.irqType = null; | |
}, | |
// Emulates a single CPU instruction, returns the number of cycles | |
emulate: function() { | |
var temp; | |
var add; | |
// Check interrupts: | |
if(this.irqRequested){ | |
temp = | |
(this.F_CARRY)| | |
((this.F_ZERO===0?1:0)<<1)| | |
(this.F_INTERRUPT<<2)| | |
(this.F_DECIMAL<<3)| | |
(this.F_BRK<<4)| | |
(this.F_NOTUSED<<5)| | |
(this.F_OVERFLOW<<6)| | |
(this.F_SIGN<<7); | |
this.REG_PC_NEW = this.REG_PC; | |
this.F_INTERRUPT_NEW = this.F_INTERRUPT; | |
switch(this.irqType){ | |
case 0: { | |
// Normal IRQ: | |
if(this.F_INTERRUPT!=0){ | |
////System.out.println("Interrupt was masked."); | |
break; | |
} | |
this.doIrq(temp); | |
////System.out.println("Did normal IRQ. I="+this.F_INTERRUPT); | |
break; | |
}case 1:{ | |
// NMI: | |
this.doNonMaskableInterrupt(temp); | |
break; | |
}case 2:{ | |
// Reset: | |
this.doResetInterrupt(); | |
break; | |
} | |
} | |
this.REG_PC = this.REG_PC_NEW; | |
this.F_INTERRUPT = this.F_INTERRUPT_NEW; | |
this.F_BRK = this.F_BRK_NEW; | |
this.irqRequested = false; | |
} | |
var opinf = this.opdata[this.nes.mmap.load(this.REG_PC+1)]; | |
var cycleCount = (opinf>>24); | |
var cycleAdd = 0; | |
// Find address mode: | |
var addrMode = (opinf >> 8) & 0xFF; | |
// Increment PC by number of op bytes: | |
var opaddr = this.REG_PC; | |
this.REG_PC += ((opinf >> 16) & 0xFF); | |
var addr = 0; | |
switch(addrMode){ | |
case 0:{ | |
// Zero Page mode. Use the address given after the opcode, | |
// but without high byte. | |
addr = this.load(opaddr+2); | |
break; | |
}case 1:{ | |
// Relative mode. | |
addr = this.load(opaddr+2); | |
if(addr<0x80){ | |
addr += this.REG_PC; | |
}else{ | |
addr += this.REG_PC-256; | |
} | |
break; | |
}case 2:{ | |
// Ignore. Address is implied in instruction. | |
break; | |
}case 3:{ | |
// Absolute mode. Use the two bytes following the opcode as | |
// an address. | |
addr = this.load16bit(opaddr+2); | |
break; | |
}case 4:{ | |
// Accumulator mode. The address is in the accumulator | |
// register. | |
addr = this.REG_ACC; | |
break; | |
}case 5:{ | |
// Immediate mode. The value is given after the opcode. | |
addr = this.REG_PC; | |
break; | |
}case 6:{ | |
// Zero Page Indexed mode, X as index. Use the address given | |
// after the opcode, then add the | |
// X register to it to get the final address. | |
addr = (this.load(opaddr+2)+this.REG_X)&0xFF; | |
break; | |
}case 7:{ | |
// Zero Page Indexed mode, Y as index. Use the address given | |
// after the opcode, then add the | |
// Y register to it to get the final address. | |
addr = (this.load(opaddr+2)+this.REG_Y)&0xFF; | |
break; | |
}case 8:{ | |
// Absolute Indexed Mode, X as index. Same as zero page | |
// indexed, but with the high byte. | |
addr = this.load16bit(opaddr+2); | |
if((addr&0xFF00)!=((addr+this.REG_X)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_X; | |
break; | |
}case 9:{ | |
// Absolute Indexed Mode, Y as index. Same as zero page | |
// indexed, but with the high byte. | |
addr = this.load16bit(opaddr+2); | |
if((addr&0xFF00)!=((addr+this.REG_Y)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_Y; | |
break; | |
}case 10:{ | |
// Pre-indexed Indirect mode. Find the 16-bit address | |
// starting at the given location plus | |
// the current X register. The value is the contents of that | |
// address. | |
addr = this.load(opaddr+2); | |
if((addr&0xFF00)!=((addr+this.REG_X)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_X; | |
addr&=0xFF; | |
addr = this.load16bit(addr); | |
break; | |
}case 11:{ | |
// Post-indexed Indirect mode. Find the 16-bit address | |
// contained in the given location | |
// (and the one following). Add to that address the contents | |
// of the Y register. Fetch the value | |
// stored at that adress. | |
addr = this.load16bit(this.load(opaddr+2)); | |
if((addr&0xFF00)!=((addr+this.REG_Y)&0xFF00)){ | |
cycleAdd = 1; | |
} | |
addr+=this.REG_Y; | |
break; | |
}case 12:{ | |
// Indirect Absolute mode. Find the 16-bit address contained | |
// at the given location. | |
addr = this.load16bit(opaddr+2);// Find op | |
if(addr < 0x1FFF) { | |
addr = this.mem[addr] + (this.mem[(addr & 0xFF00) | (((addr & 0xFF) + 1) & 0xFF)] << 8);// Read from address given in op | |
} | |
else{ | |
addr = this.nes.mmap.load(addr) + (this.nes.mmap.load((addr & 0xFF00) | (((addr & 0xFF) + 1) & 0xFF)) << 8); | |
} | |
break; | |
} | |
} | |
// Wrap around for addresses above 0xFFFF: | |
addr&=0xFFFF; | |
// ---------------------------------------------------------------------------------------------------- | |
// Decode & execute instruction: | |
// ---------------------------------------------------------------------------------------------------- | |
// This should be compiled to a jump table. | |
switch(opinf&0xFF){ | |
case 0:{ | |
// ******* | |
// * ADC * | |
// ******* | |
// Add with carry. | |
temp = this.REG_ACC + this.load(addr) + this.F_CARRY; | |
this.F_OVERFLOW = ((!(((this.REG_ACC ^ this.load(addr)) & 0x80)!=0) && (((this.REG_ACC ^ temp) & 0x80))!=0)?1:0); | |
this.F_CARRY = (temp>255?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
this.REG_ACC = (temp&255); | |
cycleCount+=cycleAdd; | |
break; | |
}case 1:{ | |
// ******* | |
// * AND * | |
// ******* | |
// AND memory with accumulator. | |
this.REG_ACC = this.REG_ACC & this.load(addr); | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
//this.REG_ACC = temp; | |
if(addrMode!=11)cycleCount+=cycleAdd; // PostIdxInd = 11 | |
break; | |
}case 2:{ | |
// ******* | |
// * ASL * | |
// ******* | |
// Shift left one bit | |
if(addrMode == 4){ // ADDR_ACC = 4 | |
this.F_CARRY = (this.REG_ACC>>7)&1; | |
this.REG_ACC = (this.REG_ACC<<1)&255; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
}else{ | |
temp = this.load(addr); | |
this.F_CARRY = (temp>>7)&1; | |
temp = (temp<<1)&255; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.write(addr, temp); | |
} | |
break; | |
}case 3:{ | |
// ******* | |
// * BCC * | |
// ******* | |
// Branch on carry clear | |
if(this.F_CARRY == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 4:{ | |
// ******* | |
// * BCS * | |
// ******* | |
// Branch on carry set | |
if(this.F_CARRY == 1){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 5:{ | |
// ******* | |
// * BEQ * | |
// ******* | |
// Branch on zero | |
if(this.F_ZERO == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 6:{ | |
// ******* | |
// * BIT * | |
// ******* | |
temp = this.load(addr); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_OVERFLOW = (temp>>6)&1; | |
temp &= this.REG_ACC; | |
this.F_ZERO = temp; | |
break; | |
}case 7:{ | |
// ******* | |
// * BMI * | |
// ******* | |
// Branch on negative result | |
if(this.F_SIGN == 1){ | |
cycleCount++; | |
this.REG_PC = addr; | |
} | |
break; | |
}case 8:{ | |
// ******* | |
// * BNE * | |
// ******* | |
// Branch on not zero | |
if(this.F_ZERO != 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 9:{ | |
// ******* | |
// * BPL * | |
// ******* | |
// Branch on positive result | |
if(this.F_SIGN == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 10:{ | |
// ******* | |
// * BRK * | |
// ******* | |
this.REG_PC+=2; | |
this.push((this.REG_PC>>8)&255); | |
this.push(this.REG_PC&255); | |
this.F_BRK = 1; | |
this.push( | |
(this.F_CARRY)| | |
((this.F_ZERO==0?1:0)<<1)| | |
(this.F_INTERRUPT<<2)| | |
(this.F_DECIMAL<<3)| | |
(this.F_BRK<<4)| | |
(this.F_NOTUSED<<5)| | |
(this.F_OVERFLOW<<6)| | |
(this.F_SIGN<<7) | |
); | |
this.F_INTERRUPT = 1; | |
//this.REG_PC = load(0xFFFE) | (load(0xFFFF) << 8); | |
this.REG_PC = this.load16bit(0xFFFE); | |
this.REG_PC--; | |
break; | |
}case 11:{ | |
// ******* | |
// * BVC * | |
// ******* | |
// Branch on overflow clear | |
if(this.F_OVERFLOW == 0){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 12:{ | |
// ******* | |
// * BVS * | |
// ******* | |
// Branch on overflow set | |
if(this.F_OVERFLOW == 1){ | |
cycleCount += ((opaddr&0xFF00)!=(addr&0xFF00)?2:1); | |
this.REG_PC = addr; | |
} | |
break; | |
}case 13:{ | |
// ******* | |
// * CLC * | |
// ******* | |
// Clear carry flag | |
this.F_CARRY = 0; | |
break; | |
}case 14:{ | |
// ******* | |
// * CLD * | |
// ******* | |
// Clear decimal flag | |
this.F_DECIMAL = 0; | |
break; | |
}case 15:{ | |
// ******* | |
// * CLI * | |
// ******* | |
// Clear interrupt flag | |
this.F_INTERRUPT = 0; | |
break; | |
}case 16:{ | |
// ******* | |
// * CLV * | |
// ******* | |
// Clear overflow flag | |
this.F_OVERFLOW = 0; | |
break; | |
}case 17:{ | |
// ******* | |
// * CMP * | |
// ******* | |
// Compare memory and accumulator: | |
temp = this.REG_ACC - this.load(addr); | |
this.F_CARRY = (temp>=0?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
cycleCount+=cycleAdd; | |
break; | |
}case 18:{ | |
// ******* | |
// * CPX * | |
// ******* | |
// Compare memory and index X: | |
temp = this.REG_X - this.load(addr); | |
this.F_CARRY = (temp>=0?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
break; | |
}case 19:{ | |
// ******* | |
// * CPY * | |
// ******* | |
// Compare memory and index Y: | |
temp = this.REG_Y - this.load(addr); | |
this.F_CARRY = (temp>=0?1:0); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
break; | |
}case 20:{ | |
// ******* | |
// * DEC * | |
// ******* | |
// Decrement memory by one: | |
temp = (this.load(addr)-1)&0xFF; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.write(addr, temp); | |
break; | |
}case 21:{ | |
// ******* | |
// * DEX * | |
// ******* | |
// Decrement index X by one: | |
this.REG_X = (this.REG_X-1)&0xFF; | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 22:{ | |
// ******* | |
// * DEY * | |
// ******* | |
// Decrement index Y by one: | |
this.REG_Y = (this.REG_Y-1)&0xFF; | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
break; | |
}case 23:{ | |
// ******* | |
// * EOR * | |
// ******* | |
// XOR Memory with accumulator, store in accumulator: | |
this.REG_ACC = (this.load(addr)^this.REG_ACC)&0xFF; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
cycleCount+=cycleAdd; | |
break; | |
}case 24:{ | |
// ******* | |
// * INC * | |
// ******* | |
// Increment memory by one: | |
temp = (this.load(addr)+1)&0xFF; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.write(addr, temp&0xFF); | |
break; | |
}case 25:{ | |
// ******* | |
// * INX * | |
// ******* | |
// Increment index X by one: | |
this.REG_X = (this.REG_X+1)&0xFF; | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 26:{ | |
// ******* | |
// * INY * | |
// ******* | |
// Increment index Y by one: | |
this.REG_Y++; | |
this.REG_Y &= 0xFF; | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
break; | |
}case 27:{ | |
// ******* | |
// * JMP * | |
// ******* | |
// Jump to new location: | |
this.REG_PC = addr-1; | |
break; | |
}case 28:{ | |
// ******* | |
// * JSR * | |
// ******* | |
// Jump to new location, saving return address. | |
// Push return address on stack: | |
this.push((this.REG_PC>>8)&255); | |
this.push(this.REG_PC&255); | |
this.REG_PC = addr-1; | |
break; | |
}case 29:{ | |
// ******* | |
// * LDA * | |
// ******* | |
// Load accumulator with memory: | |
this.REG_ACC = this.load(addr); | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
cycleCount+=cycleAdd; | |
break; | |
}case 30:{ | |
// ******* | |
// * LDX * | |
// ******* | |
// Load index X with memory: | |
this.REG_X = this.load(addr); | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
cycleCount+=cycleAdd; | |
break; | |
}case 31:{ | |
// ******* | |
// * LDY * | |
// ******* | |
// Load index Y with memory: | |
this.REG_Y = this.load(addr); | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
cycleCount+=cycleAdd; | |
break; | |
}case 32:{ | |
// ******* | |
// * LSR * | |
// ******* | |
// Shift right one bit: | |
if(addrMode == 4){ // ADDR_ACC | |
temp = (this.REG_ACC & 0xFF); | |
this.F_CARRY = temp&1; | |
temp >>= 1; | |
this.REG_ACC = temp; | |
}else{ | |
temp = this.load(addr) & 0xFF; | |
this.F_CARRY = temp&1; | |
temp >>= 1; | |
this.write(addr, temp); | |
} | |
this.F_SIGN = 0; | |
this.F_ZERO = temp; | |
break; | |
}case 33:{ | |
// ******* | |
// * NOP * | |
// ******* | |
// No OPeration. | |
// Ignore. | |
break; | |
}case 34:{ | |
// ******* | |
// * ORA * | |
// ******* | |
// OR memory with accumulator, store in accumulator. | |
temp = (this.load(addr)|this.REG_ACC)&255; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
this.REG_ACC = temp; | |
if(addrMode!=11)cycleCount+=cycleAdd; // PostIdxInd = 11 | |
break; | |
}case 35:{ | |
// ******* | |
// * PHA * | |
// ******* | |
// Push accumulator on stack | |
this.push(this.REG_ACC); | |
break; | |
}case 36:{ | |
// ******* | |
// * PHP * | |
// ******* | |
// Push processor status on stack | |
this.F_BRK = 1; | |
this.push( | |
(this.F_CARRY)| | |
((this.F_ZERO==0?1:0)<<1)| | |
(this.F_INTERRUPT<<2)| | |
(this.F_DECIMAL<<3)| | |
(this.F_BRK<<4)| | |
(this.F_NOTUSED<<5)| | |
(this.F_OVERFLOW<<6)| | |
(this.F_SIGN<<7) | |
); | |
break; | |
}case 37:{ | |
// ******* | |
// * PLA * | |
// ******* | |
// Pull accumulator from stack | |
this.REG_ACC = this.pull(); | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
break; | |
}case 38:{ | |
// ******* | |
// * PLP * | |
// ******* | |
// Pull processor status from stack | |
temp = this.pull(); | |
this.F_CARRY = (temp )&1; | |
this.F_ZERO = (((temp>>1)&1)==1)?0:1; | |
this.F_INTERRUPT = (temp>>2)&1; | |
this.F_DECIMAL = (temp>>3)&1; | |
this.F_BRK = (temp>>4)&1; | |
this.F_NOTUSED = (temp>>5)&1; | |
this.F_OVERFLOW = (temp>>6)&1; | |
this.F_SIGN = (temp>>7)&1; | |
this.F_NOTUSED = 1; | |
break; | |
}case 39:{ | |
// ******* | |
// * ROL * | |
// ******* | |
// Rotate one bit left | |
if(addrMode == 4){ // ADDR_ACC = 4 | |
temp = this.REG_ACC; | |
add = this.F_CARRY; | |
this.F_CARRY = (temp>>7)&1; | |
temp = ((temp<<1)&0xFF)+add; | |
this.REG_ACC = temp; | |
}else{ | |
temp = this.load(addr); | |
add = this.F_CARRY; | |
this.F_CARRY = (temp>>7)&1; | |
temp = ((temp<<1)&0xFF)+add; | |
this.write(addr, temp); | |
} | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
break; | |
}case 40:{ | |
// ******* | |
// * ROR * | |
// ******* | |
// Rotate one bit right | |
if(addrMode == 4){ // ADDR_ACC = 4 | |
add = this.F_CARRY<<7; | |
this.F_CARRY = this.REG_ACC&1; | |
temp = (this.REG_ACC>>1)+add; | |
this.REG_ACC = temp; | |
}else{ | |
temp = this.load(addr); | |
add = this.F_CARRY<<7; | |
this.F_CARRY = temp&1; | |
temp = (temp>>1)+add; | |
this.write(addr, temp); | |
} | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp; | |
break; | |
}case 41:{ | |
// ******* | |
// * RTI * | |
// ******* | |
// Return from interrupt. Pull status and PC from stack. | |
temp = this.pull(); | |
this.F_CARRY = (temp )&1; | |
this.F_ZERO = ((temp>>1)&1)==0?1:0; | |
this.F_INTERRUPT = (temp>>2)&1; | |
this.F_DECIMAL = (temp>>3)&1; | |
this.F_BRK = (temp>>4)&1; | |
this.F_NOTUSED = (temp>>5)&1; | |
this.F_OVERFLOW = (temp>>6)&1; | |
this.F_SIGN = (temp>>7)&1; | |
this.REG_PC = this.pull(); | |
this.REG_PC += (this.pull()<<8); | |
if(this.REG_PC==0xFFFF){ | |
return; | |
} | |
this.REG_PC--; | |
this.F_NOTUSED = 1; | |
break; | |
}case 42:{ | |
// ******* | |
// * RTS * | |
// ******* | |
// Return from subroutine. Pull PC from stack. | |
this.REG_PC = this.pull(); | |
this.REG_PC += (this.pull()<<8); | |
if(this.REG_PC==0xFFFF){ | |
return; // return from NSF play routine: | |
} | |
break; | |
}case 43:{ | |
// ******* | |
// * SBC * | |
// ******* | |
temp = this.REG_ACC-this.load(addr)-(1-this.F_CARRY); | |
this.F_SIGN = (temp>>7)&1; | |
this.F_ZERO = temp&0xFF; | |
this.F_OVERFLOW = ((((this.REG_ACC^temp)&0x80)!=0 && ((this.REG_ACC^this.load(addr))&0x80)!=0)?1:0); | |
this.F_CARRY = (temp<0?0:1); | |
this.REG_ACC = (temp&0xFF); | |
if(addrMode!=11)cycleCount+=cycleAdd; // PostIdxInd = 11 | |
break; | |
}case 44:{ | |
// ******* | |
// * SEC * | |
// ******* | |
// Set carry flag | |
this.F_CARRY = 1; | |
break; | |
}case 45:{ | |
// ******* | |
// * SED * | |
// ******* | |
// Set decimal mode | |
this.F_DECIMAL = 1; | |
break; | |
}case 46:{ | |
// ******* | |
// * SEI * | |
// ******* | |
// Set interrupt disable status | |
this.F_INTERRUPT = 1; | |
break; | |
}case 47:{ | |
// ******* | |
// * STA * | |
// ******* | |
// Store accumulator in memory | |
this.write(addr, this.REG_ACC); | |
break; | |
}case 48:{ | |
// ******* | |
// * STX * | |
// ******* | |
// Store index X in memory | |
this.write(addr, this.REG_X); | |
break; | |
}case 49:{ | |
// ******* | |
// * STY * | |
// ******* | |
// Store index Y in memory: | |
this.write(addr, this.REG_Y); | |
break; | |
}case 50:{ | |
// ******* | |
// * TAX * | |
// ******* | |
// Transfer accumulator to index X: | |
this.REG_X = this.REG_ACC; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
break; | |
}case 51:{ | |
// ******* | |
// * TAY * | |
// ******* | |
// Transfer accumulator to index Y: | |
this.REG_Y = this.REG_ACC; | |
this.F_SIGN = (this.REG_ACC>>7)&1; | |
this.F_ZERO = this.REG_ACC; | |
break; | |
}case 52:{ | |
// ******* | |
// * TSX * | |
// ******* | |
// Transfer stack pointer to index X: | |
this.REG_X = (this.REG_SP-0x0100); | |
this.F_SIGN = (this.REG_SP>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 53:{ | |
// ******* | |
// * TXA * | |
// ******* | |
// Transfer index X to accumulator: | |
this.REG_ACC = this.REG_X; | |
this.F_SIGN = (this.REG_X>>7)&1; | |
this.F_ZERO = this.REG_X; | |
break; | |
}case 54:{ | |
// ******* | |
// * TXS * | |
// ******* | |
// Transfer index X to stack pointer: | |
this.REG_SP = (this.REG_X+0x0100); | |
this.stackWrap(); | |
break; | |
}case 55:{ | |
// ******* | |
// * TYA * | |
// ******* | |
// Transfer index Y to accumulator: | |
this.REG_ACC = this.REG_Y; | |
this.F_SIGN = (this.REG_Y>>7)&1; | |
this.F_ZERO = this.REG_Y; | |
break; | |
}default:{ | |
// ******* | |
// * ??? * | |
// ******* | |
this.nes.stop(); | |
this.nes.crashMessage = "Game crashed, invalid opcode at address $"+opaddr.toString(16); | |
break; | |
} | |
}// end of switch | |
return cycleCount; | |
}, | |
load: function(addr){ | |
if (addr < 0x2000) { | |
return this.mem[addr & 0x7FF]; | |
} | |
else { | |
return this.nes.mmap.load(addr); | |
} | |
}, | |
load16bit: function(addr){ | |
if (addr < 0x1FFF) { | |
return this.mem[addr&0x7FF] | |
| (this.mem[(addr+1)&0x7FF]<<8); | |
} | |
else { | |
return this.nes.mmap.load(addr) | (this.nes.mmap.load(addr+1) << 8); | |
} | |
}, | |
write: function(addr, val){ | |
if(addr < 0x2000) { | |
this.mem[addr&0x7FF] = val; | |
} | |
else { | |
this.nes.mmap.write(addr,val); | |
} | |
}, | |
requestIrq: function(type){ | |
if(this.irqRequested){ | |
if(type == this.IRQ_NORMAL){ | |
return; | |
} | |
////System.out.println("too fast irqs. type="+type); | |
} | |
this.irqRequested = true; | |
this.irqType = type; | |
}, | |
push: function(value){ | |
this.nes.mmap.write(this.REG_SP, value); | |
this.REG_SP--; | |
this.REG_SP = 0x0100 | (this.REG_SP&0xFF); | |
}, | |
stackWrap: function(){ | |
this.REG_SP = 0x0100 | (this.REG_SP&0xFF); | |
}, | |
pull: function(){ | |
this.REG_SP++; | |
this.REG_SP = 0x0100 | (this.REG_SP&0xFF); | |
return this.nes.mmap.load(this.REG_SP); | |
}, | |
pageCrossed: function(addr1, addr2){ | |
return ((addr1&0xFF00) != (addr2&0xFF00)); | |
}, | |
haltCycles: function(cycles){ | |
this.cyclesToHalt += cycles; | |
}, | |
doNonMaskableInterrupt: function(status){ | |
if((this.nes.mmap.load(0x2000) & 128) != 0) { // Check whether VBlank Interrupts are enabled | |
this.REG_PC_NEW++; | |
this.push((this.REG_PC_NEW>>8)&0xFF); | |
this.push(this.REG_PC_NEW&0xFF); | |
//this.F_INTERRUPT_NEW = 1; | |
this.push(status); | |
this.REG_PC_NEW = this.nes.mmap.load(0xFFFA) | (this.nes.mmap.load(0xFFFB) << 8); | |
this.REG_PC_NEW--; | |
} | |
}, | |
doResetInterrupt: function(){ | |
this.REG_PC_NEW = this.nes.mmap.load(0xFFFC) | (this.nes.mmap.load(0xFFFD) << 8); | |
this.REG_PC_NEW--; | |
}, | |
doIrq: function(status){ | |
this.REG_PC_NEW++; | |
this.push((this.REG_PC_NEW>>8)&0xFF); | |
this.push(this.REG_PC_NEW&0xFF); | |
this.push(status); | |
this.F_INTERRUPT_NEW = 1; | |
this.F_BRK_NEW = 0; | |
this.REG_PC_NEW = this.nes.mmap.load(0xFFFE) | (this.nes.mmap.load(0xFFFF) << 8); | |
this.REG_PC_NEW--; | |
}, | |
getStatus: function(){ | |
return (this.F_CARRY) | |
|(this.F_ZERO<<1) | |
|(this.F_INTERRUPT<<2) | |
|(this.F_DECIMAL<<3) | |
|(this.F_BRK<<4) | |
|(this.F_NOTUSED<<5) | |
|(this.F_OVERFLOW<<6) | |
|(this.F_SIGN<<7); | |
}, | |
setStatus: function(st){ | |
this.F_CARRY = (st )&1; | |
this.F_ZERO = (st>>1)&1; | |
this.F_INTERRUPT = (st>>2)&1; | |
this.F_DECIMAL = (st>>3)&1; | |
this.F_BRK = (st>>4)&1; | |
this.F_NOTUSED = (st>>5)&1; | |
this.F_OVERFLOW = (st>>6)&1; | |
this.F_SIGN = (st>>7)&1; | |
}, | |
JSON_PROPERTIES: [ | |
'mem', 'cyclesToHalt', 'irqRequested', 'irqType', | |
// Registers | |
'REG_ACC', 'REG_X', 'REG_Y', 'REG_SP', 'REG_PC', 'REG_PC_NEW', | |
'REG_STATUS', | |
// Status | |
'F_CARRY', 'F_DECIMAL', 'F_INTERRUPT', 'F_INTERRUPT_NEW', 'F_OVERFLOW', | |
'F_SIGN', 'F_ZERO', 'F_NOTUSED', 'F_NOTUSED_NEW', 'F_BRK', 'F_BRK_NEW' | |
], | |
toJSON: function() { | |
return JSNES.Utils.toJSON(this); | |
}, | |
fromJSON: function(s) { | |
JSNES.Utils.fromJSON(this, s); | |
} | |
} | |
// Generates and provides an array of details about instructions | |
JSNES.CPU.OpData = function() { | |
this.opdata = new Array(256); | |
// Set all to invalid instruction (to detect crashes): | |
for(var i=0;i<256;i++) this.opdata[i]=0xFF; | |
// Now fill in all valid opcodes: | |
// ADC: | |
this.setOp(this.INS_ADC,0x69,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_ADC,0x65,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_ADC,0x75,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_ADC,0x6D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_ADC,0x7D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_ADC,0x79,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_ADC,0x61,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_ADC,0x71,this.ADDR_POSTIDXIND,2,5); | |
// AND: | |
this.setOp(this.INS_AND,0x29,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_AND,0x25,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_AND,0x35,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_AND,0x2D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_AND,0x3D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_AND,0x39,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_AND,0x21,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_AND,0x31,this.ADDR_POSTIDXIND,2,5); | |
// ASL: | |
this.setOp(this.INS_ASL,0x0A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_ASL,0x06,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_ASL,0x16,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_ASL,0x0E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_ASL,0x1E,this.ADDR_ABSX,3,7); | |
// BCC: | |
this.setOp(this.INS_BCC,0x90,this.ADDR_REL,2,2); | |
// BCS: | |
this.setOp(this.INS_BCS,0xB0,this.ADDR_REL,2,2); | |
// BEQ: | |
this.setOp(this.INS_BEQ,0xF0,this.ADDR_REL,2,2); | |
// BIT: | |
this.setOp(this.INS_BIT,0x24,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_BIT,0x2C,this.ADDR_ABS,3,4); | |
// BMI: | |
this.setOp(this.INS_BMI,0x30,this.ADDR_REL,2,2); | |
// BNE: | |
this.setOp(this.INS_BNE,0xD0,this.ADDR_REL,2,2); | |
// BPL: | |
this.setOp(this.INS_BPL,0x10,this.ADDR_REL,2,2); | |
// BRK: | |
this.setOp(this.INS_BRK,0x00,this.ADDR_IMP,1,7); | |
// BVC: | |
this.setOp(this.INS_BVC,0x50,this.ADDR_REL,2,2); | |
// BVS: | |
this.setOp(this.INS_BVS,0x70,this.ADDR_REL,2,2); | |
// CLC: | |
this.setOp(this.INS_CLC,0x18,this.ADDR_IMP,1,2); | |
// CLD: | |
this.setOp(this.INS_CLD,0xD8,this.ADDR_IMP,1,2); | |
// CLI: | |
this.setOp(this.INS_CLI,0x58,this.ADDR_IMP,1,2); | |
// CLV: | |
this.setOp(this.INS_CLV,0xB8,this.ADDR_IMP,1,2); | |
// CMP: | |
this.setOp(this.INS_CMP,0xC9,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_CMP,0xC5,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_CMP,0xD5,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_CMP,0xCD,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_CMP,0xDD,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_CMP,0xD9,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_CMP,0xC1,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_CMP,0xD1,this.ADDR_POSTIDXIND,2,5); | |
// CPX: | |
this.setOp(this.INS_CPX,0xE0,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_CPX,0xE4,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_CPX,0xEC,this.ADDR_ABS,3,4); | |
// CPY: | |
this.setOp(this.INS_CPY,0xC0,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_CPY,0xC4,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_CPY,0xCC,this.ADDR_ABS,3,4); | |
// DEC: | |
this.setOp(this.INS_DEC,0xC6,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_DEC,0xD6,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_DEC,0xCE,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_DEC,0xDE,this.ADDR_ABSX,3,7); | |
// DEX: | |
this.setOp(this.INS_DEX,0xCA,this.ADDR_IMP,1,2); | |
// DEY: | |
this.setOp(this.INS_DEY,0x88,this.ADDR_IMP,1,2); | |
// EOR: | |
this.setOp(this.INS_EOR,0x49,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_EOR,0x45,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_EOR,0x55,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_EOR,0x4D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_EOR,0x5D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_EOR,0x59,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_EOR,0x41,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_EOR,0x51,this.ADDR_POSTIDXIND,2,5); | |
// INC: | |
this.setOp(this.INS_INC,0xE6,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_INC,0xF6,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_INC,0xEE,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_INC,0xFE,this.ADDR_ABSX,3,7); | |
// INX: | |
this.setOp(this.INS_INX,0xE8,this.ADDR_IMP,1,2); | |
// INY: | |
this.setOp(this.INS_INY,0xC8,this.ADDR_IMP,1,2); | |
// JMP: | |
this.setOp(this.INS_JMP,0x4C,this.ADDR_ABS,3,3); | |
this.setOp(this.INS_JMP,0x6C,this.ADDR_INDABS,3,5); | |
// JSR: | |
this.setOp(this.INS_JSR,0x20,this.ADDR_ABS,3,6); | |
// LDA: | |
this.setOp(this.INS_LDA,0xA9,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_LDA,0xA5,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_LDA,0xB5,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_LDA,0xAD,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_LDA,0xBD,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_LDA,0xB9,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_LDA,0xA1,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_LDA,0xB1,this.ADDR_POSTIDXIND,2,5); | |
// LDX: | |
this.setOp(this.INS_LDX,0xA2,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_LDX,0xA6,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_LDX,0xB6,this.ADDR_ZPY,2,4); | |
this.setOp(this.INS_LDX,0xAE,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_LDX,0xBE,this.ADDR_ABSY,3,4); | |
// LDY: | |
this.setOp(this.INS_LDY,0xA0,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_LDY,0xA4,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_LDY,0xB4,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_LDY,0xAC,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_LDY,0xBC,this.ADDR_ABSX,3,4); | |
// LSR: | |
this.setOp(this.INS_LSR,0x4A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_LSR,0x46,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_LSR,0x56,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_LSR,0x4E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_LSR,0x5E,this.ADDR_ABSX,3,7); | |
// NOP: | |
this.setOp(this.INS_NOP,0xEA,this.ADDR_IMP,1,2); | |
// ORA: | |
this.setOp(this.INS_ORA,0x09,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_ORA,0x05,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_ORA,0x15,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_ORA,0x0D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_ORA,0x1D,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_ORA,0x19,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_ORA,0x01,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_ORA,0x11,this.ADDR_POSTIDXIND,2,5); | |
// PHA: | |
this.setOp(this.INS_PHA,0x48,this.ADDR_IMP,1,3); | |
// PHP: | |
this.setOp(this.INS_PHP,0x08,this.ADDR_IMP,1,3); | |
// PLA: | |
this.setOp(this.INS_PLA,0x68,this.ADDR_IMP,1,4); | |
// PLP: | |
this.setOp(this.INS_PLP,0x28,this.ADDR_IMP,1,4); | |
// ROL: | |
this.setOp(this.INS_ROL,0x2A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_ROL,0x26,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_ROL,0x36,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_ROL,0x2E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_ROL,0x3E,this.ADDR_ABSX,3,7); | |
// ROR: | |
this.setOp(this.INS_ROR,0x6A,this.ADDR_ACC,1,2); | |
this.setOp(this.INS_ROR,0x66,this.ADDR_ZP,2,5); | |
this.setOp(this.INS_ROR,0x76,this.ADDR_ZPX,2,6); | |
this.setOp(this.INS_ROR,0x6E,this.ADDR_ABS,3,6); | |
this.setOp(this.INS_ROR,0x7E,this.ADDR_ABSX,3,7); | |
// RTI: | |
this.setOp(this.INS_RTI,0x40,this.ADDR_IMP,1,6); | |
// RTS: | |
this.setOp(this.INS_RTS,0x60,this.ADDR_IMP,1,6); | |
// SBC: | |
this.setOp(this.INS_SBC,0xE9,this.ADDR_IMM,2,2); | |
this.setOp(this.INS_SBC,0xE5,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_SBC,0xF5,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_SBC,0xED,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_SBC,0xFD,this.ADDR_ABSX,3,4); | |
this.setOp(this.INS_SBC,0xF9,this.ADDR_ABSY,3,4); | |
this.setOp(this.INS_SBC,0xE1,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_SBC,0xF1,this.ADDR_POSTIDXIND,2,5); | |
// SEC: | |
this.setOp(this.INS_SEC,0x38,this.ADDR_IMP,1,2); | |
// SED: | |
this.setOp(this.INS_SED,0xF8,this.ADDR_IMP,1,2); | |
// SEI: | |
this.setOp(this.INS_SEI,0x78,this.ADDR_IMP,1,2); | |
// STA: | |
this.setOp(this.INS_STA,0x85,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_STA,0x95,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_STA,0x8D,this.ADDR_ABS,3,4); | |
this.setOp(this.INS_STA,0x9D,this.ADDR_ABSX,3,5); | |
this.setOp(this.INS_STA,0x99,this.ADDR_ABSY,3,5); | |
this.setOp(this.INS_STA,0x81,this.ADDR_PREIDXIND,2,6); | |
this.setOp(this.INS_STA,0x91,this.ADDR_POSTIDXIND,2,6); | |
// STX: | |
this.setOp(this.INS_STX,0x86,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_STX,0x96,this.ADDR_ZPY,2,4); | |
this.setOp(this.INS_STX,0x8E,this.ADDR_ABS,3,4); | |
// STY: | |
this.setOp(this.INS_STY,0x84,this.ADDR_ZP,2,3); | |
this.setOp(this.INS_STY,0x94,this.ADDR_ZPX,2,4); | |
this.setOp(this.INS_STY,0x8C,this.ADDR_ABS,3,4); | |
// TAX: | |
this.setOp(this.INS_TAX,0xAA,this.ADDR_IMP,1,2); | |
// TAY: | |
this.setOp(this.INS_TAY,0xA8,this.ADDR_IMP,1,2); | |
// TSX: | |
this.setOp(this.INS_TSX,0xBA,this.ADDR_IMP,1,2); | |
// TXA: | |
this.setOp(this.INS_TXA,0x8A,this.ADDR_IMP,1,2); | |
// TXS: | |
this.setOp(this.INS_TXS,0x9A,this.ADDR_IMP,1,2); | |
// TYA: | |
this.setOp(this.INS_TYA,0x98,this.ADDR_IMP,1,2); | |
this.cycTable = new Array( | |
/*0x00*/ 7,6,2,8,3,3,5,5,3,2,2,2,4,4,6,6, | |
/*0x10*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x20*/ 6,6,2,8,3,3,5,5,4,2,2,2,4,4,6,6, | |
/*0x30*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x40*/ 6,6,2,8,3,3,5,5,3,2,2,2,3,4,6,6, | |
/*0x50*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x60*/ 6,6,2,8,3,3,5,5,4,2,2,2,5,4,6,6, | |
/*0x70*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0x80*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, | |
/*0x90*/ 2,6,2,6,4,4,4,4,2,5,2,5,5,5,5,5, | |
/*0xA0*/ 2,6,2,6,3,3,3,3,2,2,2,2,4,4,4,4, | |
/*0xB0*/ 2,5,2,5,4,4,4,4,2,4,2,4,4,4,4,4, | |
/*0xC0*/ 2,6,2,8,3,3,5,5,2,2,2,2,4,4,6,6, | |
/*0xD0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7, | |
/*0xE0*/ 2,6,3,8,3,3,5,5,2,2,2,2,4,4,6,6, | |
/*0xF0*/ 2,5,2,8,4,4,6,6,2,4,2,7,4,4,7,7 | |
); | |
this.instname = new Array(56); | |
// Instruction Names: | |
this.instname[ 0] = "ADC"; | |
this.instname[ 1] = "AND"; | |
this.instname[ 2] = "ASL"; | |
this.instname[ 3] = "BCC"; | |
this.instname[ 4] = "BCS"; | |
this.instname[ 5] = "BEQ"; | |
this.instname[ 6] = "BIT"; | |
this.instname[ 7] = "BMI"; | |
this.instname[ 8] = "BNE"; | |
this.instname[ 9] = "BPL"; | |
this.instname[10] = "BRK"; | |
this.instname[11] = "BVC"; | |
this.instname[12] = "BVS"; | |
this.instname[13] = "CLC"; | |
this.instname[14] = "CLD"; | |
this.instname[15] = "CLI"; | |
this.instname[16] = "CLV"; | |
this.instname[17] = "CMP"; | |
this.instname[18] = "CPX"; | |
this.instname[19] = "CPY"; | |
this.instname[20] = "DEC"; | |
this.instname[21] = "DEX"; | |
this.instname[22] = "DEY"; | |
this.instname[23] = "EOR"; | |
this.instname[24] = "INC"; | |
this.instname[25] = "INX"; | |
this.instname[26] = "INY"; | |
this.instname[27] = "JMP"; | |
this.instname[28] = "JSR"; | |
this.instname[29] = "LDA"; | |
this.instname[30] = "LDX"; | |
this.instname[31] = "LDY"; | |
this.instname[32] = "LSR"; | |
this.instname[33] = "NOP"; | |
this.instname[34] = "ORA"; | |
this.instname[35] = "PHA"; | |
this.instname[36] = "PHP"; | |
this.instname[37] = "PLA"; | |
this.instname[38] = "PLP"; | |
this.instname[39] = "ROL"; | |
this.instname[40] = "ROR"; | |
this.instname[41] = "RTI"; | |
this.instname[42] = "RTS"; | |
this.instname[43] = "SBC"; | |
this.instname[44] = "SEC"; | |
this.instname[45] = "SED"; | |
this.instname[46] = "SEI"; | |
this.instname[47] = "STA"; | |
this.instname[48] = "STX"; | |
this.instname[49] = "STY"; | |
this.instname[50] = "TAX"; | |
this.instname[51] = "TAY"; | |
this.instname[52] = "TSX"; | |
this.instname[53] = "TXA"; | |
this.instname[54] = "TXS"; | |
this.instname[55] = "TYA"; | |
this.addrDesc = new Array( | |
"Zero Page ", | |
"Relative ", | |
"Implied ", | |
"Absolute ", | |
"Accumulator ", | |
"Immediate ", | |
"Zero Page,X ", | |
"Zero Page,Y ", | |
"Absolute,X ", | |
"Absolute,Y ", | |
"Preindexed Indirect ", | |
"Postindexed Indirect", | |
"Indirect Absolute " | |
); | |
} | |
JSNES.CPU.OpData.prototype = { | |
INS_ADC: 0, | |
INS_AND: 1, | |
INS_ASL: 2, | |
INS_BCC: 3, | |
INS_BCS: 4, | |
INS_BEQ: 5, | |
INS_BIT: 6, | |
INS_BMI: 7, | |
INS_BNE: 8, | |
INS_BPL: 9, | |
INS_BRK: 10, | |
INS_BVC: 11, | |
INS_BVS: 12, | |
INS_CLC: 13, | |
INS_CLD: 14, | |
INS_CLI: 15, | |
INS_CLV: 16, | |
INS_CMP: 17, | |
INS_CPX: 18, | |
INS_CPY: 19, | |
INS_DEC: 20, | |
INS_DEX: 21, | |
INS_DEY: 22, | |
INS_EOR: 23, | |
INS_INC: 24, | |
INS_INX: 25, | |
INS_INY: 26, | |
INS_JMP: 27, | |
INS_JSR: 28, | |
INS_LDA: 29, | |
INS_LDX: 30, | |
INS_LDY: 31, | |
INS_LSR: 32, | |
INS_NOP: 33, | |
INS_ORA: 34, | |
INS_PHA: 35, | |
INS_PHP: 36, | |
INS_PLA: 37, | |
INS_PLP: 38, | |
INS_ROL: 39, | |
INS_ROR: 40, | |
INS_RTI: 41, | |
INS_RTS: 42, | |
INS_SBC: 43, | |
INS_SEC: 44, | |
INS_SED: 45, | |
INS_SEI: 46, | |
INS_STA: 47, | |
INS_STX: 48, | |
INS_STY: 49, | |
INS_TAX: 50, | |
INS_TAY: 51, | |
INS_TSX: 52, | |
INS_TXA: 53, | |
INS_TXS: 54, | |
INS_TYA: 55, | |
INS_DUMMY: 56, // dummy instruction used for 'halting' the processor some cycles | |
// -------------------------------- // | |
// Addressing modes: | |
ADDR_ZP : 0, | |
ADDR_REL : 1, | |
ADDR_IMP : 2, | |
ADDR_ABS : 3, | |
ADDR_ACC : 4, | |
ADDR_IMM : 5, | |
ADDR_ZPX : 6, | |
ADDR_ZPY : 7, | |
ADDR_ABSX : 8, | |
ADDR_ABSY : 9, | |
ADDR_PREIDXIND : 10, | |
ADDR_POSTIDXIND: 11, | |
ADDR_INDABS : 12, | |
setOp: function(inst, op, addr, size, cycles){ | |
this.opdata[op] = | |
((inst &0xFF) )| | |
((addr &0xFF)<< 8)| | |
((size &0xFF)<<16)| | |
((cycles&0xFF)<<24); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var swfobject=function(){var m="undefined",t="object",W="Shockwave Flash",bh="ShockwaveFlash.ShockwaveFlash",F="application/x-shockwave-flash",X="SWFObjectExprInst",Y="onreadystatechange",r=window,i=document,w=navigator,Z=false,G=[bi],x=[],H=[],B=[],D,I,O,ba,z=false,J=false,u,P,bb=true,f=function(){var a=typeof i.getElementById!=m&&typeof i.getElementsByTagName!=m&&typeof i.createElement!=m,c=w.userAgent.toLowerCase(),b=w.platform.toLowerCase(),d=b?/win/.test(b):/win/.test(c),g=b?/mac/.test(b):/mac/.test(c),j=/webkit/.test(c)?parseFloat(c.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,h=!+"\v1",o=[0,0,0],l=null;if(typeof w.plugins!=m&&typeof w.plugins[W]==t){l=w.plugins[W].description;if(l&&!(typeof w.mimeTypes!=m&&w.mimeTypes[F]&&!w.mimeTypes[F].enabledPlugin)){Z=true;h=false;l=l.replace(/^.*\s+(\S+\s+\S+$)/,"$1");o[0]=parseInt(l.replace(/^(.*)\..*$/,"$1"),10);o[1]=parseInt(l.replace(/^.*\.(.*)\s.*$/,"$1"),10);o[2]=/[a-zA-Z]/.test(l)?parseInt(l.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else if(typeof r.ActiveXObject!=m){try{var q=new ActiveXObject(bh);if(q){l=q.GetVariable("$version");if(l){h=true;l=l.split(" ")[1].split(",");o=[parseInt(l[0],10),parseInt(l[1],10),parseInt(l[2],10)]}}}catch(e){}}return{w3:a,pv:o,wk:j,ie:h,win:d,mac:g}}(),bo=function(){if(!f.w3){return}if((typeof i.readyState!=m&&i.readyState=="complete")||(typeof i.readyState==m&&(i.getElementsByTagName("body")[0]||i.body))){C()}if(!z){if(typeof i.addEventListener!=m){i.addEventListener("DOMContentLoaded",C,false)}if(f.ie&&f.win){i.attachEvent(Y,function(){if(i.readyState=="complete"){i.detachEvent(Y,arguments.callee);C()}});if(r==top){(function(){if(z){return}try{i.documentElement.doScroll("left")}catch(e){setTimeout(arguments.callee,0);return}C()})()}}if(f.wk){(function(){if(z){return}if(!/loaded|complete/.test(i.readyState)){setTimeout(arguments.callee,0);return}C()})()}bc(C)}}();function C(){if(z){return}try{var a=i.getElementsByTagName("body")[0].appendChild(y("span"));a.parentNode.removeChild(a)}catch(e){return}z=true;var c=G.length;for(var b=0;b<c;b++){G[b]()}}function bd(a){if(z){a()}else{G[G.length]=a}}function bc(a){if(typeof r.addEventListener!=m){r.addEventListener("load",a,false)}else if(typeof i.addEventListener!=m){i.addEventListener("load",a,false)}else if(typeof r.attachEvent!=m){bj(r,"onload",a)}else if(typeof r.onload=="function"){var c=r.onload;r.onload=function(){c();a()}}else{r.onload=a}}function bi(){if(Z){bk()}else{Q()}}function bk(){var c=i.getElementsByTagName("body")[0];var b=y(t);b.setAttribute("type",F);var d=c.appendChild(b);if(d){var g=0;(function(){if(typeof d.GetVariable!=m){var a=d.GetVariable("$version");if(a){a=a.split(" ")[1].split(",");f.pv=[parseInt(a[0],10),parseInt(a[1],10),parseInt(a[2],10)]}}else if(g<10){g++;setTimeout(arguments.callee,10);return}c.removeChild(b);d=null;Q()})()}else{Q()}}function Q(){var a=x.length;if(a>0){for(var c=0;c<a;c++){var b=x[c].id;var d=x[c].callbackFn;var g={success:false,id:b};if(f.pv[0]>0){var j=s(b);if(j){if(K(x[c].swfVersion)&&!(f.wk&&f.wk<312)){A(b,true);if(d){g.success=true;g.ref=R(b);d(g)}}else if(x[c].expressInstall&&S()){var h={};h.data=x[c].expressInstall;h.width=j.getAttribute("width")||"0";h.height=j.getAttribute("height")||"0";if(j.getAttribute("class")){h.styleclass=j.getAttribute("class")}if(j.getAttribute("align")){h.align=j.getAttribute("align")}var o={};var l=j.getElementsByTagName("param");var q=l.length;for(var p=0;p<q;p++){if(l[p].getAttribute("name").toLowerCase()!="movie"){o[l[p].getAttribute("name")]=l[p].getAttribute("value")}}T(h,o,b,d)}else{bl(j);if(d){d(g)}}}}else{A(b,true);if(d){var v=R(b);if(v&&typeof v.SetVariable!=m){g.success=true;g.ref=v}d(g)}}}}}function R(a){var c=null;var b=s(a);if(b&&b.nodeName=="OBJECT"){if(typeof b.SetVariable!=m){c=b}else{var d=b.getElementsByTagName(t)[0];if(d){c=d}}}return c}function S(){return!J&&K("6.0.65")&&(f.win||f.mac)&&!(f.wk&&f.wk<312)}function T(a,c,b,d){J=true;O=d||null;ba={success:false,id:b};var g=s(b);if(g){if(g.nodeName=="OBJECT"){D=U(g);I=null}else{D=g;I=b}a.id=X;if(typeof a.width==m||(!/%$/.test(a.width)&&parseInt(a.width,10)<310)){a.width="310"}if(typeof a.height==m||(!/%$/.test(a.height)&&parseInt(a.height,10)<137)){a.height="137"}i.title=i.title.slice(0,47)+" - Flash Player Installation";var j=f.ie&&f.win?"ActiveX":"PlugIn",h="MMredirectURL="+r.location.toString().replace(/&/g,"%26")+"&MMplayerType="+j+"&MMdoctitle="+i.title;if(typeof c.flashvars!=m){c.flashvars+="&"+h}else{c.flashvars=h}if(f.ie&&f.win&&g.readyState!=4){var o=y("div");b+="SWFObjectNew";o.setAttribute("id",b);g.parentNode.insertBefore(o,g);g.style.display="none";(function(){if(g.readyState==4){g.parentNode.removeChild(g)}else{setTimeout(arguments.callee,10)}})()}V(a,c,b)}}function bl(a){if(f.ie&&f.win&&a.readyState!=4){var c=y("div");a.parentNode.insertBefore(c,a);c.parentNode.replaceChild(U(a),c);a.style.display="none";(function(){if(a.readyState==4){a.parentNode.removeChild(a)}else{setTimeout(arguments.callee,10)}})()}else{a.parentNode.replaceChild(U(a),a)}}function U(a){var c=y("div");if(f.win&&f.ie){c.innerHTML=a.innerHTML}else{var b=a.getElementsByTagName(t)[0];if(b){var d=b.childNodes;if(d){var g=d.length;for(var j=0;j<g;j++){if(!(d[j].nodeType==1&&d[j].nodeName=="PARAM")&&!(d[j].nodeType==8)){c.appendChild(d[j].cloneNode(true))}}}}}return c}function V(a,c,b){var d,g=s(b);if(f.wk&&f.wk<312){return d}if(g){if(typeof a.id==m){a.id=b}if(f.ie&&f.win){var j="";for(var h in a){if(a[h]!=Object.prototype[h]){if(h.toLowerCase()=="data"){c.movie=a[h]}else if(h.toLowerCase()=="styleclass"){j+=' class="'+a[h]+'"'}else if(h.toLowerCase()!="classid"){j+=' '+h+'="'+a[h]+'"'}}}var o="";for(var l in c){if(c[l]!=Object.prototype[l]){o+='<param name="'+l+'" value="'+c[l]+'" />'}}g.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+j+'>'+o+'</object>';H[H.length]=a.id;d=s(a.id)}else{var q=y(t);q.setAttribute("type",F);for(var p in a){if(a[p]!=Object.prototype[p]){if(p.toLowerCase()=="styleclass"){q.setAttribute("class",a[p])}else if(p.toLowerCase()!="classid"){q.setAttribute(p,a[p])}}}for(var n in c){if(c[n]!=Object.prototype[n]&&n.toLowerCase()!="movie"){bm(q,n,c[n])}}g.parentNode.replaceChild(q,g);d=q}}return d}function bm(a,c,b){var d=y("param");d.setAttribute("name",c);d.setAttribute("value",b);a.appendChild(d)}function be(a){var c=s(a);if(c&&c.nodeName=="OBJECT"){if(f.ie&&f.win){c.style.display="none";(function(){if(c.readyState==4){bn(a)}else{setTimeout(arguments.callee,10)}})()}else{c.parentNode.removeChild(c)}}}function bn(a){var c=s(a);if(c){for(var b in c){if(typeof c[b]=="function"){c[b]=null}}c.parentNode.removeChild(c)}}function s(a){var c=null;try{c=i.getElementById(a)}catch(e){}return c}function y(a){return i.createElement(a)}function bj(a,c,b){a.attachEvent(c,b);B[B.length]=[a,c,b]}function K(a){var c=f.pv,b=a.split(".");b[0]=parseInt(b[0],10);b[1]=parseInt(b[1],10)||0;b[2]=parseInt(b[2],10)||0;return(c[0]>b[0]||(c[0]==b[0]&&c[1]>b[1])||(c[0]==b[0]&&c[1]==b[1]&&c[2]>=b[2]))?true:false}function bf(a,c,b,d){if(f.ie&&f.mac){return}var g=i.getElementsByTagName("head")[0];if(!g){return}var j=(b&&typeof b=="string")?b:"screen";if(d){u=null;P=null}if(!u||P!=j){var h=y("style");h.setAttribute("type","text/css");h.setAttribute("media",j);u=g.appendChild(h);if(f.ie&&f.win&&typeof i.styleSheets!=m&&i.styleSheets.length>0){u=i.styleSheets[i.styleSheets.length-1]}P=j}if(f.ie&&f.win){if(u&&typeof u.addRule==t){u.addRule(a,c)}}else{if(u&&typeof i.createTextNode!=m){u.appendChild(i.createTextNode(a+" {"+c+"}"))}}}function A(a,c){if(!bb){return}var b=c?"visible":"hidden";if(z&&s(a)){s(a).style.visibility=b}else{bf("#"+a,"visibility:"+b)}}function bg(a){var c=/[\\\"<>\.;]/;var b=c.exec(a)!=null;return b&&typeof encodeURIComponent!=m?encodeURIComponent(a):a}var bp=function(){if(f.ie&&f.win){window.attachEvent("onunload",function(){var a=B.length;for(var c=0;c<a;c++){B[c][0].detachEvent(B[c][1],B[c][2])}var b=H.length;for(var d=0;d<b;d++){be(H[d])}for(var g in f){f[g]=null}f=null;for(var j in swfobject){swfobject[j]=null}swfobject=null})}}();return{registerObject:function(a,c,b,d){if(f.w3&&a&&c){var g={};g.id=a;g.swfVersion=c;g.expressInstall=b;g.callbackFn=d;x[x.length]=g;A(a,false)}else if(d){d({success:false,id:a})}},getObjectById:function(a){if(f.w3){return R(a)}},embedSWF:function(j,h,o,l,q,p,v,L,M,E){var N={success:false,id:h};if(f.w3&&!(f.wk&&f.wk<312)&&j&&h&&o&&l&&q){A(h,false);bd(function(){o+="";l+="";var a={};if(M&&typeof M===t){for(var c in M){a[c]=M[c]}}a.data=j;a.width=o;a.height=l;var b={};if(L&&typeof L===t){for(var d in L){b[d]=L[d]}}if(v&&typeof v===t){for(var k in v){if(typeof b.flashvars!=m){b.flashvars+="&"+k+"="+v[k]}else{b.flashvars=k+"="+v[k]}}}if(K(q)){var g=V(a,b,h);if(a.id==h){A(h,true)}N.success=true;N.ref=g}else if(p&&S()){a.data=p;T(a,b,h,E);return}else{A(h,true)}if(E){E(N)}})}else if(E){E(N)}},switchOffAutoHideShow:function(){bb=false},ua:f,getFlashPlayerVersion:function(){return{major:f.pv[0],minor:f.pv[1],release:f.pv[2]}},hasFlashPlayerVersion:K,createSWF:function(a,c,b){if(f.w3){return V(a,c,b)}else{return undefined}},showExpressInstall:function(a,c,b,d){if(f.w3&&S()){T(a,c,b,d)}},removeSWF:function(a){if(f.w3){be(a)}},createCSS:function(a,c,b,d){if(f.w3){bf(a,c,b,d)}},addDomLoadEvent:bd,addLoadEvent:bc,getQueryParamValue:function(a){var c=i.location.search||i.location.hash;if(c){if(/\?/.test(c)){c=c.split("?")[1]}if(a==null){return bg(c)}var b=c.split("&");for(var d=0;d<b.length;d++){if(b[d].substring(0,b[d].indexOf("="))==a){return bg(b[d].substring((b[d].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(J){var a=s(X);if(a&&D){a.parentNode.replaceChild(D,a);if(I){A(I,true);if(f.ie&&f.win){D.style.display="block"}}if(O){O(ba)}}J=false}}}}();function DynamicAudio(a){if(this instanceof arguments.callee){if(typeof this.init=="function"){this.init.apply(this,(a&&a.callee)?a:arguments)}}else{return new arguments.callee(arguments)}}DynamicAudio.nextId=1;DynamicAudio.prototype={nextId:null,swf:'dynamicaudio.swf',audioElement:null,flashWrapper:null,flashElement:null,init:function(c){var b=this;b.id=DynamicAudio.nextId++;if(c&&typeof c['swf']!='undefined'){b.swf=c['swf']}if(typeof Audio!='undefined'){b.audioElement=new Audio();if(b.audioElement.mozSetup){b.audioElement.mozSetup(2,44100,1);return}}b.audioElement=null;b.flashWrapper=document.createElement('div');b.flashWrapper.id='dynamicaudio-flashwrapper-'+b.id;var d=b.flashWrapper.style;d['position']='fixed';d['width']=d['height']='8px';d['bottom']=d['left']='0px';d['overflow']='hidden';b.flashElement=document.createElement('div');b.flashElement.id='dynamicaudio-flashelement-'+b.id;b.flashWrapper.appendChild(b.flashElement);document.body.appendChild(b.flashWrapper);swfobject.embedSWF(b.swf,b.flashElement.id,"8","8","9.0.0",null,null,{'allowScriptAccess':'always'},null,function(a){b.flashElement=a.ref})},write:function(a){if(this.audioElement!=null){this.audioElement.mozWriteAudio(a.length,a)}else if(this.flashElement!=null){var c=new Array(a.length);for(var b=a.length-1;b!=0;b--){c[b]=Math.floor(a[b]*32768)}this.flashElement.write(c.join(' '))}},writeInt:function(a){if(this.audioElement!=null){var c=new Array(a.length);for(var b=a.length-1;b!=0;b--){c[b]=Math.floor(a[b]/32768)}this.audioElement.mozWriteAudio(c.length,c)}else if(this.flashElement!=null){this.flashElement.write(a.join(' '))}}}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<title>JSNES for Google Glass: A JavaScript NES emulator running on Google Glass via Wearscript</title> | |
<script src="jquery-1.4.2.min.js" type="text/javascript" charset="utf-8"></script> | |
<script src="dynamicaudio-min.js" type="text/javascript" charset="utf-8"></script> | |
<script src="nes.js" type="text/javascript" charset="utf-8"></script> | |
<script src="utils.js" type="text/javascript" charset="utf-8"></script> | |
<script src="cpu.js" type="text/javascript" charset="utf-8"></script> | |
<script src="keyboard.js" type="text/javascript" charset="utf-8"></script> | |
<script src="mappers.js" type="text/javascript" charset="utf-8"></script> | |
<script src="papu.js" type="text/javascript" charset="utf-8"></script> | |
<script src="ppu.js" type="text/javascript" charset="utf-8"></script> | |
<script src="rom.js" type="text/javascript" charset="utf-8"></script> | |
<script src="ui.js" type="text/javascript" charset="utf-8"></script> | |
</head> | |
<body bgcolor="#000000"> | |
<div style="background-color:black;height:380px;width:640px;"> | |
<div align="center" id="emulator"></div> | |
</div> | |
<br> | |
<font color="white" size="2"> | |
Porting by: Justin "jujuman" Chase | |
<a color="white" align="right" href="http://fir.sh/projects/jsnes/">Official JSNES</a> - JSNES source @ <a href="https://github.com/bfirsh/jsnes/">GitHub</a> <br> | |
<a color="white" align="right" href="http://wearscript.com/">Wearscript</a> | |
</font> | |
<script type="text/javascript" charset="utf-8"> | |
function server() { | |
WS.say('Keyboard'); | |
} | |
function main() { | |
if (WS.scriptVersion(1)) return; | |
nes = new JSNES({ | |
'ui': $('#emulator').JSNESUI({ | |
"Homebrew": [ | |
['Super Mario Bros', 'smb.nes'], | |
], | |
}) | |
}); | |
WS.serverConnect('{{WSUrl}}', server); | |
} | |
window.onload = main; | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* jQuery JavaScript Library v1.4.2 | |
* http://jquery.com/ | |
* | |
* Copyright 2010, John Resig | |
* Dual licensed under the MIT or GPL Version 2 licenses. | |
* http://jquery.org/license | |
* | |
* Includes Sizzle.js | |
* http://sizzlejs.com/ | |
* Copyright 2010, The Dojo Foundation | |
* Released under the MIT, BSD, and GPL Licenses. | |
* | |
* Date: Sat Feb 13 22:33:48 2010 -0500 | |
*/ | |
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i? | |
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r= | |
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g, | |
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e= | |
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, | |
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& | |
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, | |
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== | |
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, | |
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)|| | |
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded", | |
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype, | |
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+ | |
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f], | |
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]=== | |
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&& | |
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari= | |
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>"; | |
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, | |
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= | |
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= | |
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, | |
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; | |
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, | |
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== | |
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, | |
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ", | |
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ", | |
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className= | |
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i= | |
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= | |
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); | |
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, | |
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); | |
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), | |
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!= | |
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type= | |
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& | |
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; | |
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), | |
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop|| | |
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this, | |
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent= | |
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y, | |
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit= | |
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}}; | |
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", | |
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, | |
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, | |
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&& | |
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}}, | |
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector, | |
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "), | |
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q]; | |
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, | |
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); | |
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| | |
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[]; | |
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length- | |
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, | |
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}}, | |
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]= | |
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[]; | |
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, | |
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, | |
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, | |
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, | |
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= | |
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m= | |
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== | |
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, | |
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition|| | |
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m= | |
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& | |
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>"; | |
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); | |
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: | |
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/, | |
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length; | |
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= | |
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== | |
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", | |
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? | |
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== | |
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)? | |
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= | |
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, | |
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, | |
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, | |
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); | |
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, | |
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&& | |
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]|| | |
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length=== | |
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); | |
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", | |
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= | |
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? | |
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= | |
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= | |
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, | |
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= | |
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= | |
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== | |
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, | |
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), | |
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, | |
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& | |
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? | |
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== | |
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= | |
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", | |
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| | |
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); | |
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== | |
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== | |
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; | |
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay"); | |
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a], | |
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)}, | |
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing= | |
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]); | |
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== | |
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| | |
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; | |
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= | |
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, | |
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length|| | |
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement? | |
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b= | |
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle; | |
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&& | |
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>"; | |
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); | |
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, | |
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- | |
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": | |
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in | |
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license | |
//@ sourceMappingURL=jquery.min.map | |
*/ | |
(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t | |
}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); | |
u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
// Keyboard events are bound in the UI | |
JSNES.Keyboard = function() { | |
var i; | |
this.keys = { | |
KEY_A: 0, | |
KEY_B: 1, | |
KEY_SELECT: 2, | |
KEY_START: 3, | |
KEY_UP: 4, | |
KEY_DOWN: 5, | |
KEY_LEFT: 6, | |
KEY_RIGHT: 7 | |
}; | |
this.state1 = new Array(8); | |
for (i = 0; i < this.state1.length; i++) { | |
this.state1[i] = 0x40; | |
} | |
this.state2 = new Array(8); | |
for (i = 0; i < this.state2.length; i++) { | |
this.state2[i] = 0x40; | |
} | |
}; | |
JSNES.Keyboard.prototype = { | |
setKey: function(key, value) { | |
console.log(key); | |
console.log(value); | |
switch (key) { | |
case 88: this.state1[this.keys.KEY_A] = value; break; // X | |
case 89: this.state1[this.keys.KEY_B] = value; break; // Y (Central European keyboard) | |
case 90: this.state1[this.keys.KEY_B] = value; break; // Z | |
case 38: this.state1[this.keys.KEY_A] = value; break; // MM Up | |
case 17: this.state1[this.keys.KEY_SELECT] = value; break; // Right Ctrl | |
case 13: this.state1[this.keys.KEY_START] = value; break; // Enter | |
case 38: this.state1[this.keys.KEY_UP] = value; break; // Up | |
case 40: this.state1[this.keys.KEY_DOWN] = value; break; // Down | |
case 188: this.state1[this.keys.KEY_LEFT] = value; break; // Left | |
case 190: this.state1[this.keys.KEY_RIGHT] = value; break; // Right | |
case 39: this.state1[this.keys.KEY_RIGHT] = value; break; // MM Right | |
case 103: this.state2[this.keys.KEY_A] = value; break; // Num-7 | |
case 105: this.state2[this.keys.KEY_B] = value; break; // Num-9 | |
case 99: this.state2[this.keys.KEY_SELECT] = value; break; // Num-3 | |
case 97: this.state2[this.keys.KEY_START] = value; break; // Num-1 | |
case 104: this.state2[this.keys.KEY_UP] = value; break; // Num-8 | |
case 98: this.state2[this.keys.KEY_DOWN] = value; break; // Num-2 | |
case 100: this.state2[this.keys.KEY_LEFT] = value; break; // Num-4 | |
case 102: this.state2[this.keys.KEY_RIGHT] = value; break; // Num-6 | |
default: return true; | |
} | |
return false; // preventDefault | |
}, | |
keyDown: function(evt) { | |
if (!this.setKey(evt.keyCode, 0x41) && evt.preventDefault) { | |
evt.preventDefault(); | |
} | |
}, | |
keyUp: function(evt) { | |
if (!this.setKey(evt.keyCode, 0x40) && evt.preventDefault) { | |
evt.preventDefault(); | |
} | |
}, | |
keyPress: function(evt) { | |
evt.preventDefault(); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"name": "Mario NES"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.Mappers = {}; | |
JSNES.Mappers[0] = function(nes) { | |
this.nes = nes; | |
}; | |
JSNES.Mappers[0].prototype = { | |
reset: function() { | |
this.joy1StrobeState = 0; | |
this.joy2StrobeState = 0; | |
this.joypadLastWrite = 0; | |
this.mousePressed = false; | |
this.mouseX = null; | |
this.mouseY = null; | |
}, | |
write: function(address, value) { | |
if (address < 0x2000) { | |
// Mirroring of RAM: | |
this.nes.cpu.mem[address & 0x7FF] = value; | |
} | |
else if (address > 0x4017) { | |
this.nes.cpu.mem[address] = value; | |
if (address >= 0x6000 && address < 0x8000) { | |
// Write to SaveRAM. Store in file: | |
// TODO: not yet | |
//if(this.nes.rom!=null) | |
// this.nes.rom.writeBatteryRam(address,value); | |
} | |
} | |
else if (address > 0x2007 && address < 0x4000) { | |
this.regWrite(0x2000 + (address & 0x7), value); | |
} | |
else { | |
this.regWrite(address, value); | |
} | |
}, | |
writelow: function(address, value) { | |
if (address < 0x2000) { | |
// Mirroring of RAM: | |
this.nes.cpu.mem[address & 0x7FF] = value; | |
} | |
else if (address > 0x4017) { | |
this.nes.cpu.mem[address] = value; | |
} | |
else if (address > 0x2007 && address < 0x4000) { | |
this.regWrite(0x2000 + (address & 0x7), value); | |
} | |
else { | |
this.regWrite(address, value); | |
} | |
}, | |
load: function(address) { | |
// Wrap around: | |
address &= 0xFFFF; | |
// Check address range: | |
if (address > 0x4017) { | |
// ROM: | |
return this.nes.cpu.mem[address]; | |
} | |
else if (address >= 0x2000) { | |
// I/O Ports. | |
return this.regLoad(address); | |
} | |
else { | |
// RAM (mirrored) | |
return this.nes.cpu.mem[address & 0x7FF]; | |
} | |
}, | |
regLoad: function(address) { | |
switch (address >> 12) { // use fourth nibble (0xF000) | |
case 0: | |
break; | |
case 1: | |
break; | |
case 2: | |
// Fall through to case 3 | |
case 3: | |
// PPU Registers | |
switch (address & 0x7) { | |
case 0x0: | |
// 0x2000: | |
// PPU Control Register 1. | |
// (the value is stored both | |
// in main memory and in the | |
// PPU as flags): | |
// (not in the real NES) | |
return this.nes.cpu.mem[0x2000]; | |
case 0x1: | |
// 0x2001: | |
// PPU Control Register 2. | |
// (the value is stored both | |
// in main memory and in the | |
// PPU as flags): | |
// (not in the real NES) | |
return this.nes.cpu.mem[0x2001]; | |
case 0x2: | |
// 0x2002: | |
// PPU Status Register. | |
// The value is stored in | |
// main memory in addition | |
// to as flags in the PPU. | |
// (not in the real NES) | |
return this.nes.ppu.readStatusRegister(); | |
case 0x3: | |
return 0; | |
case 0x4: | |
// 0x2004: | |
// Sprite Memory read. | |
return this.nes.ppu.sramLoad(); | |
case 0x5: | |
return 0; | |
case 0x6: | |
return 0; | |
case 0x7: | |
// 0x2007: | |
// VRAM read: | |
return this.nes.ppu.vramLoad(); | |
} | |
break; | |
case 4: | |
// Sound+Joypad registers | |
switch (address - 0x4015) { | |
case 0: | |
// 0x4015: | |
// Sound channel enable, DMC Status | |
return this.nes.papu.readReg(address); | |
case 1: | |
// 0x4016: | |
// Joystick 1 + Strobe | |
return this.joy1Read(); | |
case 2: | |
// 0x4017: | |
// Joystick 2 + Strobe | |
if (this.mousePressed) { | |
// Check for white pixel nearby: | |
var sx = Math.max(0, this.mouseX - 4); | |
var ex = Math.min(256, this.mouseX + 4); | |
var sy = Math.max(0, this.mouseY - 4); | |
var ey = Math.min(240, this.mouseY + 4); | |
var w = 0; | |
for (var y=sy; y<ey; y++) { | |
for (var x=sx; x<ex; x++) { | |
if (this.nes.ppu.buffer[(y<<8)+x] == 0xFFFFFF) { | |
w |= 0x1<<3; | |
console.debug("Clicked on white!"); | |
break; | |
} | |
} | |
} | |
w |= (this.mousePressed?(0x1<<4):0); | |
return (this.joy2Read()|w) & 0xFFFF; | |
} | |
else { | |
return this.joy2Read(); | |
} | |
} | |
break; | |
} | |
return 0; | |
}, | |
regWrite: function(address, value) { | |
switch (address) { | |
case 0x2000: | |
// PPU Control register 1 | |
this.nes.cpu.mem[address] = value; | |
this.nes.ppu.updateControlReg1(value); | |
break; | |
case 0x2001: | |
// PPU Control register 2 | |
this.nes.cpu.mem[address] = value; | |
this.nes.ppu.updateControlReg2(value); | |
break; | |
case 0x2003: | |
// Set Sprite RAM address: | |
this.nes.ppu.writeSRAMAddress(value); | |
break; | |
case 0x2004: | |
// Write to Sprite RAM: | |
this.nes.ppu.sramWrite(value); | |
break; | |
case 0x2005: | |
// Screen Scroll offsets: | |
this.nes.ppu.scrollWrite(value); | |
break; | |
case 0x2006: | |
// Set VRAM address: | |
this.nes.ppu.writeVRAMAddress(value); | |
break; | |
case 0x2007: | |
// Write to VRAM: | |
this.nes.ppu.vramWrite(value); | |
break; | |
case 0x4014: | |
// Sprite Memory DMA Access | |
this.nes.ppu.sramDMA(value); | |
break; | |
case 0x4015: | |
// Sound Channel Switch, DMC Status | |
this.nes.papu.writeReg(address, value); | |
break; | |
case 0x4016: | |
// Joystick 1 + Strobe | |
if ((value&1) === 0 && (this.joypadLastWrite&1) === 1) { | |
this.joy1StrobeState = 0; | |
this.joy2StrobeState = 0; | |
} | |
this.joypadLastWrite = value; | |
break; | |
case 0x4017: | |
// Sound channel frame sequencer: | |
this.nes.papu.writeReg(address, value); | |
break; | |
default: | |
// Sound registers | |
////System.out.println("write to sound reg"); | |
if (address >= 0x4000 && address <= 0x4017) { | |
this.nes.papu.writeReg(address,value); | |
} | |
} | |
}, | |
joy1Read: function() { | |
var ret; | |
switch (this.joy1StrobeState) { | |
case 0: | |
case 1: | |
case 2: | |
case 3: | |
case 4: | |
case 5: | |
case 6: | |
case 7: | |
ret = this.nes.keyboard.state1[this.joy1StrobeState]; | |
break; | |
case 8: | |
case 9: | |
case 10: | |
case 11: | |
case 12: | |
case 13: | |
case 14: | |
case 15: | |
case 16: | |
case 17: | |
case 18: | |
ret = 0; | |
break; | |
case 19: | |
ret = 1; | |
break; | |
default: | |
ret = 0; | |
} | |
this.joy1StrobeState++; | |
if (this.joy1StrobeState == 24) { | |
this.joy1StrobeState = 0; | |
} | |
return ret; | |
}, | |
joy2Read: function() { | |
var ret; | |
switch (this.joy2StrobeState) { | |
case 0: | |
case 1: | |
case 2: | |
case 3: | |
case 4: | |
case 5: | |
case 6: | |
case 7: | |
ret = this.nes.keyboard.state2[this.joy2StrobeState]; | |
break; | |
case 8: | |
case 9: | |
case 10: | |
case 11: | |
case 12: | |
case 13: | |
case 14: | |
case 15: | |
case 16: | |
case 17: | |
case 18: | |
ret = 0; | |
break; | |
case 19: | |
ret = 1; | |
break; | |
default: | |
ret = 0; | |
} | |
this.joy2StrobeState++; | |
if (this.joy2StrobeState == 24) { | |
this.joy2StrobeState = 0; | |
} | |
return ret; | |
}, | |
loadROM: function() { | |
if (!this.nes.rom.valid || this.nes.rom.romCount < 1) { | |
alert("NoMapper: Invalid ROM! Unable to load."); | |
return; | |
} | |
// Load ROM into memory: | |
this.loadPRGROM(); | |
// Load CHR-ROM: | |
this.loadCHRROM(); | |
// Load Battery RAM (if present): | |
this.loadBatteryRam(); | |
// Reset IRQ: | |
//nes.getCpu().doResetInterrupt(); | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_RESET); | |
}, | |
loadPRGROM: function() { | |
if (this.nes.rom.romCount > 1) { | |
// Load the two first banks into memory. | |
this.loadRomBank(0, 0x8000); | |
this.loadRomBank(1, 0xC000); | |
} | |
else { | |
// Load the one bank into both memory locations: | |
this.loadRomBank(0, 0x8000); | |
this.loadRomBank(0, 0xC000); | |
} | |
}, | |
loadCHRROM: function() { | |
////System.out.println("Loading CHR ROM.."); | |
if (this.nes.rom.vromCount > 0) { | |
if (this.nes.rom.vromCount == 1) { | |
this.loadVromBank(0,0x0000); | |
this.loadVromBank(0,0x1000); | |
} | |
else { | |
this.loadVromBank(0,0x0000); | |
this.loadVromBank(1,0x1000); | |
} | |
} | |
else { | |
//System.out.println("There aren't any CHR-ROM banks.."); | |
} | |
}, | |
loadBatteryRam: function() { | |
if (this.nes.rom.batteryRam) { | |
var ram = this.nes.rom.batteryRam; | |
if (ram !== null && ram.length == 0x2000) { | |
// Load Battery RAM into memory: | |
JSNES.Utils.copyArrayElements(ram, 0, this.nes.cpu.mem, 0x6000, 0x2000); | |
} | |
} | |
}, | |
loadRomBank: function(bank, address) { | |
// Loads a ROM bank into the specified address. | |
bank %= this.nes.rom.romCount; | |
//var data = this.nes.rom.rom[bank]; | |
//cpuMem.write(address,data,data.length); | |
JSNES.Utils.copyArrayElements(this.nes.rom.rom[bank], 0, this.nes.cpu.mem, address, 16384); | |
}, | |
loadVromBank: function(bank, address) { | |
if (this.nes.rom.vromCount === 0) { | |
return; | |
} | |
this.nes.ppu.triggerRendering(); | |
JSNES.Utils.copyArrayElements(this.nes.rom.vrom[bank % this.nes.rom.vromCount], | |
0, this.nes.ppu.vramMem, address, 4096); | |
var vromTile = this.nes.rom.vromTile[bank % this.nes.rom.vromCount]; | |
JSNES.Utils.copyArrayElements(vromTile, 0, this.nes.ppu.ptTile,address >> 4, 256); | |
}, | |
load32kRomBank: function(bank, address) { | |
this.loadRomBank((bank*2) % this.nes.rom.romCount, address); | |
this.loadRomBank((bank*2+1) % this.nes.rom.romCount, address+16384); | |
}, | |
load8kVromBank: function(bank4kStart, address) { | |
if (this.nes.rom.vromCount === 0) { | |
return; | |
} | |
this.nes.ppu.triggerRendering(); | |
this.loadVromBank((bank4kStart) % this.nes.rom.vromCount, address); | |
this.loadVromBank((bank4kStart + 1) % this.nes.rom.vromCount, | |
address + 4096); | |
}, | |
load1kVromBank: function(bank1k, address) { | |
if (this.nes.rom.vromCount === 0) { | |
return; | |
} | |
this.nes.ppu.triggerRendering(); | |
var bank4k = Math.floor(bank1k / 4) % this.nes.rom.vromCount; | |
var bankoffset = (bank1k % 4) * 1024; | |
JSNES.Utils.copyArrayElements(this.nes.rom.vrom[bank4k], 0, | |
this.nes.ppu.vramMem, bankoffset, 1024); | |
// Update tiles: | |
var vromTile = this.nes.rom.vromTile[bank4k]; | |
var baseIndex = address >> 4; | |
for (var i = 0; i < 64; i++) { | |
this.nes.ppu.ptTile[baseIndex+i] = vromTile[((bank1k%4) << 6) + i]; | |
} | |
}, | |
load2kVromBank: function(bank2k, address) { | |
if (this.nes.rom.vromCount === 0) { | |
return; | |
} | |
this.nes.ppu.triggerRendering(); | |
var bank4k = Math.floor(bank2k / 2) % this.nes.rom.vromCount; | |
var bankoffset = (bank2k % 2) * 2048; | |
JSNES.Utils.copyArrayElements(this.nes.rom.vrom[bank4k], bankoffset, | |
this.nes.ppu.vramMem, address, 2048); | |
// Update tiles: | |
var vromTile = this.nes.rom.vromTile[bank4k]; | |
var baseIndex = address >> 4; | |
for (var i = 0; i < 128; i++) { | |
this.nes.ppu.ptTile[baseIndex+i] = vromTile[((bank2k%2) << 7) + i]; | |
} | |
}, | |
load8kRomBank: function(bank8k, address) { | |
var bank16k = Math.floor(bank8k / 2) % this.nes.rom.romCount; | |
var offset = (bank8k % 2) * 8192; | |
//this.nes.cpu.mem.write(address,this.nes.rom.rom[bank16k],offset,8192); | |
JSNES.Utils.copyArrayElements(this.nes.rom.rom[bank16k], offset, | |
this.nes.cpu.mem, address, 8192); | |
}, | |
clockIrqCounter: function() { | |
// Does nothing. This is used by the MMC3 mapper. | |
}, | |
latchAccess: function(address) { | |
// Does nothing. This is used by MMC2. | |
}, | |
toJSON: function() { | |
return { | |
'joy1StrobeState': this.joy1StrobeState, | |
'joy2StrobeState': this.joy2StrobeState, | |
'joypadLastWrite': this.joypadLastWrite | |
}; | |
}, | |
fromJSON: function(s) { | |
this.joy1StrobeState = s.joy1StrobeState; | |
this.joy2StrobeState = s.joy2StrobeState; | |
this.joypadLastWrite = s.joypadLastWrite; | |
} | |
}; | |
JSNES.Mappers[1] = function(nes) { | |
this.nes = nes; | |
}; | |
JSNES.Mappers[1].prototype = new JSNES.Mappers[0](); | |
JSNES.Mappers[1].prototype.reset = function() { | |
JSNES.Mappers[0].prototype.reset.apply(this); | |
// 5-bit buffer: | |
this.regBuffer = 0; | |
this.regBufferCounter = 0; | |
// Register 0: | |
this.mirroring = 0; | |
this.oneScreenMirroring = 0; | |
this.prgSwitchingArea = 1; | |
this.prgSwitchingSize = 1; | |
this.vromSwitchingSize = 0; | |
// Register 1: | |
this.romSelectionReg0 = 0; | |
// Register 2: | |
this.romSelectionReg1 = 0; | |
// Register 3: | |
this.romBankSelect = 0; | |
}; | |
JSNES.Mappers[1].prototype.write = function(address, value) { | |
// Writes to addresses other than MMC registers are handled by NoMapper. | |
if (address < 0x8000) { | |
JSNES.Mappers[0].prototype.write.apply(this, arguments); | |
return; | |
} | |
// See what should be done with the written value: | |
if ((value & 128) !== 0) { | |
// Reset buffering: | |
this.regBufferCounter = 0; | |
this.regBuffer = 0; | |
// Reset register: | |
if (this.getRegNumber(address) === 0) { | |
this.prgSwitchingArea = 1; | |
this.prgSwitchingSize = 1; | |
} | |
} | |
else { | |
// Continue buffering: | |
//regBuffer = (regBuffer & (0xFF-(1<<regBufferCounter))) | ((value & (1<<regBufferCounter))<<regBufferCounter); | |
this.regBuffer = (this.regBuffer & (0xFF - (1 << this.regBufferCounter))) | ((value & 1) << this.regBufferCounter); | |
this.regBufferCounter++; | |
if (this.regBufferCounter == 5) { | |
// Use the buffered value: | |
this.setReg(this.getRegNumber(address), this.regBuffer); | |
// Reset buffer: | |
this.regBuffer = 0; | |
this.regBufferCounter = 0; | |
} | |
} | |
}; | |
JSNES.Mappers[1].prototype.setReg = function(reg, value) { | |
var tmp; | |
switch (reg) { | |
case 0: | |
// Mirroring: | |
tmp = value & 3; | |
if (tmp !== this.mirroring) { | |
// Set mirroring: | |
this.mirroring = tmp; | |
if ((this.mirroring & 2) === 0) { | |
// SingleScreen mirroring overrides the other setting: | |
this.nes.ppu.setMirroring( | |
this.nes.rom.SINGLESCREEN_MIRRORING); | |
} | |
// Not overridden by SingleScreen mirroring. | |
else if ((this.mirroring & 1) !== 0) { | |
this.nes.ppu.setMirroring( | |
this.nes.rom.HORIZONTAL_MIRRORING | |
); | |
} | |
else { | |
this.nes.ppu.setMirroring(this.nes.rom.VERTICAL_MIRRORING); | |
} | |
} | |
// PRG Switching Area; | |
this.prgSwitchingArea = (value >> 2) & 1; | |
// PRG Switching Size: | |
this.prgSwitchingSize = (value >> 3) & 1; | |
// VROM Switching Size: | |
this.vromSwitchingSize = (value >> 4) & 1; | |
break; | |
case 1: | |
// ROM selection: | |
this.romSelectionReg0 = (value >> 4) & 1; | |
// Check whether the cart has VROM: | |
if (this.nes.rom.vromCount > 0) { | |
// Select VROM bank at 0x0000: | |
if (this.vromSwitchingSize === 0) { | |
// Swap 8kB VROM: | |
if (this.romSelectionReg0 === 0) { | |
this.load8kVromBank((value & 0xF), 0x0000); | |
} | |
else { | |
this.load8kVromBank( | |
Math.floor(this.nes.rom.vromCount / 2) + | |
(value & 0xF), | |
0x0000 | |
); | |
} | |
} | |
else { | |
// Swap 4kB VROM: | |
if (this.romSelectionReg0 === 0) { | |
this.loadVromBank((value & 0xF), 0x0000); | |
} | |
else { | |
this.loadVromBank( | |
Math.floor(this.nes.rom.vromCount / 2) + | |
(value & 0xF), | |
0x0000 | |
); | |
} | |
} | |
} | |
break; | |
case 2: | |
// ROM selection: | |
this.romSelectionReg1 = (value >> 4) & 1; | |
// Check whether the cart has VROM: | |
if (this.nes.rom.vromCount > 0) { | |
// Select VROM bank at 0x1000: | |
if (this.vromSwitchingSize === 1) { | |
// Swap 4kB of VROM: | |
if (this.romSelectionReg1 === 0) { | |
this.loadVromBank((value & 0xF), 0x1000); | |
} | |
else { | |
this.loadVromBank( | |
Math.floor(this.nes.rom.vromCount / 2) + | |
(value & 0xF), | |
0x1000 | |
); | |
} | |
} | |
} | |
break; | |
default: | |
// Select ROM bank: | |
// ------------------------- | |
tmp = value & 0xF; | |
var bank; | |
var baseBank = 0; | |
if (this.nes.rom.romCount >= 32) { | |
// 1024 kB cart | |
if (this.vromSwitchingSize === 0) { | |
if (this.romSelectionReg0 === 1) { | |
baseBank = 16; | |
} | |
} | |
else { | |
baseBank = (this.romSelectionReg0 | |
| (this.romSelectionReg1 << 1)) << 3; | |
} | |
} | |
else if (this.nes.rom.romCount >= 16) { | |
// 512 kB cart | |
if (this.romSelectionReg0 === 1) { | |
baseBank = 8; | |
} | |
} | |
if (this.prgSwitchingSize === 0) { | |
// 32kB | |
bank = baseBank + (value & 0xF); | |
this.load32kRomBank(bank, 0x8000); | |
} | |
else { | |
// 16kB | |
bank = baseBank * 2 + (value & 0xF); | |
if (this.prgSwitchingArea === 0) { | |
this.loadRomBank(bank, 0xC000); | |
} | |
else { | |
this.loadRomBank(bank, 0x8000); | |
} | |
} | |
} | |
}; | |
// Returns the register number from the address written to: | |
JSNES.Mappers[1].prototype.getRegNumber = function(address) { | |
if (address >= 0x8000 && address <= 0x9FFF) { | |
return 0; | |
} | |
else if (address >= 0xA000 && address <= 0xBFFF) { | |
return 1; | |
} | |
else if (address >= 0xC000 && address <= 0xDFFF) { | |
return 2; | |
} | |
else { | |
return 3; | |
} | |
}; | |
JSNES.Mappers[1].prototype.loadROM = function(rom) { | |
if (!this.nes.rom.valid) { | |
alert("MMC1: Invalid ROM! Unable to load."); | |
return; | |
} | |
// Load PRG-ROM: | |
this.loadRomBank(0, 0x8000); // First ROM bank.. | |
this.loadRomBank(this.nes.rom.romCount - 1, 0xC000); // ..and last ROM bank. | |
// Load CHR-ROM: | |
this.loadCHRROM(); | |
// Load Battery RAM (if present): | |
this.loadBatteryRam(); | |
// Do Reset-Interrupt: | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_RESET); | |
}; | |
JSNES.Mappers[1].prototype.switchLowHighPrgRom = function(oldSetting) { | |
// not yet. | |
}; | |
JSNES.Mappers[1].prototype.switch16to32 = function() { | |
// not yet. | |
}; | |
JSNES.Mappers[1].prototype.switch32to16 = function() { | |
// not yet. | |
}; | |
JSNES.Mappers[1].prototype.toJSON = function() { | |
var s = JSNES.Mappers[0].prototype.toJSON.apply(this); | |
s.mirroring = this.mirroring; | |
s.oneScreenMirroring = this.oneScreenMirroring; | |
s.prgSwitchingArea = this.prgSwitchingArea; | |
s.prgSwitchingSize = this.prgSwitchingSize; | |
s.vromSwitchingSize = this.vromSwitchingSize; | |
s.romSelectionReg0 = this.romSelectionReg0; | |
s.romSelectionReg1 = this.romSelectionReg1; | |
s.romBankSelect = this.romBankSelect; | |
s.regBuffer = this.regBuffer; | |
s.regBufferCounter = this.regBufferCounter; | |
return s; | |
}; | |
JSNES.Mappers[1].prototype.fromJSON = function(s) { | |
JSNES.Mappers[0].prototype.fromJSON.apply(this, s); | |
this.mirroring = s.mirroring; | |
this.oneScreenMirroring = s.oneScreenMirroring; | |
this.prgSwitchingArea = s.prgSwitchingArea; | |
this.prgSwitchingSize = s.prgSwitchingSize; | |
this.vromSwitchingSize = s.vromSwitchingSize; | |
this.romSelectionReg0 = s.romSelectionReg0; | |
this.romSelectionReg1 = s.romSelectionReg1; | |
this.romBankSelect = s.romBankSelect; | |
this.regBuffer = s.regBuffer; | |
this.regBufferCounter = s.regBufferCounter; | |
}; | |
JSNES.Mappers[2] = function(nes) { | |
this.nes = nes; | |
}; | |
JSNES.Mappers[2].prototype = new JSNES.Mappers[0](); | |
JSNES.Mappers[2].prototype.write = function(address, value) { | |
// Writes to addresses other than MMC registers are handled by NoMapper. | |
if (address < 0x8000) { | |
JSNES.Mappers[0].prototype.write.apply(this, arguments); | |
return; | |
} | |
else { | |
// This is a ROM bank select command. | |
// Swap in the given ROM bank at 0x8000: | |
this.loadRomBank(value, 0x8000); | |
} | |
}; | |
JSNES.Mappers[2].prototype.loadROM = function(rom) { | |
if (!this.nes.rom.valid) { | |
alert("UNROM: Invalid ROM! Unable to load."); | |
return; | |
} | |
// Load PRG-ROM: | |
this.loadRomBank(0, 0x8000); | |
this.loadRomBank(this.nes.rom.romCount - 1, 0xC000); | |
// Load CHR-ROM: | |
this.loadCHRROM(); | |
// Do Reset-Interrupt: | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_RESET); | |
}; | |
JSNES.Mappers[4] = function(nes) { | |
this.nes = nes; | |
this.CMD_SEL_2_1K_VROM_0000 = 0; | |
this.CMD_SEL_2_1K_VROM_0800 = 1; | |
this.CMD_SEL_1K_VROM_1000 = 2; | |
this.CMD_SEL_1K_VROM_1400 = 3; | |
this.CMD_SEL_1K_VROM_1800 = 4; | |
this.CMD_SEL_1K_VROM_1C00 = 5; | |
this.CMD_SEL_ROM_PAGE1 = 6; | |
this.CMD_SEL_ROM_PAGE2 = 7; | |
this.command = null; | |
this.prgAddressSelect = null; | |
this.chrAddressSelect = null; | |
this.pageNumber = null; | |
this.irqCounter = null; | |
this.irqLatchValue = null; | |
this.irqEnable = null; | |
this.prgAddressChanged = false; | |
}; | |
JSNES.Mappers[4].prototype = new JSNES.Mappers[0](); | |
JSNES.Mappers[4].prototype.write = function(address, value) { | |
// Writes to addresses other than MMC registers are handled by NoMapper. | |
if (address < 0x8000) { | |
JSNES.Mappers[0].prototype.write.apply(this, arguments); | |
return; | |
} | |
switch (address) { | |
case 0x8000: | |
// Command/Address Select register | |
this.command = value & 7; | |
var tmp = (value >> 6) & 1; | |
if (tmp != this.prgAddressSelect) { | |
this.prgAddressChanged = true; | |
} | |
this.prgAddressSelect = tmp; | |
this.chrAddressSelect = (value >> 7) & 1; | |
break; | |
case 0x8001: | |
// Page number for command | |
this.executeCommand(this.command, value); | |
break; | |
case 0xA000: | |
// Mirroring select | |
if ((value & 1) !== 0) { | |
this.nes.ppu.setMirroring( | |
this.nes.rom.HORIZONTAL_MIRRORING | |
); | |
} | |
else { | |
this.nes.ppu.setMirroring(this.nes.rom.VERTICAL_MIRRORING); | |
} | |
break; | |
case 0xA001: | |
// SaveRAM Toggle | |
// TODO | |
//nes.getRom().setSaveState((value&1)!=0); | |
break; | |
case 0xC000: | |
// IRQ Counter register | |
this.irqCounter = value; | |
//nes.ppu.mapperIrqCounter = 0; | |
break; | |
case 0xC001: | |
// IRQ Latch register | |
this.irqLatchValue = value; | |
break; | |
case 0xE000: | |
// IRQ Control Reg 0 (disable) | |
//irqCounter = irqLatchValue; | |
this.irqEnable = 0; | |
break; | |
case 0xE001: | |
// IRQ Control Reg 1 (enable) | |
this.irqEnable = 1; | |
break; | |
default: | |
// Not a MMC3 register. | |
// The game has probably crashed, | |
// since it tries to write to ROM.. | |
// IGNORE. | |
} | |
}; | |
JSNES.Mappers[4].prototype.executeCommand = function(cmd, arg) { | |
switch (cmd) { | |
case this.CMD_SEL_2_1K_VROM_0000: | |
// Select 2 1KB VROM pages at 0x0000: | |
if (this.chrAddressSelect === 0) { | |
this.load1kVromBank(arg, 0x0000); | |
this.load1kVromBank(arg + 1, 0x0400); | |
} | |
else { | |
this.load1kVromBank(arg, 0x1000); | |
this.load1kVromBank(arg + 1, 0x1400); | |
} | |
break; | |
case this.CMD_SEL_2_1K_VROM_0800: | |
// Select 2 1KB VROM pages at 0x0800: | |
if (this.chrAddressSelect === 0) { | |
this.load1kVromBank(arg, 0x0800); | |
this.load1kVromBank(arg + 1, 0x0C00); | |
} | |
else { | |
this.load1kVromBank(arg, 0x1800); | |
this.load1kVromBank(arg + 1, 0x1C00); | |
} | |
break; | |
case this.CMD_SEL_1K_VROM_1000: | |
// Select 1K VROM Page at 0x1000: | |
if (this.chrAddressSelect === 0) { | |
this.load1kVromBank(arg, 0x1000); | |
} | |
else { | |
this.load1kVromBank(arg, 0x0000); | |
} | |
break; | |
case this.CMD_SEL_1K_VROM_1400: | |
// Select 1K VROM Page at 0x1400: | |
if (this.chrAddressSelect === 0) { | |
this.load1kVromBank(arg, 0x1400); | |
} | |
else { | |
this.load1kVromBank(arg, 0x0400); | |
} | |
break; | |
case this.CMD_SEL_1K_VROM_1800: | |
// Select 1K VROM Page at 0x1800: | |
if (this.chrAddressSelect === 0) { | |
this.load1kVromBank(arg, 0x1800); | |
} | |
else { | |
this.load1kVromBank(arg, 0x0800); | |
} | |
break; | |
case this.CMD_SEL_1K_VROM_1C00: | |
// Select 1K VROM Page at 0x1C00: | |
if (this.chrAddressSelect === 0) { | |
this.load1kVromBank(arg, 0x1C00); | |
}else { | |
this.load1kVromBank(arg, 0x0C00); | |
} | |
break; | |
case this.CMD_SEL_ROM_PAGE1: | |
if (this.prgAddressChanged) { | |
// Load the two hardwired banks: | |
if (this.prgAddressSelect === 0) { | |
this.load8kRomBank( | |
((this.nes.rom.romCount - 1) * 2), | |
0xC000 | |
); | |
} | |
else { | |
this.load8kRomBank( | |
((this.nes.rom.romCount - 1) * 2), | |
0x8000 | |
); | |
} | |
this.prgAddressChanged = false; | |
} | |
// Select first switchable ROM page: | |
if (this.prgAddressSelect === 0) { | |
this.load8kRomBank(arg, 0x8000); | |
} | |
else { | |
this.load8kRomBank(arg, 0xC000); | |
} | |
break; | |
case this.CMD_SEL_ROM_PAGE2: | |
// Select second switchable ROM page: | |
this.load8kRomBank(arg, 0xA000); | |
// hardwire appropriate bank: | |
if (this.prgAddressChanged) { | |
// Load the two hardwired banks: | |
if (this.prgAddressSelect === 0) { | |
this.load8kRomBank( | |
((this.nes.rom.romCount - 1) * 2), | |
0xC000 | |
); | |
} | |
else { | |
this.load8kRomBank( | |
((this.nes.rom.romCount - 1) * 2), | |
0x8000 | |
); | |
} | |
this.prgAddressChanged = false; | |
} | |
} | |
}; | |
JSNES.Mappers[4].prototype.loadROM = function(rom) { | |
if (!this.nes.rom.valid) { | |
alert("MMC3: Invalid ROM! Unable to load."); | |
return; | |
} | |
// Load hardwired PRG banks (0xC000 and 0xE000): | |
this.load8kRomBank(((this.nes.rom.romCount - 1) * 2), 0xC000); | |
this.load8kRomBank(((this.nes.rom.romCount - 1) * 2) + 1, 0xE000); | |
// Load swappable PRG banks (0x8000 and 0xA000): | |
this.load8kRomBank(0, 0x8000); | |
this.load8kRomBank(1, 0xA000); | |
// Load CHR-ROM: | |
this.loadCHRROM(); | |
// Load Battery RAM (if present): | |
this.loadBatteryRam(); | |
// Do Reset-Interrupt: | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_RESET); | |
}; | |
JSNES.Mappers[4].prototype.clockIrqCounter = function() { | |
if (this.irqEnable == 1) { | |
this.irqCounter--; | |
if (this.irqCounter < 0) { | |
// Trigger IRQ: | |
//nes.getCpu().doIrq(); | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_NORMAL); | |
this.irqCounter = this.irqLatchValue; | |
} | |
} | |
}; | |
JSNES.Mappers[4].prototype.toJSON = function() { | |
var s = JSNES.Mappers[0].prototype.toJSON.apply(this); | |
s.command = this.command; | |
s.prgAddressSelect = this.prgAddressSelect; | |
s.chrAddressSelect = this.chrAddressSelect; | |
s.pageNumber = this.pageNumber; | |
s.irqCounter = this.irqCounter; | |
s.irqLatchValue = this.irqLatchValue; | |
s.irqEnable = this.irqEnable; | |
s.prgAddressChanged = this.prgAddressChanged; | |
return s; | |
}; | |
JSNES.Mappers[4].prototype.fromJSON = function(s) { | |
JSNES.Mappers[0].prototype.fromJSON.apply(this, s); | |
this.command = s.command; | |
this.prgAddressSelect = s.prgAddressSelect; | |
this.chrAddressSelect = s.chrAddressSelect; | |
this.pageNumber = s.pageNumber; | |
this.irqCounter = s.irqCounter; | |
this.irqLatchValue = s.irqLatchValue; | |
this.irqEnable = s.irqEnable; | |
this.prgAddressChanged = s.prgAddressChanged; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
var JSNES = function(opts) { | |
this.opts = { | |
ui: JSNES.DummyUI, | |
swfPath: 'lib/', | |
preferredFrameRate: 60, | |
fpsInterval: 500, // Time between updating FPS in ms | |
showDisplay: true, | |
emulateSound: false, | |
sampleRate: 44100, // Sound sample rate in hz | |
CPU_FREQ_NTSC: 1789772.5, //1789772.72727272d; | |
CPU_FREQ_PAL: 1773447.4 | |
}; | |
if (typeof opts != 'undefined') { | |
var key; | |
for (key in this.opts) { | |
if (typeof opts[key] != 'undefined') { | |
this.opts[key] = opts[key]; | |
} | |
} | |
} | |
this.frameTime = 1000 / this.opts.preferredFrameRate; | |
this.ui = new this.opts.ui(this); | |
this.cpu = new JSNES.CPU(this); | |
this.ppu = new JSNES.PPU(this); | |
this.papu = new JSNES.PAPU(this); | |
this.mmap = null; // set in loadRom() | |
this.keyboard = new JSNES.Keyboard(); | |
this.ui.updateStatus("Ready to load a ROM."); | |
}; | |
JSNES.VERSION = "<%= version %>"; | |
JSNES.prototype = { | |
isRunning: false, | |
fpsFrameCount: 0, | |
romData: null, | |
// Resets the system | |
reset: function() { | |
if (this.mmap !== null) { | |
this.mmap.reset(); | |
} | |
this.cpu.reset(); | |
this.ppu.reset(); | |
this.papu.reset(); | |
}, | |
start: function() { | |
var self = this; | |
if (this.rom !== null && this.rom.valid) { | |
if (!this.isRunning) { | |
this.isRunning = true; | |
this.frameInterval = setInterval(function() { | |
self.frame(); | |
}, this.frameTime); | |
this.resetFps(); | |
this.printFps(); | |
this.fpsInterval = setInterval(function() { | |
self.printFps(); | |
}, this.opts.fpsInterval); | |
} | |
} | |
else { | |
this.ui.updateStatus("There is no ROM loaded, or it is invalid."); | |
} | |
}, | |
frame: function() { | |
this.ppu.startFrame(); | |
var cycles = 0; | |
var emulateSound = this.opts.emulateSound; | |
var cpu = this.cpu; | |
var ppu = this.ppu; | |
var papu = this.papu; | |
FRAMELOOP: for (;;) { | |
if (cpu.cyclesToHalt === 0) { | |
// Execute a CPU instruction | |
cycles = cpu.emulate(); | |
if (emulateSound) { | |
papu.clockFrameCounter(cycles); | |
} | |
cycles *= 3; | |
} | |
else { | |
if (cpu.cyclesToHalt > 8) { | |
cycles = 24; | |
if (emulateSound) { | |
papu.clockFrameCounter(8); | |
} | |
cpu.cyclesToHalt -= 8; | |
} | |
else { | |
cycles = cpu.cyclesToHalt * 3; | |
if (emulateSound) { | |
papu.clockFrameCounter(cpu.cyclesToHalt); | |
} | |
cpu.cyclesToHalt = 0; | |
} | |
} | |
for (; cycles > 0; cycles--) { | |
if(ppu.curX === ppu.spr0HitX && | |
ppu.f_spVisibility === 1 && | |
ppu.scanline - 21 === ppu.spr0HitY) { | |
// Set sprite 0 hit flag: | |
ppu.setStatusFlag(ppu.STATUS_SPRITE0HIT, true); | |
} | |
if (ppu.requestEndFrame) { | |
ppu.nmiCounter--; | |
if (ppu.nmiCounter === 0) { | |
ppu.requestEndFrame = false; | |
ppu.startVBlank(); | |
break FRAMELOOP; | |
} | |
} | |
ppu.curX++; | |
if (ppu.curX === 341) { | |
ppu.curX = 0; | |
ppu.endScanline(); | |
} | |
} | |
} | |
this.fpsFrameCount++; | |
this.lastFrameTime = +new Date(); | |
}, | |
printFps: function() { | |
var now = +new Date(); | |
var s = 'Running'; | |
if (this.lastFpsTime) { | |
s += ': '+( | |
this.fpsFrameCount / ((now - this.lastFpsTime) / 1000) | |
).toFixed(2)+' FPS'; | |
} | |
this.ui.updateStatus(s); | |
this.fpsFrameCount = 0; | |
this.lastFpsTime = now; | |
}, | |
stop: function() { | |
clearInterval(this.frameInterval); | |
clearInterval(this.fpsInterval); | |
this.isRunning = false; | |
}, | |
reloadRom: function() { | |
if (this.romData !== null) { | |
this.loadRom(this.romData); | |
} | |
}, | |
// Loads a ROM file into the CPU and PPU. | |
// The ROM file is validated first. | |
loadRom: function(data) { | |
if (this.isRunning) { | |
this.stop(); | |
} | |
this.ui.updateStatus("Loading ROM..."); | |
// Load ROM file: | |
this.rom = new JSNES.ROM(this); | |
this.rom.load(data); | |
if (this.rom.valid) { | |
this.reset(); | |
this.mmap = this.rom.createMapper(); | |
if (!this.mmap) { | |
return; | |
} | |
this.mmap.loadROM(); | |
this.ppu.setMirroring(this.rom.getMirroringType()); | |
this.romData = data; | |
this.ui.updateStatus("Successfully loaded. Ready to be started."); | |
} | |
else { | |
this.ui.updateStatus("Invalid ROM!"); | |
} | |
return this.rom.valid; | |
}, | |
resetFps: function() { | |
this.lastFpsTime = null; | |
this.fpsFrameCount = 0; | |
}, | |
setFramerate: function(rate){ | |
this.opts.preferredFrameRate = rate; | |
this.frameTime = 1000 / rate; | |
this.papu.setSampleRate(this.opts.sampleRate, false); | |
}, | |
toJSON: function() { | |
return { | |
'romData': this.romData, | |
'cpu': this.cpu.toJSON(), | |
'mmap': this.mmap.toJSON(), | |
'ppu': this.ppu.toJSON() | |
}; | |
}, | |
fromJSON: function(s) { | |
this.loadRom(s.romData); | |
this.cpu.fromJSON(s.cpu); | |
this.mmap.fromJSON(s.mmap); | |
this.ppu.fromJSON(s.ppu); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.PAPU = function(nes) { | |
this.nes = nes; | |
this.square1 = new JSNES.PAPU.ChannelSquare(this, true); | |
this.square2 = new JSNES.PAPU.ChannelSquare(this, false); | |
this.triangle = new JSNES.PAPU.ChannelTriangle(this); | |
this.noise = new JSNES.PAPU.ChannelNoise(this); | |
this.dmc = new JSNES.PAPU.ChannelDM(this); | |
this.frameIrqCounter = null; | |
this.frameIrqCounterMax = 4; | |
this.initCounter = 2048; | |
this.channelEnableValue = null; | |
this.bufferSize = 8192; | |
this.bufferIndex = 0; | |
this.sampleRate = 44100; | |
this.lengthLookup = null; | |
this.dmcFreqLookup = null; | |
this.noiseWavelengthLookup = null; | |
this.square_table = null; | |
this.tnd_table = null; | |
this.sampleBuffer = new Array(this.bufferSize*2); | |
this.frameIrqEnabled = false; | |
this.frameIrqActive = null; | |
this.frameClockNow = null; | |
this.startedPlaying=false; | |
this.recordOutput = false; | |
this.initingHardware = false; | |
this.masterFrameCounter = null; | |
this.derivedFrameCounter = null; | |
this.countSequence = null; | |
this.sampleTimer = null; | |
this.frameTime = null; | |
this.sampleTimerMax = null; | |
this.sampleCount = null; | |
this.triValue = 0; | |
this.smpSquare1 = null; | |
this.smpSquare2 = null; | |
this.smpTriangle = null; | |
this.smpDmc = null; | |
this.accCount = null; | |
// DC removal vars: | |
this.prevSampleL = 0; | |
this.prevSampleR = 0; | |
this.smpAccumL = 0; | |
this.smpAccumR = 0; | |
// DAC range: | |
this.dacRange = 0; | |
this.dcValue = 0; | |
// Master volume: | |
this.masterVolume = 256; | |
// Stereo positioning: | |
this.stereoPosLSquare1 = null; | |
this.stereoPosLSquare2 = null; | |
this.stereoPosLTriangle = null; | |
this.stereoPosLNoise = null; | |
this.stereoPosLDMC = null; | |
this.stereoPosRSquare1 = null; | |
this.stereoPosRSquare2 = null; | |
this.stereoPosRTriangle = null; | |
this.stereoPosRNoise = null; | |
this.stereoPosRDMC = null; | |
this.extraCycles = null; | |
this.maxSample = null; | |
this.minSample = null; | |
// Panning: | |
this.panning = [80, 170, 100, 150, 128]; | |
this.setPanning(this.panning); | |
// Initialize lookup tables: | |
this.initLengthLookup(); | |
this.initDmcFrequencyLookup(); | |
this.initNoiseWavelengthLookup(); | |
this.initDACtables(); | |
// Init sound registers: | |
for (var i = 0; i < 0x14; i++) { | |
if (i === 0x10){ | |
this.writeReg(0x4010, 0x10); | |
} | |
else { | |
this.writeReg(0x4000 + i, 0); | |
} | |
} | |
this.reset(); | |
}; | |
JSNES.PAPU.prototype = { | |
reset: function() { | |
this.sampleRate = this.nes.opts.sampleRate; | |
this.sampleTimerMax = Math.floor( | |
(1024.0 * this.nes.opts.CPU_FREQ_NTSC * | |
this.nes.opts.preferredFrameRate) / | |
(this.sampleRate * 60.0) | |
); | |
this.frameTime = Math.floor( | |
(14915.0 * this.nes.opts.preferredFrameRate) / 60.0 | |
); | |
this.sampleTimer = 0; | |
this.bufferIndex = 0; | |
this.updateChannelEnable(0); | |
this.masterFrameCounter = 0; | |
this.derivedFrameCounter = 0; | |
this.countSequence = 0; | |
this.sampleCount = 0; | |
this.initCounter = 2048; | |
this.frameIrqEnabled = false; | |
this.initingHardware = false; | |
this.resetCounter(); | |
this.square1.reset(); | |
this.square2.reset(); | |
this.triangle.reset(); | |
this.noise.reset(); | |
this.dmc.reset(); | |
this.bufferIndex = 0; | |
this.accCount = 0; | |
this.smpSquare1 = 0; | |
this.smpSquare2 = 0; | |
this.smpTriangle = 0; | |
this.smpDmc = 0; | |
this.frameIrqEnabled = false; | |
this.frameIrqCounterMax = 4; | |
this.channelEnableValue = 0xFF; | |
this.startedPlaying = false; | |
this.prevSampleL = 0; | |
this.prevSampleR = 0; | |
this.smpAccumL = 0; | |
this.smpAccumR = 0; | |
this.maxSample = -500000; | |
this.minSample = 500000; | |
}, | |
readReg: function(address){ | |
// Read 0x4015: | |
var tmp = 0; | |
tmp |= (this.square1.getLengthStatus() ); | |
tmp |= (this.square2.getLengthStatus() <<1); | |
tmp |= (this.triangle.getLengthStatus()<<2); | |
tmp |= (this.noise.getLengthStatus() <<3); | |
tmp |= (this.dmc.getLengthStatus() <<4); | |
tmp |= (((this.frameIrqActive && this.frameIrqEnabled)? 1 : 0) << 6); | |
tmp |= (this.dmc.getIrqStatus() <<7); | |
this.frameIrqActive = false; | |
this.dmc.irqGenerated = false; | |
return tmp & 0xFFFF; | |
}, | |
writeReg: function(address, value){ | |
if (address >= 0x4000 && address < 0x4004) { | |
// Square Wave 1 Control | |
this.square1.writeReg(address, value); | |
////System.out.println("Square Write"); | |
} | |
else if (address >= 0x4004 && address < 0x4008) { | |
// Square 2 Control | |
this.square2.writeReg(address, value); | |
} | |
else if (address >= 0x4008 && address < 0x400C) { | |
// Triangle Control | |
this.triangle.writeReg(address, value); | |
} | |
else if (address >= 0x400C && address <= 0x400F) { | |
// Noise Control | |
this.noise.writeReg(address, value); | |
} | |
else if (address === 0x4010){ | |
// DMC Play mode & DMA frequency | |
this.dmc.writeReg(address, value); | |
} | |
else if (address === 0x4011){ | |
// DMC Delta Counter | |
this.dmc.writeReg(address, value); | |
} | |
else if (address === 0x4012){ | |
// DMC Play code starting address | |
this.dmc.writeReg(address, value); | |
} | |
else if (address === 0x4013){ | |
// DMC Play code length | |
this.dmc.writeReg(address, value); | |
} | |
else if (address === 0x4015){ | |
// Channel enable | |
this.updateChannelEnable(value); | |
if (value !== 0 && this.initCounter > 0) { | |
// Start hardware initialization | |
this.initingHardware = true; | |
} | |
// DMC/IRQ Status | |
this.dmc.writeReg(address, value); | |
} | |
else if (address === 0x4017) { | |
// Frame counter control | |
this.countSequence = (value>>7)&1; | |
this.masterFrameCounter = 0; | |
this.frameIrqActive = false; | |
if (((value>>6)&0x1)===0){ | |
this.frameIrqEnabled = true; | |
} | |
else { | |
this.frameIrqEnabled = false; | |
} | |
if (this.countSequence === 0) { | |
// NTSC: | |
this.frameIrqCounterMax = 4; | |
this.derivedFrameCounter = 4; | |
} | |
else { | |
// PAL: | |
this.frameIrqCounterMax = 5; | |
this.derivedFrameCounter = 0; | |
this.frameCounterTick(); | |
} | |
} | |
}, | |
resetCounter: function(){ | |
if (this.countSequence === 0) { | |
this.derivedFrameCounter = 4; | |
}else{ | |
this.derivedFrameCounter = 0; | |
} | |
}, | |
// Updates channel enable status. | |
// This is done on writes to the | |
// channel enable register (0x4015), | |
// and when the user enables/disables channels | |
// in the GUI. | |
updateChannelEnable: function(value){ | |
this.channelEnableValue = value&0xFFFF; | |
this.square1.setEnabled((value&1) !== 0); | |
this.square2.setEnabled((value&2) !== 0); | |
this.triangle.setEnabled((value&4) !== 0); | |
this.noise.setEnabled((value&8) !== 0); | |
this.dmc.setEnabled((value&16) !== 0); | |
}, | |
// Clocks the frame counter. It should be clocked at | |
// twice the cpu speed, so the cycles will be | |
// divided by 2 for those counters that are | |
// clocked at cpu speed. | |
clockFrameCounter: function(nCycles){ | |
if (this.initCounter > 0) { | |
if (this.initingHardware) { | |
this.initCounter -= nCycles; | |
if (this.initCounter <= 0) { | |
this.initingHardware = false; | |
} | |
return; | |
} | |
} | |
// Don't process ticks beyond next sampling: | |
nCycles += this.extraCycles; | |
var maxCycles = this.sampleTimerMax-this.sampleTimer; | |
if ((nCycles<<10) > maxCycles) { | |
this.extraCycles = ((nCycles<<10) - maxCycles)>>10; | |
nCycles -= this.extraCycles; | |
}else{ | |
this.extraCycles = 0; | |
} | |
var dmc = this.dmc; | |
var triangle = this.triangle; | |
var square1 = this.square1; | |
var square2 = this.square2; | |
var noise = this.noise; | |
// Clock DMC: | |
if (dmc.isEnabled) { | |
dmc.shiftCounter-=(nCycles<<3); | |
while(dmc.shiftCounter<=0 && dmc.dmaFrequency>0){ | |
dmc.shiftCounter += dmc.dmaFrequency; | |
dmc.clockDmc(); | |
} | |
} | |
// Clock Triangle channel Prog timer: | |
if (triangle.progTimerMax>0) { | |
triangle.progTimerCount -= nCycles; | |
while(triangle.progTimerCount <= 0){ | |
triangle.progTimerCount += triangle.progTimerMax+1; | |
if (triangle.linearCounter>0 && triangle.lengthCounter>0) { | |
triangle.triangleCounter++; | |
triangle.triangleCounter &= 0x1F; | |
if (triangle.isEnabled) { | |
if (triangle.triangleCounter>=0x10) { | |
// Normal value. | |
triangle.sampleValue = (triangle.triangleCounter&0xF); | |
}else{ | |
// Inverted value. | |
triangle.sampleValue = (0xF - (triangle.triangleCounter&0xF)); | |
} | |
triangle.sampleValue <<= 4; | |
} | |
} | |
} | |
} | |
// Clock Square channel 1 Prog timer: | |
square1.progTimerCount -= nCycles; | |
if (square1.progTimerCount <= 0) { | |
square1.progTimerCount += (square1.progTimerMax+1)<<1; | |
square1.squareCounter++; | |
square1.squareCounter&=0x7; | |
square1.updateSampleValue(); | |
} | |
// Clock Square channel 2 Prog timer: | |
square2.progTimerCount -= nCycles; | |
if (square2.progTimerCount <= 0) { | |
square2.progTimerCount += (square2.progTimerMax+1)<<1; | |
square2.squareCounter++; | |
square2.squareCounter&=0x7; | |
square2.updateSampleValue(); | |
} | |
// Clock noise channel Prog timer: | |
var acc_c = nCycles; | |
if (noise.progTimerCount-acc_c > 0) { | |
// Do all cycles at once: | |
noise.progTimerCount -= acc_c; | |
noise.accCount += acc_c; | |
noise.accValue += acc_c * noise.sampleValue; | |
}else{ | |
// Slow-step: | |
while((acc_c--) > 0){ | |
if (--noise.progTimerCount <= 0 && noise.progTimerMax>0) { | |
// Update noise shift register: | |
noise.shiftReg <<= 1; | |
noise.tmp = (((noise.shiftReg << (noise.randomMode===0?1:6)) ^ noise.shiftReg) & 0x8000 ); | |
if (noise.tmp !== 0) { | |
// Sample value must be 0. | |
noise.shiftReg |= 0x01; | |
noise.randomBit = 0; | |
noise.sampleValue = 0; | |
}else{ | |
// Find sample value: | |
noise.randomBit = 1; | |
if (noise.isEnabled && noise.lengthCounter>0) { | |
noise.sampleValue = noise.masterVolume; | |
}else{ | |
noise.sampleValue = 0; | |
} | |
} | |
noise.progTimerCount += noise.progTimerMax; | |
} | |
noise.accValue += noise.sampleValue; | |
noise.accCount++; | |
} | |
} | |
// Frame IRQ handling: | |
if (this.frameIrqEnabled && this.frameIrqActive){ | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_NORMAL); | |
} | |
// Clock frame counter at double CPU speed: | |
this.masterFrameCounter += (nCycles<<1); | |
if (this.masterFrameCounter >= this.frameTime) { | |
// 240Hz tick: | |
this.masterFrameCounter -= this.frameTime; | |
this.frameCounterTick(); | |
} | |
// Accumulate sample value: | |
this.accSample(nCycles); | |
// Clock sample timer: | |
this.sampleTimer += nCycles<<10; | |
if (this.sampleTimer>=this.sampleTimerMax) { | |
// Sample channels: | |
this.sample(); | |
this.sampleTimer -= this.sampleTimerMax; | |
} | |
}, | |
accSample: function(cycles) { | |
// Special treatment for triangle channel - need to interpolate. | |
if (this.triangle.sampleCondition) { | |
this.triValue = Math.floor((this.triangle.progTimerCount << 4) / | |
(this.triangle.progTimerMax + 1)); | |
if (this.triValue > 16) { | |
this.triValue = 16; | |
} | |
if (this.triangle.triangleCounter >= 16) { | |
this.triValue = 16 - this.triValue; | |
} | |
// Add non-interpolated sample value: | |
this.triValue += this.triangle.sampleValue; | |
} | |
// Now sample normally: | |
if (cycles === 2) { | |
this.smpTriangle += this.triValue << 1; | |
this.smpDmc += this.dmc.sample << 1; | |
this.smpSquare1 += this.square1.sampleValue << 1; | |
this.smpSquare2 += this.square2.sampleValue << 1; | |
this.accCount += 2; | |
}else if (cycles === 4) { | |
this.smpTriangle += this.triValue << 2; | |
this.smpDmc += this.dmc.sample << 2; | |
this.smpSquare1 += this.square1.sampleValue << 2; | |
this.smpSquare2 += this.square2.sampleValue << 2; | |
this.accCount += 4; | |
}else{ | |
this.smpTriangle += cycles * this.triValue; | |
this.smpDmc += cycles * this.dmc.sample; | |
this.smpSquare1 += cycles * this.square1.sampleValue; | |
this.smpSquare2 += cycles * this.square2.sampleValue; | |
this.accCount += cycles; | |
} | |
}, | |
frameCounterTick: function(){ | |
this.derivedFrameCounter++; | |
if (this.derivedFrameCounter >= this.frameIrqCounterMax) { | |
this.derivedFrameCounter = 0; | |
} | |
if (this.derivedFrameCounter===1 || this.derivedFrameCounter===3) { | |
// Clock length & sweep: | |
this.triangle.clockLengthCounter(); | |
this.square1.clockLengthCounter(); | |
this.square2.clockLengthCounter(); | |
this.noise.clockLengthCounter(); | |
this.square1.clockSweep(); | |
this.square2.clockSweep(); | |
} | |
if (this.derivedFrameCounter >= 0 && this.derivedFrameCounter < 4) { | |
// Clock linear & decay: | |
this.square1.clockEnvDecay(); | |
this.square2.clockEnvDecay(); | |
this.noise.clockEnvDecay(); | |
this.triangle.clockLinearCounter(); | |
} | |
if (this.derivedFrameCounter === 3 && this.countSequence===0) { | |
// Enable IRQ: | |
this.frameIrqActive = true; | |
} | |
// End of 240Hz tick | |
}, | |
// Samples the channels, mixes the output together, | |
// writes to buffer and (if enabled) file. | |
sample: function(){ | |
var sq_index, tnd_index; | |
if (this.accCount > 0) { | |
this.smpSquare1 <<= 4; | |
this.smpSquare1 = Math.floor(this.smpSquare1 / this.accCount); | |
this.smpSquare2 <<= 4; | |
this.smpSquare2 = Math.floor(this.smpSquare2 / this.accCount); | |
this.smpTriangle = Math.floor(this.smpTriangle / this.accCount); | |
this.smpDmc <<= 4; | |
this.smpDmc = Math.floor(this.smpDmc / this.accCount); | |
this.accCount = 0; | |
} | |
else { | |
this.smpSquare1 = this.square1.sampleValue << 4; | |
this.smpSquare2 = this.square2.sampleValue << 4; | |
this.smpTriangle = this.triangle.sampleValue; | |
this.smpDmc = this.dmc.sample << 4; | |
} | |
var smpNoise = Math.floor((this.noise.accValue << 4) / | |
this.noise.accCount); | |
this.noise.accValue = smpNoise >> 4; | |
this.noise.accCount = 1; | |
// Stereo sound. | |
// Left channel: | |
sq_index = ( | |
this.smpSquare1 * this.stereoPosLSquare1 + | |
this.smpSquare2 * this.stereoPosLSquare2 | |
) >> 8; | |
tnd_index = ( | |
3 * this.smpTriangle * this.stereoPosLTriangle + | |
(smpNoise<<1) * this.stereoPosLNoise + this.smpDmc * | |
this.stereoPosLDMC | |
) >> 8; | |
if (sq_index >= this.square_table.length) { | |
sq_index = this.square_table.length-1; | |
} | |
if (tnd_index >= this.tnd_table.length) { | |
tnd_index = this.tnd_table.length - 1; | |
} | |
var sampleValueL = this.square_table[sq_index] + | |
this.tnd_table[tnd_index] - this.dcValue; | |
// Right channel: | |
sq_index = (this.smpSquare1 * this.stereoPosRSquare1 + | |
this.smpSquare2 * this.stereoPosRSquare2 | |
) >> 8; | |
tnd_index = (3 * this.smpTriangle * this.stereoPosRTriangle + | |
(smpNoise << 1) * this.stereoPosRNoise + this.smpDmc * | |
this.stereoPosRDMC | |
) >> 8; | |
if (sq_index >= this.square_table.length) { | |
sq_index = this.square_table.length - 1; | |
} | |
if (tnd_index >= this.tnd_table.length) { | |
tnd_index = this.tnd_table.length - 1; | |
} | |
var sampleValueR = this.square_table[sq_index] + | |
this.tnd_table[tnd_index] - this.dcValue; | |
// Remove DC from left channel: | |
var smpDiffL = sampleValueL - this.prevSampleL; | |
this.prevSampleL += smpDiffL; | |
this.smpAccumL += smpDiffL - (this.smpAccumL >> 10); | |
sampleValueL = this.smpAccumL; | |
// Remove DC from right channel: | |
var smpDiffR = sampleValueR - this.prevSampleR; | |
this.prevSampleR += smpDiffR; | |
this.smpAccumR += smpDiffR - (this.smpAccumR >> 10); | |
sampleValueR = this.smpAccumR; | |
// Write: | |
if (sampleValueL > this.maxSample) { | |
this.maxSample = sampleValueL; | |
} | |
if (sampleValueL < this.minSample) { | |
this.minSample = sampleValueL; | |
} | |
this.sampleBuffer[this.bufferIndex++] = sampleValueL; | |
this.sampleBuffer[this.bufferIndex++] = sampleValueR; | |
// Write full buffer | |
if (this.bufferIndex === this.sampleBuffer.length) { | |
this.nes.ui.writeAudio(this.sampleBuffer); | |
this.sampleBuffer = new Array(this.bufferSize*2); | |
this.bufferIndex = 0; | |
} | |
// Reset sampled values: | |
this.smpSquare1 = 0; | |
this.smpSquare2 = 0; | |
this.smpTriangle = 0; | |
this.smpDmc = 0; | |
}, | |
getLengthMax: function(value){ | |
return this.lengthLookup[value >> 3]; | |
}, | |
getDmcFrequency: function(value){ | |
if (value >= 0 && value < 0x10) { | |
return this.dmcFreqLookup[value]; | |
} | |
return 0; | |
}, | |
getNoiseWaveLength: function(value){ | |
if (value >= 0 && value < 0x10) { | |
return this.noiseWavelengthLookup[value]; | |
} | |
return 0; | |
}, | |
setPanning: function(pos){ | |
for (var i = 0; i < 5; i++) { | |
this.panning[i] = pos[i]; | |
} | |
this.updateStereoPos(); | |
}, | |
setMasterVolume: function(value){ | |
if (value < 0) { | |
value = 0; | |
} | |
if (value > 256) { | |
value = 256; | |
} | |
this.masterVolume = value; | |
this.updateStereoPos(); | |
}, | |
updateStereoPos: function(){ | |
this.stereoPosLSquare1 = (this.panning[0] * this.masterVolume) >> 8; | |
this.stereoPosLSquare2 = (this.panning[1] * this.masterVolume) >> 8; | |
this.stereoPosLTriangle = (this.panning[2] * this.masterVolume) >> 8; | |
this.stereoPosLNoise = (this.panning[3] * this.masterVolume) >> 8; | |
this.stereoPosLDMC = (this.panning[4] * this.masterVolume) >> 8; | |
this.stereoPosRSquare1 = this.masterVolume - this.stereoPosLSquare1; | |
this.stereoPosRSquare2 = this.masterVolume - this.stereoPosLSquare2; | |
this.stereoPosRTriangle = this.masterVolume - this.stereoPosLTriangle; | |
this.stereoPosRNoise = this.masterVolume - this.stereoPosLNoise; | |
this.stereoPosRDMC = this.masterVolume - this.stereoPosLDMC; | |
}, | |
initLengthLookup: function(){ | |
this.lengthLookup = [ | |
0x0A, 0xFE, | |
0x14, 0x02, | |
0x28, 0x04, | |
0x50, 0x06, | |
0xA0, 0x08, | |
0x3C, 0x0A, | |
0x0E, 0x0C, | |
0x1A, 0x0E, | |
0x0C, 0x10, | |
0x18, 0x12, | |
0x30, 0x14, | |
0x60, 0x16, | |
0xC0, 0x18, | |
0x48, 0x1A, | |
0x10, 0x1C, | |
0x20, 0x1E | |
]; | |
}, | |
initDmcFrequencyLookup: function(){ | |
this.dmcFreqLookup = new Array(16); | |
this.dmcFreqLookup[0x0] = 0xD60; | |
this.dmcFreqLookup[0x1] = 0xBE0; | |
this.dmcFreqLookup[0x2] = 0xAA0; | |
this.dmcFreqLookup[0x3] = 0xA00; | |
this.dmcFreqLookup[0x4] = 0x8F0; | |
this.dmcFreqLookup[0x5] = 0x7F0; | |
this.dmcFreqLookup[0x6] = 0x710; | |
this.dmcFreqLookup[0x7] = 0x6B0; | |
this.dmcFreqLookup[0x8] = 0x5F0; | |
this.dmcFreqLookup[0x9] = 0x500; | |
this.dmcFreqLookup[0xA] = 0x470; | |
this.dmcFreqLookup[0xB] = 0x400; | |
this.dmcFreqLookup[0xC] = 0x350; | |
this.dmcFreqLookup[0xD] = 0x2A0; | |
this.dmcFreqLookup[0xE] = 0x240; | |
this.dmcFreqLookup[0xF] = 0x1B0; | |
//for(int i=0;i<16;i++)dmcFreqLookup[i]/=8; | |
}, | |
initNoiseWavelengthLookup: function(){ | |
this.noiseWavelengthLookup = new Array(16); | |
this.noiseWavelengthLookup[0x0] = 0x004; | |
this.noiseWavelengthLookup[0x1] = 0x008; | |
this.noiseWavelengthLookup[0x2] = 0x010; | |
this.noiseWavelengthLookup[0x3] = 0x020; | |
this.noiseWavelengthLookup[0x4] = 0x040; | |
this.noiseWavelengthLookup[0x5] = 0x060; | |
this.noiseWavelengthLookup[0x6] = 0x080; | |
this.noiseWavelengthLookup[0x7] = 0x0A0; | |
this.noiseWavelengthLookup[0x8] = 0x0CA; | |
this.noiseWavelengthLookup[0x9] = 0x0FE; | |
this.noiseWavelengthLookup[0xA] = 0x17C; | |
this.noiseWavelengthLookup[0xB] = 0x1FC; | |
this.noiseWavelengthLookup[0xC] = 0x2FA; | |
this.noiseWavelengthLookup[0xD] = 0x3F8; | |
this.noiseWavelengthLookup[0xE] = 0x7F2; | |
this.noiseWavelengthLookup[0xF] = 0xFE4; | |
}, | |
initDACtables: function(){ | |
var value, ival, i; | |
var max_sqr = 0; | |
var max_tnd = 0; | |
this.square_table = new Array(32*16); | |
this.tnd_table = new Array(204*16); | |
for (i = 0; i < 32 * 16; i++) { | |
value = 95.52 / (8128.0 / (i/16.0) + 100.0); | |
value *= 0.98411; | |
value *= 50000.0; | |
ival = Math.floor(value); | |
this.square_table[i] = ival; | |
if (ival > max_sqr) { | |
max_sqr = ival; | |
} | |
} | |
for (i = 0; i < 204 * 16; i++) { | |
value = 163.67 / (24329.0 / (i/16.0) + 100.0); | |
value *= 0.98411; | |
value *= 50000.0; | |
ival = Math.floor(value); | |
this.tnd_table[i] = ival; | |
if (ival > max_tnd) { | |
max_tnd = ival; | |
} | |
} | |
this.dacRange = max_sqr+max_tnd; | |
this.dcValue = this.dacRange/2; | |
} | |
}; | |
JSNES.PAPU.ChannelDM = function(papu) { | |
this.papu = papu; | |
this.MODE_NORMAL = 0; | |
this.MODE_LOOP = 1; | |
this.MODE_IRQ = 2; | |
this.isEnabled = null; | |
this.hasSample = null; | |
this.irqGenerated = false; | |
this.playMode = null; | |
this.dmaFrequency = null; | |
this.dmaCounter = null; | |
this.deltaCounter = null; | |
this.playStartAddress = null; | |
this.playAddress = null; | |
this.playLength = null; | |
this.playLengthCounter = null; | |
this.shiftCounter = null; | |
this.reg4012 = null; | |
this.reg4013 = null; | |
this.sample = null; | |
this.dacLsb = null; | |
this.data = null; | |
this.reset(); | |
}; | |
JSNES.PAPU.ChannelDM.prototype = { | |
clockDmc: function() { | |
// Only alter DAC value if the sample buffer has data: | |
if(this.hasSample) { | |
if ((this.data & 1) === 0) { | |
// Decrement delta: | |
if(this.deltaCounter>0) { | |
this.deltaCounter--; | |
} | |
} | |
else { | |
// Increment delta: | |
if (this.deltaCounter < 63) { | |
this.deltaCounter++; | |
} | |
} | |
// Update sample value: | |
this.sample = this.isEnabled ? (this.deltaCounter << 1) + this.dacLsb : 0; | |
// Update shift register: | |
this.data >>= 1; | |
} | |
this.dmaCounter--; | |
if (this.dmaCounter <= 0) { | |
// No more sample bits. | |
this.hasSample = false; | |
this.endOfSample(); | |
this.dmaCounter = 8; | |
} | |
if (this.irqGenerated) { | |
this.papu.nes.cpu.requestIrq(this.papu.nes.cpu.IRQ_NORMAL); | |
} | |
}, | |
endOfSample: function() { | |
if (this.playLengthCounter === 0 && this.playMode === this.MODE_LOOP) { | |
// Start from beginning of sample: | |
this.playAddress = this.playStartAddress; | |
this.playLengthCounter = this.playLength; | |
} | |
if (this.playLengthCounter > 0) { | |
// Fetch next sample: | |
this.nextSample(); | |
if (this.playLengthCounter === 0) { | |
// Last byte of sample fetched, generate IRQ: | |
if (this.playMode === this.MODE_IRQ) { | |
// Generate IRQ: | |
this.irqGenerated = true; | |
} | |
} | |
} | |
}, | |
nextSample: function() { | |
// Fetch byte: | |
this.data = this.papu.nes.mmap.load(this.playAddress); | |
this.papu.nes.cpu.haltCycles(4); | |
this.playLengthCounter--; | |
this.playAddress++; | |
if (this.playAddress > 0xFFFF) { | |
this.playAddress = 0x8000; | |
} | |
this.hasSample = true; | |
}, | |
writeReg: function(address, value) { | |
if (address === 0x4010) { | |
// Play mode, DMA Frequency | |
if ((value >> 6) === 0) { | |
this.playMode = this.MODE_NORMAL; | |
} | |
else if (((value >> 6) & 1) === 1) { | |
this.playMode = this.MODE_LOOP; | |
} | |
else if ((value >> 6) === 2) { | |
this.playMode = this.MODE_IRQ; | |
} | |
if ((value & 0x80) === 0) { | |
this.irqGenerated = false; | |
} | |
this.dmaFrequency = this.papu.getDmcFrequency(value & 0xF); | |
} | |
else if (address === 0x4011) { | |
// Delta counter load register: | |
this.deltaCounter = (value >> 1) & 63; | |
this.dacLsb = value & 1; | |
this.sample = ((this.deltaCounter << 1) + this.dacLsb); // update sample value | |
} | |
else if (address === 0x4012) { | |
// DMA address load register | |
this.playStartAddress = (value << 6) | 0x0C000; | |
this.playAddress = this.playStartAddress; | |
this.reg4012 = value; | |
} | |
else if (address === 0x4013) { | |
// Length of play code | |
this.playLength = (value << 4) + 1; | |
this.playLengthCounter = this.playLength; | |
this.reg4013 = value; | |
} | |
else if (address === 0x4015) { | |
// DMC/IRQ Status | |
if (((value >> 4) & 1) === 0) { | |
// Disable: | |
this.playLengthCounter = 0; | |
} | |
else { | |
// Restart: | |
this.playAddress = this.playStartAddress; | |
this.playLengthCounter = this.playLength; | |
} | |
this.irqGenerated = false; | |
} | |
}, | |
setEnabled: function(value) { | |
if ((!this.isEnabled) && value) { | |
this.playLengthCounter = this.playLength; | |
} | |
this.isEnabled = value; | |
}, | |
getLengthStatus: function(){ | |
return ((this.playLengthCounter === 0 || !this.isEnabled) ? 0 : 1); | |
}, | |
getIrqStatus: function(){ | |
return (this.irqGenerated ? 1 : 0); | |
}, | |
reset: function(){ | |
this.isEnabled = false; | |
this.irqGenerated = false; | |
this.playMode = this.MODE_NORMAL; | |
this.dmaFrequency = 0; | |
this.dmaCounter = 0; | |
this.deltaCounter = 0; | |
this.playStartAddress = 0; | |
this.playAddress = 0; | |
this.playLength = 0; | |
this.playLengthCounter = 0; | |
this.sample = 0; | |
this.dacLsb = 0; | |
this.shiftCounter = 0; | |
this.reg4012 = 0; | |
this.reg4013 = 0; | |
this.data = 0; | |
} | |
}; | |
JSNES.PAPU.ChannelNoise = function(papu) { | |
this.papu = papu; | |
this.isEnabled = null; | |
this.envDecayDisable = null; | |
this.envDecayLoopEnable = null; | |
this.lengthCounterEnable = null; | |
this.envReset = null; | |
this.shiftNow = null; | |
this.lengthCounter = null; | |
this.progTimerCount = null; | |
this.progTimerMax = null; | |
this.envDecayRate = null; | |
this.envDecayCounter = null; | |
this.envVolume = null; | |
this.masterVolume = null; | |
this.shiftReg = 1<<14; | |
this.randomBit = null; | |
this.randomMode = null; | |
this.sampleValue = null; | |
this.accValue=0; | |
this.accCount=1; | |
this.tmp = null; | |
this.reset(); | |
}; | |
JSNES.PAPU.ChannelNoise.prototype = { | |
reset: function() { | |
this.progTimerCount = 0; | |
this.progTimerMax = 0; | |
this.isEnabled = false; | |
this.lengthCounter = 0; | |
this.lengthCounterEnable = false; | |
this.envDecayDisable = false; | |
this.envDecayLoopEnable = false; | |
this.shiftNow = false; | |
this.envDecayRate = 0; | |
this.envDecayCounter = 0; | |
this.envVolume = 0; | |
this.masterVolume = 0; | |
this.shiftReg = 1; | |
this.randomBit = 0; | |
this.randomMode = 0; | |
this.sampleValue = 0; | |
this.tmp = 0; | |
}, | |
clockLengthCounter: function(){ | |
if (this.lengthCounterEnable && this.lengthCounter>0){ | |
this.lengthCounter--; | |
if (this.lengthCounter === 0) { | |
this.updateSampleValue(); | |
} | |
} | |
}, | |
clockEnvDecay: function() { | |
if(this.envReset) { | |
// Reset envelope: | |
this.envReset = false; | |
this.envDecayCounter = this.envDecayRate + 1; | |
this.envVolume = 0xF; | |
} | |
else if (--this.envDecayCounter <= 0) { | |
// Normal handling: | |
this.envDecayCounter = this.envDecayRate + 1; | |
if(this.envVolume>0) { | |
this.envVolume--; | |
} | |
else { | |
this.envVolume = this.envDecayLoopEnable ? 0xF : 0; | |
} | |
} | |
this.masterVolume = this.envDecayDisable ? this.envDecayRate : this.envVolume; | |
this.updateSampleValue(); | |
}, | |
updateSampleValue: function() { | |
if (this.isEnabled && this.lengthCounter>0) { | |
this.sampleValue = this.randomBit * this.masterVolume; | |
} | |
}, | |
writeReg: function(address, value){ | |
if(address === 0x400C) { | |
// Volume/Envelope decay: | |
this.envDecayDisable = ((value&0x10) !== 0); | |
this.envDecayRate = value&0xF; | |
this.envDecayLoopEnable = ((value&0x20) !== 0); | |
this.lengthCounterEnable = ((value&0x20)===0); | |
this.masterVolume = this.envDecayDisable?this.envDecayRate:this.envVolume; | |
}else if(address === 0x400E) { | |
// Programmable timer: | |
this.progTimerMax = this.papu.getNoiseWaveLength(value&0xF); | |
this.randomMode = value>>7; | |
}else if(address === 0x400F) { | |
// Length counter | |
this.lengthCounter = this.papu.getLengthMax(value&248); | |
this.envReset = true; | |
} | |
// Update: | |
//updateSampleValue(); | |
}, | |
setEnabled: function(value){ | |
this.isEnabled = value; | |
if (!value) { | |
this.lengthCounter = 0; | |
} | |
this.updateSampleValue(); | |
}, | |
getLengthStatus: function() { | |
return ((this.lengthCounter===0 || !this.isEnabled)?0:1); | |
} | |
}; | |
JSNES.PAPU.ChannelSquare = function(papu, square1) { | |
this.papu = papu; | |
this.dutyLookup = [ | |
0, 1, 0, 0, 0, 0, 0, 0, | |
0, 1, 1, 0, 0, 0, 0, 0, | |
0, 1, 1, 1, 1, 0, 0, 0, | |
1, 0, 0, 1, 1, 1, 1, 1 | |
]; | |
this.impLookup = [ | |
1,-1, 0, 0, 0, 0, 0, 0, | |
1, 0,-1, 0, 0, 0, 0, 0, | |
1, 0, 0, 0,-1, 0, 0, 0, | |
-1, 0, 1, 0, 0, 0, 0, 0 | |
]; | |
this.sqr1 = square1; | |
this.isEnabled = null; | |
this.lengthCounterEnable = null; | |
this.sweepActive = null; | |
this.envDecayDisable = null; | |
this.envDecayLoopEnable = null; | |
this.envReset = null; | |
this.sweepCarry = null; | |
this.updateSweepPeriod = null; | |
this.progTimerCount = null; | |
this.progTimerMax = null; | |
this.lengthCounter = null; | |
this.squareCounter = null; | |
this.sweepCounter = null; | |
this.sweepCounterMax = null; | |
this.sweepMode = null; | |
this.sweepShiftAmount = null; | |
this.envDecayRate = null; | |
this.envDecayCounter = null; | |
this.envVolume = null; | |
this.masterVolume = null; | |
this.dutyMode = null; | |
this.sweepResult = null; | |
this.sampleValue = null; | |
this.vol = null; | |
this.reset(); | |
}; | |
JSNES.PAPU.ChannelSquare.prototype = { | |
reset: function() { | |
this.progTimerCount = 0; | |
this.progTimerMax = 0; | |
this.lengthCounter = 0; | |
this.squareCounter = 0; | |
this.sweepCounter = 0; | |
this.sweepCounterMax = 0; | |
this.sweepMode = 0; | |
this.sweepShiftAmount = 0; | |
this.envDecayRate = 0; | |
this.envDecayCounter = 0; | |
this.envVolume = 0; | |
this.masterVolume = 0; | |
this.dutyMode = 0; | |
this.vol = 0; | |
this.isEnabled = false; | |
this.lengthCounterEnable = false; | |
this.sweepActive = false; | |
this.sweepCarry = false; | |
this.envDecayDisable = false; | |
this.envDecayLoopEnable = false; | |
}, | |
clockLengthCounter: function() { | |
if (this.lengthCounterEnable && this.lengthCounter > 0){ | |
this.lengthCounter--; | |
if (this.lengthCounter === 0) { | |
this.updateSampleValue(); | |
} | |
} | |
}, | |
clockEnvDecay: function() { | |
if (this.envReset) { | |
// Reset envelope: | |
this.envReset = false; | |
this.envDecayCounter = this.envDecayRate + 1; | |
this.envVolume = 0xF; | |
}else if ((--this.envDecayCounter) <= 0) { | |
// Normal handling: | |
this.envDecayCounter = this.envDecayRate + 1; | |
if (this.envVolume>0) { | |
this.envVolume--; | |
}else{ | |
this.envVolume = this.envDecayLoopEnable ? 0xF : 0; | |
} | |
} | |
this.masterVolume = this.envDecayDisable ? this.envDecayRate : this.envVolume; | |
this.updateSampleValue(); | |
}, | |
clockSweep: function() { | |
if (--this.sweepCounter<=0) { | |
this.sweepCounter = this.sweepCounterMax + 1; | |
if (this.sweepActive && this.sweepShiftAmount>0 && this.progTimerMax>7) { | |
// Calculate result from shifter: | |
this.sweepCarry = false; | |
if (this.sweepMode===0) { | |
this.progTimerMax += (this.progTimerMax>>this.sweepShiftAmount); | |
if (this.progTimerMax > 4095) { | |
this.progTimerMax = 4095; | |
this.sweepCarry = true; | |
} | |
}else{ | |
this.progTimerMax = this.progTimerMax - ((this.progTimerMax>>this.sweepShiftAmount)-(this.sqr1?1:0)); | |
} | |
} | |
} | |
if (this.updateSweepPeriod) { | |
this.updateSweepPeriod = false; | |
this.sweepCounter = this.sweepCounterMax + 1; | |
} | |
}, | |
updateSampleValue: function() { | |
if (this.isEnabled && this.lengthCounter>0 && this.progTimerMax>7) { | |
if (this.sweepMode===0 && (this.progTimerMax + (this.progTimerMax>>this.sweepShiftAmount)) > 4095) { | |
//if (this.sweepCarry) { | |
this.sampleValue = 0; | |
}else{ | |
this.sampleValue = this.masterVolume*this.dutyLookup[(this.dutyMode<<3)+this.squareCounter]; | |
} | |
}else{ | |
this.sampleValue = 0; | |
} | |
}, | |
writeReg: function(address, value){ | |
var addrAdd = (this.sqr1?0:4); | |
if (address === 0x4000 + addrAdd) { | |
// Volume/Envelope decay: | |
this.envDecayDisable = ((value&0x10) !== 0); | |
this.envDecayRate = value & 0xF; | |
this.envDecayLoopEnable = ((value&0x20) !== 0); | |
this.dutyMode = (value>>6)&0x3; | |
this.lengthCounterEnable = ((value&0x20)===0); | |
this.masterVolume = this.envDecayDisable?this.envDecayRate:this.envVolume; | |
this.updateSampleValue(); | |
} | |
else if (address === 0x4001+addrAdd) { | |
// Sweep: | |
this.sweepActive = ((value&0x80) !== 0); | |
this.sweepCounterMax = ((value>>4)&7); | |
this.sweepMode = (value>>3)&1; | |
this.sweepShiftAmount = value&7; | |
this.updateSweepPeriod = true; | |
} | |
else if (address === 0x4002+addrAdd){ | |
// Programmable timer: | |
this.progTimerMax &= 0x700; | |
this.progTimerMax |= value; | |
} | |
else if (address === 0x4003+addrAdd) { | |
// Programmable timer, length counter | |
this.progTimerMax &= 0xFF; | |
this.progTimerMax |= ((value&0x7)<<8); | |
if (this.isEnabled){ | |
this.lengthCounter = this.papu.getLengthMax(value&0xF8); | |
} | |
this.envReset = true; | |
} | |
}, | |
setEnabled: function(value) { | |
this.isEnabled = value; | |
if (!value) { | |
this.lengthCounter = 0; | |
} | |
this.updateSampleValue(); | |
}, | |
getLengthStatus: function() { | |
return ((this.lengthCounter === 0 || !this.isEnabled) ? 0 : 1); | |
} | |
}; | |
JSNES.PAPU.ChannelTriangle = function(papu) { | |
this.papu = papu; | |
this.isEnabled = null; | |
this.sampleCondition = null; | |
this.lengthCounterEnable = null; | |
this.lcHalt = null; | |
this.lcControl = null; | |
this.progTimerCount = null; | |
this.progTimerMax = null; | |
this.triangleCounter = null; | |
this.lengthCounter = null; | |
this.linearCounter = null; | |
this.lcLoadValue = null; | |
this.sampleValue = null; | |
this.tmp = null; | |
this.reset(); | |
}; | |
JSNES.PAPU.ChannelTriangle.prototype = { | |
reset: function(){ | |
this.progTimerCount = 0; | |
this.progTimerMax = 0; | |
this.triangleCounter = 0; | |
this.isEnabled = false; | |
this.sampleCondition = false; | |
this.lengthCounter = 0; | |
this.lengthCounterEnable = false; | |
this.linearCounter = 0; | |
this.lcLoadValue = 0; | |
this.lcHalt = true; | |
this.lcControl = false; | |
this.tmp = 0; | |
this.sampleValue = 0xF; | |
}, | |
clockLengthCounter: function(){ | |
if (this.lengthCounterEnable && this.lengthCounter>0) { | |
this.lengthCounter--; | |
if (this.lengthCounter===0) { | |
this.updateSampleCondition(); | |
} | |
} | |
}, | |
clockLinearCounter: function(){ | |
if (this.lcHalt){ | |
// Load: | |
this.linearCounter = this.lcLoadValue; | |
this.updateSampleCondition(); | |
} | |
else if (this.linearCounter > 0) { | |
// Decrement: | |
this.linearCounter--; | |
this.updateSampleCondition(); | |
} | |
if (!this.lcControl) { | |
// Clear halt flag: | |
this.lcHalt = false; | |
} | |
}, | |
getLengthStatus: function(){ | |
return ((this.lengthCounter === 0 || !this.isEnabled)?0:1); | |
}, | |
readReg: function(address){ | |
return 0; | |
}, | |
writeReg: function(address, value){ | |
if (address === 0x4008) { | |
// New values for linear counter: | |
this.lcControl = (value&0x80)!==0; | |
this.lcLoadValue = value&0x7F; | |
// Length counter enable: | |
this.lengthCounterEnable = !this.lcControl; | |
} | |
else if (address === 0x400A) { | |
// Programmable timer: | |
this.progTimerMax &= 0x700; | |
this.progTimerMax |= value; | |
} | |
else if(address === 0x400B) { | |
// Programmable timer, length counter | |
this.progTimerMax &= 0xFF; | |
this.progTimerMax |= ((value&0x07)<<8); | |
this.lengthCounter = this.papu.getLengthMax(value&0xF8); | |
this.lcHalt = true; | |
} | |
this.updateSampleCondition(); | |
}, | |
clockProgrammableTimer: function(nCycles){ | |
if (this.progTimerMax>0) { | |
this.progTimerCount += nCycles; | |
while (this.progTimerMax > 0 && | |
this.progTimerCount >= this.progTimerMax) { | |
this.progTimerCount -= this.progTimerMax; | |
if (this.isEnabled && this.lengthCounter>0 && | |
this.linearCounter > 0) { | |
this.clockTriangleGenerator(); | |
} | |
} | |
} | |
}, | |
clockTriangleGenerator: function() { | |
this.triangleCounter++; | |
this.triangleCounter &= 0x1F; | |
}, | |
setEnabled: function(value) { | |
this.isEnabled = value; | |
if(!value) { | |
this.lengthCounter = 0; | |
} | |
this.updateSampleCondition(); | |
}, | |
updateSampleCondition: function() { | |
this.sampleCondition = this.isEnabled && | |
this.progTimerMax > 7 && | |
this.linearCounter > 0 && | |
this.lengthCounter > 0; | |
} | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.PPU = function(nes) { | |
this.nes = nes; | |
// Keep Chrome happy | |
this.vramMem = null; | |
this.spriteMem = null; | |
this.vramAddress = null; | |
this.vramTmpAddress = null; | |
this.vramBufferedReadValue = null; | |
this.firstWrite = null; | |
this.sramAddress = null; | |
this.currentMirroring = null; | |
this.requestEndFrame = null; | |
this.nmiOk = null; | |
this.dummyCycleToggle = null; | |
this.validTileData = null; | |
this.nmiCounter = null; | |
this.scanlineAlreadyRendered = null; | |
this.f_nmiOnVblank = null; | |
this.f_spriteSize = null; | |
this.f_bgPatternTable = null; | |
this.f_spPatternTable = null; | |
this.f_addrInc = null; | |
this.f_nTblAddress = null; | |
this.f_color = null; | |
this.f_spVisibility = null; | |
this.f_bgVisibility = null; | |
this.f_spClipping = null; | |
this.f_bgClipping = null; | |
this.f_dispType = null; | |
this.cntFV = null; | |
this.cntV = null; | |
this.cntH = null; | |
this.cntVT = null; | |
this.cntHT = null; | |
this.regFV = null; | |
this.regV = null; | |
this.regH = null; | |
this.regVT = null; | |
this.regHT = null; | |
this.regFH = null; | |
this.regS = null; | |
this.curNt = null; | |
this.attrib = null; | |
this.buffer = null; | |
this.prevBuffer = null; | |
this.bgbuffer = null; | |
this.pixrendered = null; | |
this.validTileData = null; | |
this.scantile = null; | |
this.scanline = null; | |
this.lastRenderedScanline = null; | |
this.curX = null; | |
this.sprX = null; | |
this.sprY = null; | |
this.sprTile = null; | |
this.sprCol = null; | |
this.vertFlip = null; | |
this.horiFlip = null; | |
this.bgPriority = null; | |
this.spr0HitX = null; | |
this.spr0HitY = null; | |
this.hitSpr0 = null; | |
this.sprPalette = null; | |
this.imgPalette = null; | |
this.ptTile = null; | |
this.ntable1 = null; | |
this.currentMirroring = null; | |
this.nameTable = null; | |
this.vramMirrorTable = null; | |
this.palTable = null; | |
// Rendering Options: | |
this.showSpr0Hit = false; | |
this.clipToTvSize = true; | |
this.reset(); | |
}; | |
JSNES.PPU.prototype = { | |
// Status flags: | |
STATUS_VRAMWRITE: 4, | |
STATUS_SLSPRITECOUNT: 5, | |
STATUS_SPRITE0HIT: 6, | |
STATUS_VBLANK: 7, | |
reset: function() { | |
var i; | |
// Memory | |
this.vramMem = new Array(0x8000); | |
this.spriteMem = new Array(0x100); | |
for (i=0; i<this.vramMem.length; i++) { | |
this.vramMem[i] = 0; | |
} | |
for (i=0; i<this.spriteMem.length; i++) { | |
this.spriteMem[i] = 0; | |
} | |
// VRAM I/O: | |
this.vramAddress = null; | |
this.vramTmpAddress = null; | |
this.vramBufferedReadValue = 0; | |
this.firstWrite = true; // VRAM/Scroll Hi/Lo latch | |
// SPR-RAM I/O: | |
this.sramAddress = 0; // 8-bit only. | |
this.currentMirroring = -1; | |
this.requestEndFrame = false; | |
this.nmiOk = false; | |
this.dummyCycleToggle = false; | |
this.validTileData = false; | |
this.nmiCounter = 0; | |
this.scanlineAlreadyRendered = null; | |
// Control Flags Register 1: | |
this.f_nmiOnVblank = 0; // NMI on VBlank. 0=disable, 1=enable | |
this.f_spriteSize = 0; // Sprite size. 0=8x8, 1=8x16 | |
this.f_bgPatternTable = 0; // Background Pattern Table address. 0=0x0000,1=0x1000 | |
this.f_spPatternTable = 0; // Sprite Pattern Table address. 0=0x0000,1=0x1000 | |
this.f_addrInc = 0; // PPU Address Increment. 0=1,1=32 | |
this.f_nTblAddress = 0; // Name Table Address. 0=0x2000,1=0x2400,2=0x2800,3=0x2C00 | |
// Control Flags Register 2: | |
this.f_color = 0; // Background color. 0=black, 1=blue, 2=green, 4=red | |
this.f_spVisibility = 0; // Sprite visibility. 0=not displayed,1=displayed | |
this.f_bgVisibility = 0; // Background visibility. 0=Not Displayed,1=displayed | |
this.f_spClipping = 0; // Sprite clipping. 0=Sprites invisible in left 8-pixel column,1=No clipping | |
this.f_bgClipping = 0; // Background clipping. 0=BG invisible in left 8-pixel column, 1=No clipping | |
this.f_dispType = 0; // Display type. 0=color, 1=monochrome | |
// Counters: | |
this.cntFV = 0; | |
this.cntV = 0; | |
this.cntH = 0; | |
this.cntVT = 0; | |
this.cntHT = 0; | |
// Registers: | |
this.regFV = 0; | |
this.regV = 0; | |
this.regH = 0; | |
this.regVT = 0; | |
this.regHT = 0; | |
this.regFH = 0; | |
this.regS = 0; | |
// These are temporary variables used in rendering and sound procedures. | |
// Their states outside of those procedures can be ignored. | |
// TODO: the use of this is a bit weird, investigate | |
this.curNt = null; | |
// Variables used when rendering: | |
this.attrib = new Array(32); | |
this.buffer = new Array(256*240); | |
this.prevBuffer = new Array(256*240); | |
this.bgbuffer = new Array(256*240); | |
this.pixrendered = new Array(256*240); | |
this.validTileData = null; | |
this.scantile = new Array(32); | |
// Initialize misc vars: | |
this.scanline = 0; | |
this.lastRenderedScanline = -1; | |
this.curX = 0; | |
// Sprite data: | |
this.sprX = new Array(64); // X coordinate | |
this.sprY = new Array(64); // Y coordinate | |
this.sprTile = new Array(64); // Tile Index (into pattern table) | |
this.sprCol = new Array(64); // Upper two bits of color | |
this.vertFlip = new Array(64); // Vertical Flip | |
this.horiFlip = new Array(64); // Horizontal Flip | |
this.bgPriority = new Array(64); // Background priority | |
this.spr0HitX = 0; // Sprite #0 hit X coordinate | |
this.spr0HitY = 0; // Sprite #0 hit Y coordinate | |
this.hitSpr0 = false; | |
// Palette data: | |
this.sprPalette = new Array(16); | |
this.imgPalette = new Array(16); | |
// Create pattern table tile buffers: | |
this.ptTile = new Array(512); | |
for (i=0; i<512; i++) { | |
this.ptTile[i] = new JSNES.PPU.Tile(); | |
} | |
// Create nametable buffers: | |
// Name table data: | |
this.ntable1 = new Array(4); | |
this.currentMirroring = -1; | |
this.nameTable = new Array(4); | |
for (i=0; i<4; i++) { | |
this.nameTable[i] = new JSNES.PPU.NameTable(32, 32, "Nt"+i); | |
} | |
// Initialize mirroring lookup table: | |
this.vramMirrorTable = new Array(0x8000); | |
for (i=0; i<0x8000; i++) { | |
this.vramMirrorTable[i] = i; | |
} | |
this.palTable = new JSNES.PPU.PaletteTable(); | |
this.palTable.loadNTSCPalette(); | |
//this.palTable.loadDefaultPalette(); | |
this.updateControlReg1(0); | |
this.updateControlReg2(0); | |
}, | |
// Sets Nametable mirroring. | |
setMirroring: function(mirroring){ | |
if (mirroring == this.currentMirroring) { | |
return; | |
} | |
this.currentMirroring = mirroring; | |
this.triggerRendering(); | |
// Remove mirroring: | |
if (this.vramMirrorTable === null) { | |
this.vramMirrorTable = new Array(0x8000); | |
} | |
for (var i=0; i<0x8000; i++) { | |
this.vramMirrorTable[i] = i; | |
} | |
// Palette mirroring: | |
this.defineMirrorRegion(0x3f20,0x3f00,0x20); | |
this.defineMirrorRegion(0x3f40,0x3f00,0x20); | |
this.defineMirrorRegion(0x3f80,0x3f00,0x20); | |
this.defineMirrorRegion(0x3fc0,0x3f00,0x20); | |
// Additional mirroring: | |
this.defineMirrorRegion(0x3000,0x2000,0xf00); | |
this.defineMirrorRegion(0x4000,0x0000,0x4000); | |
if (mirroring == this.nes.rom.HORIZONTAL_MIRRORING) { | |
// Horizontal mirroring. | |
this.ntable1[0] = 0; | |
this.ntable1[1] = 0; | |
this.ntable1[2] = 1; | |
this.ntable1[3] = 1; | |
this.defineMirrorRegion(0x2400,0x2000,0x400); | |
this.defineMirrorRegion(0x2c00,0x2800,0x400); | |
}else if (mirroring == this.nes.rom.VERTICAL_MIRRORING) { | |
// Vertical mirroring. | |
this.ntable1[0] = 0; | |
this.ntable1[1] = 1; | |
this.ntable1[2] = 0; | |
this.ntable1[3] = 1; | |
this.defineMirrorRegion(0x2800,0x2000,0x400); | |
this.defineMirrorRegion(0x2c00,0x2400,0x400); | |
}else if (mirroring == this.nes.rom.SINGLESCREEN_MIRRORING) { | |
// Single Screen mirroring | |
this.ntable1[0] = 0; | |
this.ntable1[1] = 0; | |
this.ntable1[2] = 0; | |
this.ntable1[3] = 0; | |
this.defineMirrorRegion(0x2400,0x2000,0x400); | |
this.defineMirrorRegion(0x2800,0x2000,0x400); | |
this.defineMirrorRegion(0x2c00,0x2000,0x400); | |
}else if (mirroring == this.nes.rom.SINGLESCREEN_MIRRORING2) { | |
this.ntable1[0] = 1; | |
this.ntable1[1] = 1; | |
this.ntable1[2] = 1; | |
this.ntable1[3] = 1; | |
this.defineMirrorRegion(0x2400,0x2400,0x400); | |
this.defineMirrorRegion(0x2800,0x2400,0x400); | |
this.defineMirrorRegion(0x2c00,0x2400,0x400); | |
}else { | |
// Assume Four-screen mirroring. | |
this.ntable1[0] = 0; | |
this.ntable1[1] = 1; | |
this.ntable1[2] = 2; | |
this.ntable1[3] = 3; | |
} | |
}, | |
// Define a mirrored area in the address lookup table. | |
// Assumes the regions don't overlap. | |
// The 'to' region is the region that is physically in memory. | |
defineMirrorRegion: function(fromStart, toStart, size){ | |
for (var i=0;i<size;i++) { | |
this.vramMirrorTable[fromStart+i] = toStart+i; | |
} | |
}, | |
startVBlank: function(){ | |
// Do NMI: | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_NMI); | |
// Make sure everything is rendered: | |
if (this.lastRenderedScanline < 239) { | |
this.renderFramePartially( | |
this.lastRenderedScanline+1,240-this.lastRenderedScanline | |
); | |
} | |
// End frame: | |
this.endFrame(); | |
// Reset scanline counter: | |
this.lastRenderedScanline = -1; | |
}, | |
endScanline: function(){ | |
switch (this.scanline) { | |
case 19: | |
// Dummy scanline. | |
// May be variable length: | |
if (this.dummyCycleToggle) { | |
// Remove dead cycle at end of scanline, | |
// for next scanline: | |
this.curX = 1; | |
this.dummyCycleToggle = !this.dummyCycleToggle; | |
} | |
break; | |
case 20: | |
// Clear VBlank flag: | |
this.setStatusFlag(this.STATUS_VBLANK,false); | |
// Clear Sprite #0 hit flag: | |
this.setStatusFlag(this.STATUS_SPRITE0HIT,false); | |
this.hitSpr0 = false; | |
this.spr0HitX = -1; | |
this.spr0HitY = -1; | |
if (this.f_bgVisibility == 1 || this.f_spVisibility==1) { | |
// Update counters: | |
this.cntFV = this.regFV; | |
this.cntV = this.regV; | |
this.cntH = this.regH; | |
this.cntVT = this.regVT; | |
this.cntHT = this.regHT; | |
if (this.f_bgVisibility==1) { | |
// Render dummy scanline: | |
this.renderBgScanline(false,0); | |
} | |
} | |
if (this.f_bgVisibility==1 && this.f_spVisibility==1) { | |
// Check sprite 0 hit for first scanline: | |
this.checkSprite0(0); | |
} | |
if (this.f_bgVisibility==1 || this.f_spVisibility==1) { | |
// Clock mapper IRQ Counter: | |
this.nes.mmap.clockIrqCounter(); | |
} | |
break; | |
case 261: | |
// Dead scanline, no rendering. | |
// Set VINT: | |
this.setStatusFlag(this.STATUS_VBLANK,true); | |
this.requestEndFrame = true; | |
this.nmiCounter = 9; | |
// Wrap around: | |
this.scanline = -1; // will be incremented to 0 | |
break; | |
default: | |
if (this.scanline >= 21 && this.scanline <= 260) { | |
// Render normally: | |
if (this.f_bgVisibility == 1) { | |
if (!this.scanlineAlreadyRendered) { | |
// update scroll: | |
this.cntHT = this.regHT; | |
this.cntH = this.regH; | |
this.renderBgScanline(true,this.scanline+1-21); | |
} | |
this.scanlineAlreadyRendered=false; | |
// Check for sprite 0 (next scanline): | |
if (!this.hitSpr0 && this.f_spVisibility == 1) { | |
if (this.sprX[0] >= -7 && | |
this.sprX[0] < 256 && | |
this.sprY[0] + 1 <= (this.scanline - 20) && | |
(this.sprY[0] + 1 + ( | |
this.f_spriteSize === 0 ? 8 : 16 | |
)) >= (this.scanline - 20)) { | |
if (this.checkSprite0(this.scanline - 20)) { | |
this.hitSpr0 = true; | |
} | |
} | |
} | |
} | |
if (this.f_bgVisibility==1 || this.f_spVisibility==1) { | |
// Clock mapper IRQ Counter: | |
this.nes.mmap.clockIrqCounter(); | |
} | |
} | |
} | |
this.scanline++; | |
this.regsToAddress(); | |
this.cntsToAddress(); | |
}, | |
startFrame: function(){ | |
// Set background color: | |
var bgColor=0; | |
if (this.f_dispType === 0) { | |
// Color display. | |
// f_color determines color emphasis. | |
// Use first entry of image palette as BG color. | |
bgColor = this.imgPalette[0]; | |
} | |
else { | |
// Monochrome display. | |
// f_color determines the bg color. | |
switch (this.f_color) { | |
case 0: | |
// Black | |
bgColor = 0x00000; | |
break; | |
case 1: | |
// Green | |
bgColor = 0x00FF00; | |
break; | |
case 2: | |
// Blue | |
bgColor = 0xFF0000; | |
break; | |
case 3: | |
// Invalid. Use black. | |
bgColor = 0x000000; | |
break; | |
case 4: | |
// Red | |
bgColor = 0x0000FF; | |
break; | |
default: | |
// Invalid. Use black. | |
bgColor = 0x0; | |
} | |
} | |
var buffer = this.buffer; | |
var i; | |
for (i=0; i<256*240; i++) { | |
buffer[i] = bgColor; | |
} | |
var pixrendered = this.pixrendered; | |
for (i=0; i<pixrendered.length; i++) { | |
pixrendered[i]=65; | |
} | |
}, | |
endFrame: function(){ | |
var i, x, y; | |
var buffer = this.buffer; | |
// Draw spr#0 hit coordinates: | |
if (this.showSpr0Hit) { | |
// Spr 0 position: | |
if (this.sprX[0] >= 0 && this.sprX[0] < 256 && | |
this.sprY[0] >= 0 && this.sprY[0] < 240) { | |
for (i=0; i<256; i++) { | |
buffer[(this.sprY[0]<<8)+i] = 0xFF5555; | |
} | |
for (i=0; i<240; i++) { | |
buffer[(i<<8)+this.sprX[0]] = 0xFF5555; | |
} | |
} | |
// Hit position: | |
if (this.spr0HitX >= 0 && this.spr0HitX < 256 && | |
this.spr0HitY >= 0 && this.spr0HitY < 240) { | |
for (i=0; i<256; i++) { | |
buffer[(this.spr0HitY<<8)+i] = 0x55FF55; | |
} | |
for (i=0; i<240; i++) { | |
buffer[(i<<8)+this.spr0HitX] = 0x55FF55; | |
} | |
} | |
} | |
// This is a bit lazy.. | |
// if either the sprites or the background should be clipped, | |
// both are clipped after rendering is finished. | |
if (this.clipToTvSize || this.f_bgClipping === 0 || this.f_spClipping === 0) { | |
// Clip left 8-pixels column: | |
for (y=0;y<240;y++) { | |
for (x=0;x<8;x++) { | |
buffer[(y<<8)+x] = 0; | |
} | |
} | |
} | |
if (this.clipToTvSize) { | |
// Clip right 8-pixels column too: | |
for (y=0; y<240; y++) { | |
for (x=0; x<8; x++) { | |
buffer[(y<<8)+255-x] = 0; | |
} | |
} | |
} | |
// Clip top and bottom 8 pixels: | |
if (this.clipToTvSize) { | |
for (y=0; y<8; y++) { | |
for (x=0; x<256; x++) { | |
buffer[(y<<8)+x] = 0; | |
buffer[((239-y)<<8)+x] = 0; | |
} | |
} | |
} | |
if (this.nes.opts.showDisplay) { | |
this.nes.ui.writeFrame(buffer, this.prevBuffer); | |
} | |
}, | |
updateControlReg1: function(value){ | |
this.triggerRendering(); | |
this.f_nmiOnVblank = (value>>7)&1; | |
this.f_spriteSize = (value>>5)&1; | |
this.f_bgPatternTable = (value>>4)&1; | |
this.f_spPatternTable = (value>>3)&1; | |
this.f_addrInc = (value>>2)&1; | |
this.f_nTblAddress = value&3; | |
this.regV = (value>>1)&1; | |
this.regH = value&1; | |
this.regS = (value>>4)&1; | |
}, | |
updateControlReg2: function(value){ | |
this.triggerRendering(); | |
this.f_color = (value>>5)&7; | |
this.f_spVisibility = (value>>4)&1; | |
this.f_bgVisibility = (value>>3)&1; | |
this.f_spClipping = (value>>2)&1; | |
this.f_bgClipping = (value>>1)&1; | |
this.f_dispType = value&1; | |
if (this.f_dispType === 0) { | |
this.palTable.setEmphasis(this.f_color); | |
} | |
this.updatePalettes(); | |
}, | |
setStatusFlag: function(flag, value){ | |
var n = 1<<flag; | |
this.nes.cpu.mem[0x2002] = | |
((this.nes.cpu.mem[0x2002] & (255-n)) | (value?n:0)); | |
}, | |
// CPU Register $2002: | |
// Read the Status Register. | |
readStatusRegister: function(){ | |
var tmp = this.nes.cpu.mem[0x2002]; | |
// Reset scroll & VRAM Address toggle: | |
this.firstWrite = true; | |
// Clear VBlank flag: | |
this.setStatusFlag(this.STATUS_VBLANK,false); | |
// Fetch status data: | |
return tmp; | |
}, | |
// CPU Register $2003: | |
// Write the SPR-RAM address that is used for sramWrite (Register 0x2004 in CPU memory map) | |
writeSRAMAddress: function(address) { | |
this.sramAddress = address; | |
}, | |
// CPU Register $2004 (R): | |
// Read from SPR-RAM (Sprite RAM). | |
// The address should be set first. | |
sramLoad: function() { | |
/*short tmp = sprMem.load(sramAddress); | |
sramAddress++; // Increment address | |
sramAddress%=0x100; | |
return tmp;*/ | |
return this.spriteMem[this.sramAddress]; | |
}, | |
// CPU Register $2004 (W): | |
// Write to SPR-RAM (Sprite RAM). | |
// The address should be set first. | |
sramWrite: function(value){ | |
this.spriteMem[this.sramAddress] = value; | |
this.spriteRamWriteUpdate(this.sramAddress,value); | |
this.sramAddress++; // Increment address | |
this.sramAddress %= 0x100; | |
}, | |
// CPU Register $2005: | |
// Write to scroll registers. | |
// The first write is the vertical offset, the second is the | |
// horizontal offset: | |
scrollWrite: function(value){ | |
this.triggerRendering(); | |
if (this.firstWrite) { | |
// First write, horizontal scroll: | |
this.regHT = (value>>3)&31; | |
this.regFH = value&7; | |
}else { | |
// Second write, vertical scroll: | |
this.regFV = value&7; | |
this.regVT = (value>>3)&31; | |
} | |
this.firstWrite = !this.firstWrite; | |
}, | |
// CPU Register $2006: | |
// Sets the adress used when reading/writing from/to VRAM. | |
// The first write sets the high byte, the second the low byte. | |
writeVRAMAddress: function(address){ | |
if (this.firstWrite) { | |
this.regFV = (address>>4)&3; | |
this.regV = (address>>3)&1; | |
this.regH = (address>>2)&1; | |
this.regVT = (this.regVT&7) | ((address&3)<<3); | |
}else { | |
this.triggerRendering(); | |
this.regVT = (this.regVT&24) | ((address>>5)&7); | |
this.regHT = address&31; | |
this.cntFV = this.regFV; | |
this.cntV = this.regV; | |
this.cntH = this.regH; | |
this.cntVT = this.regVT; | |
this.cntHT = this.regHT; | |
this.checkSprite0(this.scanline-20); | |
} | |
this.firstWrite = !this.firstWrite; | |
// Invoke mapper latch: | |
this.cntsToAddress(); | |
if (this.vramAddress < 0x2000) { | |
this.nes.mmap.latchAccess(this.vramAddress); | |
} | |
}, | |
// CPU Register $2007(R): | |
// Read from PPU memory. The address should be set first. | |
vramLoad: function(){ | |
var tmp; | |
this.cntsToAddress(); | |
this.regsToAddress(); | |
// If address is in range 0x0000-0x3EFF, return buffered values: | |
if (this.vramAddress <= 0x3EFF) { | |
tmp = this.vramBufferedReadValue; | |
// Update buffered value: | |
if (this.vramAddress < 0x2000) { | |
this.vramBufferedReadValue = this.vramMem[this.vramAddress]; | |
} | |
else { | |
this.vramBufferedReadValue = this.mirroredLoad( | |
this.vramAddress | |
); | |
} | |
// Mapper latch access: | |
if (this.vramAddress < 0x2000) { | |
this.nes.mmap.latchAccess(this.vramAddress); | |
} | |
// Increment by either 1 or 32, depending on d2 of Control Register 1: | |
this.vramAddress += (this.f_addrInc == 1 ? 32 : 1); | |
this.cntsFromAddress(); | |
this.regsFromAddress(); | |
return tmp; // Return the previous buffered value. | |
} | |
// No buffering in this mem range. Read normally. | |
tmp = this.mirroredLoad(this.vramAddress); | |
// Increment by either 1 or 32, depending on d2 of Control Register 1: | |
this.vramAddress += (this.f_addrInc == 1 ? 32 : 1); | |
this.cntsFromAddress(); | |
this.regsFromAddress(); | |
return tmp; | |
}, | |
// CPU Register $2007(W): | |
// Write to PPU memory. The address should be set first. | |
vramWrite: function(value){ | |
this.triggerRendering(); | |
this.cntsToAddress(); | |
this.regsToAddress(); | |
if (this.vramAddress >= 0x2000) { | |
// Mirroring is used. | |
this.mirroredWrite(this.vramAddress,value); | |
}else { | |
// Write normally. | |
this.writeMem(this.vramAddress,value); | |
// Invoke mapper latch: | |
this.nes.mmap.latchAccess(this.vramAddress); | |
} | |
// Increment by either 1 or 32, depending on d2 of Control Register 1: | |
this.vramAddress += (this.f_addrInc==1?32:1); | |
this.regsFromAddress(); | |
this.cntsFromAddress(); | |
}, | |
// CPU Register $4014: | |
// Write 256 bytes of main memory | |
// into Sprite RAM. | |
sramDMA: function(value){ | |
var baseAddress = value * 0x100; | |
var data; | |
for (var i=this.sramAddress; i < 256; i++) { | |
data = this.nes.cpu.mem[baseAddress+i]; | |
this.spriteMem[i] = data; | |
this.spriteRamWriteUpdate(i, data); | |
} | |
this.nes.cpu.haltCycles(513); | |
}, | |
// Updates the scroll registers from a new VRAM address. | |
regsFromAddress: function(){ | |
var address = (this.vramTmpAddress>>8)&0xFF; | |
this.regFV = (address>>4)&7; | |
this.regV = (address>>3)&1; | |
this.regH = (address>>2)&1; | |
this.regVT = (this.regVT&7) | ((address&3)<<3); | |
address = this.vramTmpAddress&0xFF; | |
this.regVT = (this.regVT&24) | ((address>>5)&7); | |
this.regHT = address&31; | |
}, | |
// Updates the scroll registers from a new VRAM address. | |
cntsFromAddress: function(){ | |
var address = (this.vramAddress>>8)&0xFF; | |
this.cntFV = (address>>4)&3; | |
this.cntV = (address>>3)&1; | |
this.cntH = (address>>2)&1; | |
this.cntVT = (this.cntVT&7) | ((address&3)<<3); | |
address = this.vramAddress&0xFF; | |
this.cntVT = (this.cntVT&24) | ((address>>5)&7); | |
this.cntHT = address&31; | |
}, | |
regsToAddress: function(){ | |
var b1 = (this.regFV&7)<<4; | |
b1 |= (this.regV&1)<<3; | |
b1 |= (this.regH&1)<<2; | |
b1 |= (this.regVT>>3)&3; | |
var b2 = (this.regVT&7)<<5; | |
b2 |= this.regHT&31; | |
this.vramTmpAddress = ((b1<<8) | b2)&0x7FFF; | |
}, | |
cntsToAddress: function(){ | |
var b1 = (this.cntFV&7)<<4; | |
b1 |= (this.cntV&1)<<3; | |
b1 |= (this.cntH&1)<<2; | |
b1 |= (this.cntVT>>3)&3; | |
var b2 = (this.cntVT&7)<<5; | |
b2 |= this.cntHT&31; | |
this.vramAddress = ((b1<<8) | b2)&0x7FFF; | |
}, | |
incTileCounter: function(count) { | |
for (var i=count; i!==0; i--) { | |
this.cntHT++; | |
if (this.cntHT == 32) { | |
this.cntHT = 0; | |
this.cntVT++; | |
if (this.cntVT >= 30) { | |
this.cntH++; | |
if(this.cntH == 2) { | |
this.cntH = 0; | |
this.cntV++; | |
if (this.cntV == 2) { | |
this.cntV = 0; | |
this.cntFV++; | |
this.cntFV &= 0x7; | |
} | |
} | |
} | |
} | |
} | |
}, | |
// Reads from memory, taking into account | |
// mirroring/mapping of address ranges. | |
mirroredLoad: function(address) { | |
return this.vramMem[this.vramMirrorTable[address]]; | |
}, | |
// Writes to memory, taking into account | |
// mirroring/mapping of address ranges. | |
mirroredWrite: function(address, value){ | |
if (address>=0x3f00 && address<0x3f20) { | |
// Palette write mirroring. | |
if (address==0x3F00 || address==0x3F10) { | |
this.writeMem(0x3F00,value); | |
this.writeMem(0x3F10,value); | |
}else if (address==0x3F04 || address==0x3F14) { | |
this.writeMem(0x3F04,value); | |
this.writeMem(0x3F14,value); | |
}else if (address==0x3F08 || address==0x3F18) { | |
this.writeMem(0x3F08,value); | |
this.writeMem(0x3F18,value); | |
}else if (address==0x3F0C || address==0x3F1C) { | |
this.writeMem(0x3F0C,value); | |
this.writeMem(0x3F1C,value); | |
}else { | |
this.writeMem(address,value); | |
} | |
}else { | |
// Use lookup table for mirrored address: | |
if (address<this.vramMirrorTable.length) { | |
this.writeMem(this.vramMirrorTable[address],value); | |
}else { | |
// FIXME | |
alert("Invalid VRAM address: "+address.toString(16)); | |
} | |
} | |
}, | |
triggerRendering: function(){ | |
if (this.scanline >= 21 && this.scanline <= 260) { | |
// Render sprites, and combine: | |
this.renderFramePartially( | |
this.lastRenderedScanline+1, | |
this.scanline-21-this.lastRenderedScanline | |
); | |
// Set last rendered scanline: | |
this.lastRenderedScanline = this.scanline-21; | |
} | |
}, | |
renderFramePartially: function(startScan, scanCount){ | |
if (this.f_spVisibility == 1) { | |
this.renderSpritesPartially(startScan,scanCount,true); | |
} | |
if(this.f_bgVisibility == 1) { | |
var si = startScan<<8; | |
var ei = (startScan+scanCount)<<8; | |
if (ei > 0xF000) { | |
ei = 0xF000; | |
} | |
var buffer = this.buffer; | |
var bgbuffer = this.bgbuffer; | |
var pixrendered = this.pixrendered; | |
for (var destIndex=si; destIndex<ei; destIndex++) { | |
if (pixrendered[destIndex] > 0xFF) { | |
buffer[destIndex] = bgbuffer[destIndex]; | |
} | |
} | |
} | |
if (this.f_spVisibility == 1) { | |
this.renderSpritesPartially(startScan, scanCount, false); | |
} | |
this.validTileData = false; | |
}, | |
renderBgScanline: function(bgbuffer, scan) { | |
var baseTile = (this.regS === 0 ? 0 : 256); | |
var destIndex = (scan<<8)-this.regFH; | |
this.curNt = this.ntable1[this.cntV+this.cntV+this.cntH]; | |
this.cntHT = this.regHT; | |
this.cntH = this.regH; | |
this.curNt = this.ntable1[this.cntV+this.cntV+this.cntH]; | |
if (scan<240 && (scan-this.cntFV)>=0){ | |
var tscanoffset = this.cntFV<<3; | |
var scantile = this.scantile; | |
var attrib = this.attrib; | |
var ptTile = this.ptTile; | |
var nameTable = this.nameTable; | |
var imgPalette = this.imgPalette; | |
var pixrendered = this.pixrendered; | |
var targetBuffer = bgbuffer ? this.bgbuffer : this.buffer; | |
var t, tpix, att, col; | |
for (var tile=0;tile<32;tile++) { | |
if (scan>=0) { | |
// Fetch tile & attrib data: | |
if (this.validTileData) { | |
// Get data from array: | |
t = scantile[tile]; | |
tpix = t.pix; | |
att = attrib[tile]; | |
}else { | |
// Fetch data: | |
t = ptTile[baseTile+nameTable[this.curNt].getTileIndex(this.cntHT,this.cntVT)]; | |
tpix = t.pix; | |
att = nameTable[this.curNt].getAttrib(this.cntHT,this.cntVT); | |
scantile[tile] = t; | |
attrib[tile] = att; | |
} | |
// Render tile scanline: | |
var sx = 0; | |
var x = (tile<<3)-this.regFH; | |
if (x>-8) { | |
if (x<0) { | |
destIndex-=x; | |
sx = -x; | |
} | |
if (t.opaque[this.cntFV]) { | |
for (;sx<8;sx++) { | |
targetBuffer[destIndex] = imgPalette[ | |
tpix[tscanoffset+sx]+att | |
]; | |
pixrendered[destIndex] |= 256; | |
destIndex++; | |
} | |
}else { | |
for (;sx<8;sx++) { | |
col = tpix[tscanoffset+sx]; | |
if(col !== 0) { | |
targetBuffer[destIndex] = imgPalette[ | |
col+att | |
]; | |
pixrendered[destIndex] |= 256; | |
} | |
destIndex++; | |
} | |
} | |
} | |
} | |
// Increase Horizontal Tile Counter: | |
if (++this.cntHT==32) { | |
this.cntHT=0; | |
this.cntH++; | |
this.cntH%=2; | |
this.curNt = this.ntable1[(this.cntV<<1)+this.cntH]; | |
} | |
} | |
// Tile data for one row should now have been fetched, | |
// so the data in the array is valid. | |
this.validTileData = true; | |
} | |
// update vertical scroll: | |
this.cntFV++; | |
if (this.cntFV==8) { | |
this.cntFV = 0; | |
this.cntVT++; | |
if (this.cntVT==30) { | |
this.cntVT = 0; | |
this.cntV++; | |
this.cntV%=2; | |
this.curNt = this.ntable1[(this.cntV<<1)+this.cntH]; | |
}else if (this.cntVT==32) { | |
this.cntVT = 0; | |
} | |
// Invalidate fetched data: | |
this.validTileData = false; | |
} | |
}, | |
renderSpritesPartially: function(startscan, scancount, bgPri){ | |
if (this.f_spVisibility === 1) { | |
for (var i=0;i<64;i++) { | |
if (this.bgPriority[i]==bgPri && this.sprX[i]>=0 && | |
this.sprX[i]<256 && this.sprY[i]+8>=startscan && | |
this.sprY[i]<startscan+scancount) { | |
// Show sprite. | |
if (this.f_spriteSize === 0) { | |
// 8x8 sprites | |
this.srcy1 = 0; | |
this.srcy2 = 8; | |
if (this.sprY[i]<startscan) { | |
this.srcy1 = startscan - this.sprY[i]-1; | |
} | |
if (this.sprY[i]+8 > startscan+scancount) { | |
this.srcy2 = startscan+scancount-this.sprY[i]+1; | |
} | |
if (this.f_spPatternTable===0) { | |
this.ptTile[this.sprTile[i]].render(this.buffer, | |
0, this.srcy1, 8, this.srcy2, this.sprX[i], | |
this.sprY[i]+1, this.sprCol[i], this.sprPalette, | |
this.horiFlip[i], this.vertFlip[i], i, | |
this.pixrendered | |
); | |
}else { | |
this.ptTile[this.sprTile[i]+256].render(this.buffer, 0, this.srcy1, 8, this.srcy2, this.sprX[i], this.sprY[i]+1, this.sprCol[i], this.sprPalette, this.horiFlip[i], this.vertFlip[i], i, this.pixrendered); | |
} | |
}else { | |
// 8x16 sprites | |
var top = this.sprTile[i]; | |
if ((top&1)!==0) { | |
top = this.sprTile[i]-1+256; | |
} | |
var srcy1 = 0; | |
var srcy2 = 8; | |
if (this.sprY[i]<startscan) { | |
srcy1 = startscan - this.sprY[i]-1; | |
} | |
if (this.sprY[i]+8 > startscan+scancount) { | |
srcy2 = startscan+scancount-this.sprY[i]; | |
} | |
this.ptTile[top+(this.vertFlip[i]?1:0)].render( | |
this.buffer, | |
0, | |
srcy1, | |
8, | |
srcy2, | |
this.sprX[i], | |
this.sprY[i]+1, | |
this.sprCol[i], | |
this.sprPalette, | |
this.horiFlip[i], | |
this.vertFlip[i], | |
i, | |
this.pixrendered | |
); | |
srcy1 = 0; | |
srcy2 = 8; | |
if (this.sprY[i]+8<startscan) { | |
srcy1 = startscan - (this.sprY[i]+8+1); | |
} | |
if (this.sprY[i]+16 > startscan+scancount) { | |
srcy2 = startscan+scancount-(this.sprY[i]+8); | |
} | |
this.ptTile[top+(this.vertFlip[i]?0:1)].render( | |
this.buffer, | |
0, | |
srcy1, | |
8, | |
srcy2, | |
this.sprX[i], | |
this.sprY[i]+1+8, | |
this.sprCol[i], | |
this.sprPalette, | |
this.horiFlip[i], | |
this.vertFlip[i], | |
i, | |
this.pixrendered | |
); | |
} | |
} | |
} | |
} | |
}, | |
checkSprite0: function(scan){ | |
this.spr0HitX = -1; | |
this.spr0HitY = -1; | |
var toffset; | |
var tIndexAdd = (this.f_spPatternTable === 0?0:256); | |
var x, y, t, i; | |
var bufferIndex; | |
var col; | |
var bgPri; | |
x = this.sprX[0]; | |
y = this.sprY[0]+1; | |
if (this.f_spriteSize === 0) { | |
// 8x8 sprites. | |
// Check range: | |
if (y <= scan && y + 8 > scan && x >= -7 && x < 256) { | |
// Sprite is in range. | |
// Draw scanline: | |
t = this.ptTile[this.sprTile[0] + tIndexAdd]; | |
col = this.sprCol[0]; | |
bgPri = this.bgPriority[0]; | |
if (this.vertFlip[0]) { | |
toffset = 7 - (scan -y); | |
} | |
else { | |
toffset = scan - y; | |
} | |
toffset *= 8; | |
bufferIndex = scan * 256 + x; | |
if (this.horiFlip[0]) { | |
for (i = 7; i >= 0; i--) { | |
if (x >= 0 && x < 256) { | |
if (bufferIndex>=0 && bufferIndex<61440 && | |
this.pixrendered[bufferIndex] !==0 ) { | |
if (t.pix[toffset+i] !== 0) { | |
this.spr0HitX = bufferIndex % 256; | |
this.spr0HitY = scan; | |
return true; | |
} | |
} | |
} | |
x++; | |
bufferIndex++; | |
} | |
} | |
else { | |
for (i = 0; i < 8; i++) { | |
if (x >= 0 && x < 256) { | |
if (bufferIndex >= 0 && bufferIndex < 61440 && | |
this.pixrendered[bufferIndex] !==0 ) { | |
if (t.pix[toffset+i] !== 0) { | |
this.spr0HitX = bufferIndex % 256; | |
this.spr0HitY = scan; | |
return true; | |
} | |
} | |
} | |
x++; | |
bufferIndex++; | |
} | |
} | |
} | |
} | |
else { | |
// 8x16 sprites: | |
// Check range: | |
if (y <= scan && y + 16 > scan && x >= -7 && x < 256) { | |
// Sprite is in range. | |
// Draw scanline: | |
if (this.vertFlip[0]) { | |
toffset = 15-(scan-y); | |
}else { | |
toffset = scan-y; | |
} | |
if (toffset<8) { | |
// first half of sprite. | |
t = this.ptTile[this.sprTile[0]+(this.vertFlip[0]?1:0)+((this.sprTile[0]&1)!==0?255:0)]; | |
}else { | |
// second half of sprite. | |
t = this.ptTile[this.sprTile[0]+(this.vertFlip[0]?0:1)+((this.sprTile[0]&1)!==0?255:0)]; | |
if (this.vertFlip[0]) { | |
toffset = 15-toffset; | |
} | |
else { | |
toffset -= 8; | |
} | |
} | |
toffset*=8; | |
col = this.sprCol[0]; | |
bgPri = this.bgPriority[0]; | |
bufferIndex = scan*256+x; | |
if (this.horiFlip[0]) { | |
for (i=7;i>=0;i--) { | |
if (x>=0 && x<256) { | |
if (bufferIndex>=0 && bufferIndex<61440 && this.pixrendered[bufferIndex]!==0) { | |
if (t.pix[toffset+i] !== 0) { | |
this.spr0HitX = bufferIndex%256; | |
this.spr0HitY = scan; | |
return true; | |
} | |
} | |
} | |
x++; | |
bufferIndex++; | |
} | |
} | |
else { | |
for (i=0;i<8;i++) { | |
if (x>=0 && x<256) { | |
if (bufferIndex>=0 && bufferIndex<61440 && this.pixrendered[bufferIndex]!==0) { | |
if (t.pix[toffset+i] !== 0) { | |
this.spr0HitX = bufferIndex%256; | |
this.spr0HitY = scan; | |
return true; | |
} | |
} | |
} | |
x++; | |
bufferIndex++; | |
} | |
} | |
} | |
} | |
return false; | |
}, | |
// This will write to PPU memory, and | |
// update internally buffered data | |
// appropriately. | |
writeMem: function(address, value){ | |
this.vramMem[address] = value; | |
// Update internally buffered data: | |
if (address < 0x2000) { | |
this.vramMem[address] = value; | |
this.patternWrite(address,value); | |
} | |
else if (address >=0x2000 && address <0x23c0) { | |
this.nameTableWrite(this.ntable1[0], address - 0x2000, value); | |
} | |
else if (address >=0x23c0 && address <0x2400) { | |
this.attribTableWrite(this.ntable1[0],address-0x23c0,value); | |
} | |
else if (address >=0x2400 && address <0x27c0) { | |
this.nameTableWrite(this.ntable1[1],address-0x2400,value); | |
} | |
else if (address >=0x27c0 && address <0x2800) { | |
this.attribTableWrite(this.ntable1[1],address-0x27c0,value); | |
} | |
else if (address >=0x2800 && address <0x2bc0) { | |
this.nameTableWrite(this.ntable1[2],address-0x2800,value); | |
} | |
else if (address >=0x2bc0 && address <0x2c00) { | |
this.attribTableWrite(this.ntable1[2],address-0x2bc0,value); | |
} | |
else if (address >=0x2c00 && address <0x2fc0) { | |
this.nameTableWrite(this.ntable1[3],address-0x2c00,value); | |
} | |
else if (address >=0x2fc0 && address <0x3000) { | |
this.attribTableWrite(this.ntable1[3],address-0x2fc0,value); | |
} | |
else if (address >=0x3f00 && address <0x3f20) { | |
this.updatePalettes(); | |
} | |
}, | |
// Reads data from $3f00 to $f20 | |
// into the two buffered palettes. | |
updatePalettes: function(){ | |
var i; | |
for (i = 0; i < 16; i++) { | |
if (this.f_dispType === 0) { | |
this.imgPalette[i] = this.palTable.getEntry( | |
this.vramMem[0x3f00 + i] & 63 | |
); | |
} | |
else { | |
this.imgPalette[i] = this.palTable.getEntry( | |
this.vramMem[0x3f00 + i] & 32 | |
); | |
} | |
} | |
for (i = 0; i < 16; i++) { | |
if (this.f_dispType === 0) { | |
this.sprPalette[i] = this.palTable.getEntry( | |
this.vramMem[0x3f10 + i] & 63 | |
); | |
} | |
else { | |
this.sprPalette[i] = this.palTable.getEntry( | |
this.vramMem[0x3f10 + i] & 32 | |
); | |
} | |
} | |
}, | |
// Updates the internal pattern | |
// table buffers with this new byte. | |
// In vNES, there is a version of this with 4 arguments which isn't used. | |
patternWrite: function(address, value){ | |
var tileIndex = Math.floor(address / 16); | |
var leftOver = address%16; | |
if (leftOver<8) { | |
this.ptTile[tileIndex].setScanline( | |
leftOver, | |
value, | |
this.vramMem[address+8] | |
); | |
} | |
else { | |
this.ptTile[tileIndex].setScanline( | |
leftOver-8, | |
this.vramMem[address-8], | |
value | |
); | |
} | |
}, | |
// Updates the internal name table buffers | |
// with this new byte. | |
nameTableWrite: function(index, address, value){ | |
this.nameTable[index].tile[address] = value; | |
// Update Sprite #0 hit: | |
//updateSpr0Hit(); | |
this.checkSprite0(this.scanline-20); | |
}, | |
// Updates the internal pattern | |
// table buffers with this new attribute | |
// table byte. | |
attribTableWrite: function(index, address, value){ | |
this.nameTable[index].writeAttrib(address,value); | |
}, | |
// Updates the internally buffered sprite | |
// data with this new byte of info. | |
spriteRamWriteUpdate: function(address, value) { | |
var tIndex = Math.floor(address / 4); | |
if (tIndex === 0) { | |
//updateSpr0Hit(); | |
this.checkSprite0(this.scanline - 20); | |
} | |
if (address % 4 === 0) { | |
// Y coordinate | |
this.sprY[tIndex] = value; | |
} | |
else if (address % 4 == 1) { | |
// Tile index | |
this.sprTile[tIndex] = value; | |
} | |
else if (address % 4 == 2) { | |
// Attributes | |
this.vertFlip[tIndex] = ((value & 0x80) !== 0); | |
this.horiFlip[tIndex] = ((value & 0x40) !==0 ); | |
this.bgPriority[tIndex] = ((value & 0x20) !== 0); | |
this.sprCol[tIndex] = (value & 3) << 2; | |
} | |
else if (address % 4 == 3) { | |
// X coordinate | |
this.sprX[tIndex] = value; | |
} | |
}, | |
doNMI: function() { | |
// Set VBlank flag: | |
this.setStatusFlag(this.STATUS_VBLANK,true); | |
//nes.getCpu().doNonMaskableInterrupt(); | |
this.nes.cpu.requestIrq(this.nes.cpu.IRQ_NMI); | |
}, | |
JSON_PROPERTIES: [ | |
// Memory | |
'vramMem', 'spriteMem', | |
// Counters | |
'cntFV', 'cntV', 'cntH', 'cntVT', 'cntHT', | |
// Registers | |
'regFV', 'regV', 'regH', 'regVT', 'regHT', 'regFH', 'regS', | |
// VRAM addr | |
'vramAddress', 'vramTmpAddress', | |
// Control/Status registers | |
'f_nmiOnVblank', 'f_spriteSize', 'f_bgPatternTable', 'f_spPatternTable', | |
'f_addrInc', 'f_nTblAddress', 'f_color', 'f_spVisibility', | |
'f_bgVisibility', 'f_spClipping', 'f_bgClipping', 'f_dispType', | |
// VRAM I/O | |
'vramBufferedReadValue', 'firstWrite', | |
// Mirroring | |
'currentMirroring', 'vramMirrorTable', 'ntable1', | |
// SPR-RAM I/O | |
'sramAddress', | |
// Sprites. Most sprite data is rebuilt from spriteMem | |
'hitSpr0', | |
// Palettes | |
'sprPalette', 'imgPalette', | |
// Rendering progression | |
'curX', 'scanline', 'lastRenderedScanline', 'curNt', 'scantile', | |
// Used during rendering | |
'attrib', 'buffer', 'bgbuffer', 'pixrendered', | |
// Misc | |
'requestEndFrame', 'nmiOk', 'dummyCycleToggle', 'nmiCounter', | |
'validTileData', 'scanlineAlreadyRendered' | |
], | |
toJSON: function() { | |
var i; | |
var state = JSNES.Utils.toJSON(this); | |
state.nameTable = []; | |
for (i = 0; i < this.nameTable.length; i++) { | |
state.nameTable[i] = this.nameTable[i].toJSON(); | |
} | |
state.ptTile = []; | |
for (i = 0; i < this.ptTile.length; i++) { | |
state.ptTile[i] = this.ptTile[i].toJSON(); | |
} | |
return state; | |
}, | |
fromJSON: function(state) { | |
var i; | |
JSNES.Utils.fromJSON(this, state); | |
for (i = 0; i < this.nameTable.length; i++) { | |
this.nameTable[i].fromJSON(state.nameTable[i]); | |
} | |
for (i = 0; i < this.ptTile.length; i++) { | |
this.ptTile[i].fromJSON(state.ptTile[i]); | |
} | |
// Sprite data: | |
for (i = 0; i < this.spriteMem.length; i++) { | |
this.spriteRamWriteUpdate(i, this.spriteMem[i]); | |
} | |
} | |
}; | |
JSNES.PPU.NameTable = function(width, height, name) { | |
this.width = width; | |
this.height = height; | |
this.name = name; | |
this.tile = new Array(width*height); | |
this.attrib = new Array(width*height); | |
}; | |
JSNES.PPU.NameTable.prototype = { | |
getTileIndex: function(x, y){ | |
return this.tile[y*this.width+x]; | |
}, | |
getAttrib: function(x, y){ | |
return this.attrib[y*this.width+x]; | |
}, | |
writeAttrib: function(index, value){ | |
var basex = (index % 8) * 4; | |
var basey = Math.floor(index / 8) * 4; | |
var add; | |
var tx, ty; | |
var attindex; | |
for (var sqy=0;sqy<2;sqy++) { | |
for (var sqx=0;sqx<2;sqx++) { | |
add = (value>>(2*(sqy*2+sqx)))&3; | |
for (var y=0;y<2;y++) { | |
for (var x=0;x<2;x++) { | |
tx = basex+sqx*2+x; | |
ty = basey+sqy*2+y; | |
attindex = ty*this.width+tx; | |
this.attrib[ty*this.width+tx] = (add<<2)&12; | |
} | |
} | |
} | |
} | |
}, | |
toJSON: function() { | |
return { | |
'tile': this.tile, | |
'attrib': this.attrib | |
}; | |
}, | |
fromJSON: function(s) { | |
this.tile = s.tile; | |
this.attrib = s.attrib; | |
} | |
}; | |
JSNES.PPU.PaletteTable = function() { | |
this.curTable = new Array(64); | |
this.emphTable = new Array(8); | |
this.currentEmph = -1; | |
}; | |
JSNES.PPU.PaletteTable.prototype = { | |
reset: function() { | |
this.setEmphasis(0); | |
}, | |
loadNTSCPalette: function() { | |
this.curTable = [0x525252, 0xB40000, 0xA00000, 0xB1003D, 0x740069, 0x00005B, 0x00005F, 0x001840, 0x002F10, 0x084A08, 0x006700, 0x124200, 0x6D2800, 0x000000, 0x000000, 0x000000, 0xC4D5E7, 0xFF4000, 0xDC0E22, 0xFF476B, 0xD7009F, 0x680AD7, 0x0019BC, 0x0054B1, 0x006A5B, 0x008C03, 0x00AB00, 0x2C8800, 0xA47200, 0x000000, 0x000000, 0x000000, 0xF8F8F8, 0xFFAB3C, 0xFF7981, 0xFF5BC5, 0xFF48F2, 0xDF49FF, 0x476DFF, 0x00B4F7, 0x00E0FF, 0x00E375, 0x03F42B, 0x78B82E, 0xE5E218, 0x787878, 0x000000, 0x000000, 0xFFFFFF, 0xFFF2BE, 0xF8B8B8, 0xF8B8D8, 0xFFB6FF, 0xFFC3FF, 0xC7D1FF, 0x9ADAFF, 0x88EDF8, 0x83FFDD, 0xB8F8B8, 0xF5F8AC, 0xFFFFB0, 0xF8D8F8, 0x000000, 0x000000]; | |
this.makeTables(); | |
this.setEmphasis(0); | |
}, | |
loadPALPalette: function() { | |
this.curTable = [0x525252, 0xB40000, 0xA00000, 0xB1003D, 0x740069, 0x00005B, 0x00005F, 0x001840, 0x002F10, 0x084A08, 0x006700, 0x124200, 0x6D2800, 0x000000, 0x000000, 0x000000, 0xC4D5E7, 0xFF4000, 0xDC0E22, 0xFF476B, 0xD7009F, 0x680AD7, 0x0019BC, 0x0054B1, 0x006A5B, 0x008C03, 0x00AB00, 0x2C8800, 0xA47200, 0x000000, 0x000000, 0x000000, 0xF8F8F8, 0xFFAB3C, 0xFF7981, 0xFF5BC5, 0xFF48F2, 0xDF49FF, 0x476DFF, 0x00B4F7, 0x00E0FF, 0x00E375, 0x03F42B, 0x78B82E, 0xE5E218, 0x787878, 0x000000, 0x000000, 0xFFFFFF, 0xFFF2BE, 0xF8B8B8, 0xF8B8D8, 0xFFB6FF, 0xFFC3FF, 0xC7D1FF, 0x9ADAFF, 0x88EDF8, 0x83FFDD, 0xB8F8B8, 0xF5F8AC, 0xFFFFB0, 0xF8D8F8, 0x000000, 0x000000]; | |
this.makeTables(); | |
this.setEmphasis(0); | |
}, | |
makeTables: function(){ | |
var r, g, b, col, i, rFactor, gFactor, bFactor; | |
// Calculate a table for each possible emphasis setting: | |
for (var emph = 0; emph < 8; emph++) { | |
// Determine color component factors: | |
rFactor = 1.0; | |
gFactor = 1.0; | |
bFactor = 1.0; | |
if ((emph & 1) !== 0) { | |
rFactor = 0.75; | |
bFactor = 0.75; | |
} | |
if ((emph & 2) !== 0) { | |
rFactor = 0.75; | |
gFactor = 0.75; | |
} | |
if ((emph & 4) !== 0) { | |
gFactor = 0.75; | |
bFactor = 0.75; | |
} | |
this.emphTable[emph] = new Array(64); | |
// Calculate table: | |
for (i = 0; i < 64; i++) { | |
col = this.curTable[i]; | |
r = Math.floor(this.getRed(col) * rFactor); | |
g = Math.floor(this.getGreen(col) * gFactor); | |
b = Math.floor(this.getBlue(col) * bFactor); | |
this.emphTable[emph][i] = this.getRgb(r, g, b); | |
} | |
} | |
}, | |
setEmphasis: function(emph){ | |
if (emph != this.currentEmph) { | |
this.currentEmph = emph; | |
for (var i = 0; i < 64; i++) { | |
this.curTable[i] = this.emphTable[emph][i]; | |
} | |
} | |
}, | |
getEntry: function(yiq){ | |
return this.curTable[yiq]; | |
}, | |
getRed: function(rgb){ | |
return (rgb>>16)&0xFF; | |
}, | |
getGreen: function(rgb){ | |
return (rgb>>8)&0xFF; | |
}, | |
getBlue: function(rgb){ | |
return rgb&0xFF; | |
}, | |
getRgb: function(r, g, b){ | |
return ((r<<16)|(g<<8)|(b)); | |
}, | |
loadDefaultPalette: function(){ | |
this.curTable[ 0] = this.getRgb(117,117,117); | |
this.curTable[ 1] = this.getRgb( 39, 27,143); | |
this.curTable[ 2] = this.getRgb( 0, 0,171); | |
this.curTable[ 3] = this.getRgb( 71, 0,159); | |
this.curTable[ 4] = this.getRgb(143, 0,119); | |
this.curTable[ 5] = this.getRgb(171, 0, 19); | |
this.curTable[ 6] = this.getRgb(167, 0, 0); | |
this.curTable[ 7] = this.getRgb(127, 11, 0); | |
this.curTable[ 8] = this.getRgb( 67, 47, 0); | |
this.curTable[ 9] = this.getRgb( 0, 71, 0); | |
this.curTable[10] = this.getRgb( 0, 81, 0); | |
this.curTable[11] = this.getRgb( 0, 63, 23); | |
this.curTable[12] = this.getRgb( 27, 63, 95); | |
this.curTable[13] = this.getRgb( 0, 0, 0); | |
this.curTable[14] = this.getRgb( 0, 0, 0); | |
this.curTable[15] = this.getRgb( 0, 0, 0); | |
this.curTable[16] = this.getRgb(188,188,188); | |
this.curTable[17] = this.getRgb( 0,115,239); | |
this.curTable[18] = this.getRgb( 35, 59,239); | |
this.curTable[19] = this.getRgb(131, 0,243); | |
this.curTable[20] = this.getRgb(191, 0,191); | |
this.curTable[21] = this.getRgb(231, 0, 91); | |
this.curTable[22] = this.getRgb(219, 43, 0); | |
this.curTable[23] = this.getRgb(203, 79, 15); | |
this.curTable[24] = this.getRgb(139,115, 0); | |
this.curTable[25] = this.getRgb( 0,151, 0); | |
this.curTable[26] = this.getRgb( 0,171, 0); | |
this.curTable[27] = this.getRgb( 0,147, 59); | |
this.curTable[28] = this.getRgb( 0,131,139); | |
this.curTable[29] = this.getRgb( 0, 0, 0); | |
this.curTable[30] = this.getRgb( 0, 0, 0); | |
this.curTable[31] = this.getRgb( 0, 0, 0); | |
this.curTable[32] = this.getRgb(255,255,255); | |
this.curTable[33] = this.getRgb( 63,191,255); | |
this.curTable[34] = this.getRgb( 95,151,255); | |
this.curTable[35] = this.getRgb(167,139,253); | |
this.curTable[36] = this.getRgb(247,123,255); | |
this.curTable[37] = this.getRgb(255,119,183); | |
this.curTable[38] = this.getRgb(255,119, 99); | |
this.curTable[39] = this.getRgb(255,155, 59); | |
this.curTable[40] = this.getRgb(243,191, 63); | |
this.curTable[41] = this.getRgb(131,211, 19); | |
this.curTable[42] = this.getRgb( 79,223, 75); | |
this.curTable[43] = this.getRgb( 88,248,152); | |
this.curTable[44] = this.getRgb( 0,235,219); | |
this.curTable[45] = this.getRgb( 0, 0, 0); | |
this.curTable[46] = this.getRgb( 0, 0, 0); | |
this.curTable[47] = this.getRgb( 0, 0, 0); | |
this.curTable[48] = this.getRgb(255,255,255); | |
this.curTable[49] = this.getRgb(171,231,255); | |
this.curTable[50] = this.getRgb(199,215,255); | |
this.curTable[51] = this.getRgb(215,203,255); | |
this.curTable[52] = this.getRgb(255,199,255); | |
this.curTable[53] = this.getRgb(255,199,219); | |
this.curTable[54] = this.getRgb(255,191,179); | |
this.curTable[55] = this.getRgb(255,219,171); | |
this.curTable[56] = this.getRgb(255,231,163); | |
this.curTable[57] = this.getRgb(227,255,163); | |
this.curTable[58] = this.getRgb(171,243,191); | |
this.curTable[59] = this.getRgb(179,255,207); | |
this.curTable[60] = this.getRgb(159,255,243); | |
this.curTable[61] = this.getRgb( 0, 0, 0); | |
this.curTable[62] = this.getRgb( 0, 0, 0); | |
this.curTable[63] = this.getRgb( 0, 0, 0); | |
this.makeTables(); | |
this.setEmphasis(0); | |
} | |
}; | |
JSNES.PPU.Tile = function() { | |
// Tile data: | |
this.pix = new Array(64); | |
this.fbIndex = null; | |
this.tIndex = null; | |
this.x = null; | |
this.y = null; | |
this.w = null; | |
this.h = null; | |
this.incX = null; | |
this.incY = null; | |
this.palIndex = null; | |
this.tpri = null; | |
this.c = null; | |
this.initialized = false; | |
this.opaque = new Array(8); | |
}; | |
JSNES.PPU.Tile.prototype = { | |
setBuffer: function(scanline){ | |
for (this.y=0;this.y<8;this.y++) { | |
this.setScanline(this.y,scanline[this.y],scanline[this.y+8]); | |
} | |
}, | |
setScanline: function(sline, b1, b2){ | |
this.initialized = true; | |
this.tIndex = sline<<3; | |
for (this.x = 0; this.x < 8; this.x++) { | |
this.pix[this.tIndex + this.x] = ((b1 >> (7 - this.x)) & 1) + | |
(((b2 >> (7 - this.x)) & 1) << 1); | |
if(this.pix[this.tIndex+this.x] === 0) { | |
this.opaque[sline] = false; | |
} | |
} | |
}, | |
render: function(buffer, srcx1, srcy1, srcx2, srcy2, dx, dy, palAdd, palette, flipHorizontal, flipVertical, pri, priTable) { | |
if (dx<-7 || dx>=256 || dy<-7 || dy>=240) { | |
return; | |
} | |
this.w=srcx2-srcx1; | |
this.h=srcy2-srcy1; | |
if (dx<0) { | |
srcx1-=dx; | |
} | |
if (dx+srcx2>=256) { | |
srcx2=256-dx; | |
} | |
if (dy<0) { | |
srcy1-=dy; | |
} | |
if (dy+srcy2>=240) { | |
srcy2=240-dy; | |
} | |
if (!flipHorizontal && !flipVertical) { | |
this.fbIndex = (dy<<8)+dx; | |
this.tIndex = 0; | |
for (this.y=0;this.y<8;this.y++) { | |
for (this.x=0;this.x<8;this.x++) { | |
if (this.x>=srcx1 && this.x<srcx2 && this.y>=srcy1 && this.y<srcy2) { | |
this.palIndex = this.pix[this.tIndex]; | |
this.tpri = priTable[this.fbIndex]; | |
if (this.palIndex!==0 && pri<=(this.tpri&0xFF)) { | |
//console.log("Rendering upright tile to buffer"); | |
buffer[this.fbIndex] = palette[this.palIndex+palAdd]; | |
this.tpri = (this.tpri&0xF00)|pri; | |
priTable[this.fbIndex] =this.tpri; | |
} | |
} | |
this.fbIndex++; | |
this.tIndex++; | |
} | |
this.fbIndex-=8; | |
this.fbIndex+=256; | |
} | |
}else if (flipHorizontal && !flipVertical) { | |
this.fbIndex = (dy<<8)+dx; | |
this.tIndex = 7; | |
for (this.y=0;this.y<8;this.y++) { | |
for (this.x=0;this.x<8;this.x++) { | |
if (this.x>=srcx1 && this.x<srcx2 && this.y>=srcy1 && this.y<srcy2) { | |
this.palIndex = this.pix[this.tIndex]; | |
this.tpri = priTable[this.fbIndex]; | |
if (this.palIndex!==0 && pri<=(this.tpri&0xFF)) { | |
buffer[this.fbIndex] = palette[this.palIndex+palAdd]; | |
this.tpri = (this.tpri&0xF00)|pri; | |
priTable[this.fbIndex] =this.tpri; | |
} | |
} | |
this.fbIndex++; | |
this.tIndex--; | |
} | |
this.fbIndex-=8; | |
this.fbIndex+=256; | |
this.tIndex+=16; | |
} | |
} | |
else if(flipVertical && !flipHorizontal) { | |
this.fbIndex = (dy<<8)+dx; | |
this.tIndex = 56; | |
for (this.y=0;this.y<8;this.y++) { | |
for (this.x=0;this.x<8;this.x++) { | |
if (this.x>=srcx1 && this.x<srcx2 && this.y>=srcy1 && this.y<srcy2) { | |
this.palIndex = this.pix[this.tIndex]; | |
this.tpri = priTable[this.fbIndex]; | |
if (this.palIndex!==0 && pri<=(this.tpri&0xFF)) { | |
buffer[this.fbIndex] = palette[this.palIndex+palAdd]; | |
this.tpri = (this.tpri&0xF00)|pri; | |
priTable[this.fbIndex] =this.tpri; | |
} | |
} | |
this.fbIndex++; | |
this.tIndex++; | |
} | |
this.fbIndex-=8; | |
this.fbIndex+=256; | |
this.tIndex-=16; | |
} | |
} | |
else { | |
this.fbIndex = (dy<<8)+dx; | |
this.tIndex = 63; | |
for (this.y=0;this.y<8;this.y++) { | |
for (this.x=0;this.x<8;this.x++) { | |
if (this.x>=srcx1 && this.x<srcx2 && this.y>=srcy1 && this.y<srcy2) { | |
this.palIndex = this.pix[this.tIndex]; | |
this.tpri = priTable[this.fbIndex]; | |
if (this.palIndex!==0 && pri<=(this.tpri&0xFF)) { | |
buffer[this.fbIndex] = palette[this.palIndex+palAdd]; | |
this.tpri = (this.tpri&0xF00)|pri; | |
priTable[this.fbIndex] =this.tpri; | |
} | |
} | |
this.fbIndex++; | |
this.tIndex--; | |
} | |
this.fbIndex-=8; | |
this.fbIndex+=256; | |
} | |
} | |
}, | |
isTransparent: function(x, y){ | |
return (this.pix[(y << 3) + x] === 0); | |
}, | |
toJSON: function() { | |
return { | |
'opaque': this.opaque, | |
'pix': this.pix | |
}; | |
}, | |
fromJSON: function(s) { | |
this.opaque = s.opaque; | |
this.pix = s.pix; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.ROM = function(nes) { | |
this.nes = nes; | |
this.mapperName = new Array(92); | |
for (var i=0;i<92;i++) { | |
this.mapperName[i] = "Unknown Mapper"; | |
} | |
this.mapperName[ 0] = "Direct Access"; | |
this.mapperName[ 1] = "Nintendo MMC1"; | |
this.mapperName[ 2] = "UNROM"; | |
this.mapperName[ 3] = "CNROM"; | |
this.mapperName[ 4] = "Nintendo MMC3"; | |
this.mapperName[ 5] = "Nintendo MMC5"; | |
this.mapperName[ 6] = "FFE F4xxx"; | |
this.mapperName[ 7] = "AOROM"; | |
this.mapperName[ 8] = "FFE F3xxx"; | |
this.mapperName[ 9] = "Nintendo MMC2"; | |
this.mapperName[10] = "Nintendo MMC4"; | |
this.mapperName[11] = "Color Dreams Chip"; | |
this.mapperName[12] = "FFE F6xxx"; | |
this.mapperName[15] = "100-in-1 switch"; | |
this.mapperName[16] = "Bandai chip"; | |
this.mapperName[17] = "FFE F8xxx"; | |
this.mapperName[18] = "Jaleco SS8806 chip"; | |
this.mapperName[19] = "Namcot 106 chip"; | |
this.mapperName[20] = "Famicom Disk System"; | |
this.mapperName[21] = "Konami VRC4a"; | |
this.mapperName[22] = "Konami VRC2a"; | |
this.mapperName[23] = "Konami VRC2a"; | |
this.mapperName[24] = "Konami VRC6"; | |
this.mapperName[25] = "Konami VRC4b"; | |
this.mapperName[32] = "Irem G-101 chip"; | |
this.mapperName[33] = "Taito TC0190/TC0350"; | |
this.mapperName[34] = "32kB ROM switch"; | |
this.mapperName[64] = "Tengen RAMBO-1 chip"; | |
this.mapperName[65] = "Irem H-3001 chip"; | |
this.mapperName[66] = "GNROM switch"; | |
this.mapperName[67] = "SunSoft3 chip"; | |
this.mapperName[68] = "SunSoft4 chip"; | |
this.mapperName[69] = "SunSoft5 FME-7 chip"; | |
this.mapperName[71] = "Camerica chip"; | |
this.mapperName[78] = "Irem 74HC161/32-based"; | |
this.mapperName[91] = "Pirate HK-SF3 chip"; | |
}; | |
JSNES.ROM.prototype = { | |
// Mirroring types: | |
VERTICAL_MIRRORING: 0, | |
HORIZONTAL_MIRRORING: 1, | |
FOURSCREEN_MIRRORING: 2, | |
SINGLESCREEN_MIRRORING: 3, | |
SINGLESCREEN_MIRRORING2: 4, | |
SINGLESCREEN_MIRRORING3: 5, | |
SINGLESCREEN_MIRRORING4: 6, | |
CHRROM_MIRRORING: 7, | |
header: null, | |
rom: null, | |
vrom: null, | |
vromTile: null, | |
romCount: null, | |
vromCount: null, | |
mirroring: null, | |
batteryRam: null, | |
trainer: null, | |
fourScreen: null, | |
mapperType: null, | |
valid: false, | |
load: function(data) { | |
var i, j, v; | |
if (data.indexOf("NES\x1a") === -1) { | |
this.nes.ui.updateStatus("Not a valid NES ROM."); | |
return; | |
} | |
this.header = new Array(16); | |
for (i = 0; i < 16; i++) { | |
this.header[i] = data.charCodeAt(i) & 0xFF; | |
} | |
this.romCount = this.header[4]; | |
this.vromCount = this.header[5]*2; // Get the number of 4kB banks, not 8kB | |
this.mirroring = ((this.header[6] & 1) !== 0 ? 1 : 0); | |
this.batteryRam = (this.header[6] & 2) !== 0; | |
this.trainer = (this.header[6] & 4) !== 0; | |
this.fourScreen = (this.header[6] & 8) !== 0; | |
this.mapperType = (this.header[6] >> 4) | (this.header[7] & 0xF0); | |
/* TODO | |
if (this.batteryRam) | |
this.loadBatteryRam();*/ | |
// Check whether byte 8-15 are zero's: | |
var foundError = false; | |
for (i=8; i<16; i++) { | |
if (this.header[i] !== 0) { | |
foundError = true; | |
break; | |
} | |
} | |
if (foundError) { | |
this.mapperType &= 0xF; // Ignore byte 7 | |
} | |
// Load PRG-ROM banks: | |
this.rom = new Array(this.romCount); | |
var offset = 16; | |
for (i=0; i < this.romCount; i++) { | |
this.rom[i] = new Array(16384); | |
for (j=0; j < 16384; j++) { | |
if (offset+j >= data.length) { | |
break; | |
} | |
this.rom[i][j] = data.charCodeAt(offset + j) & 0xFF; | |
} | |
offset += 16384; | |
} | |
// Load CHR-ROM banks: | |
this.vrom = new Array(this.vromCount); | |
for (i=0; i < this.vromCount; i++) { | |
this.vrom[i] = new Array(4096); | |
for (j=0; j < 4096; j++) { | |
if (offset+j >= data.length){ | |
break; | |
} | |
this.vrom[i][j] = data.charCodeAt(offset + j) & 0xFF; | |
} | |
offset += 4096; | |
} | |
// Create VROM tiles: | |
this.vromTile = new Array(this.vromCount); | |
for (i=0; i < this.vromCount; i++) { | |
this.vromTile[i] = new Array(256); | |
for (j=0; j < 256; j++) { | |
this.vromTile[i][j] = new JSNES.PPU.Tile(); | |
} | |
} | |
// Convert CHR-ROM banks to tiles: | |
var tileIndex; | |
var leftOver; | |
for (v=0; v < this.vromCount; v++) { | |
for (i=0; i < 4096; i++) { | |
tileIndex = i >> 4; | |
leftOver = i % 16; | |
if (leftOver < 8) { | |
this.vromTile[v][tileIndex].setScanline( | |
leftOver, | |
this.vrom[v][i], | |
this.vrom[v][i+8] | |
); | |
} | |
else { | |
this.vromTile[v][tileIndex].setScanline( | |
leftOver-8, | |
this.vrom[v][i-8], | |
this.vrom[v][i] | |
); | |
} | |
} | |
} | |
this.valid = true; | |
}, | |
getMirroringType: function() { | |
if (this.fourScreen) { | |
return this.FOURSCREEN_MIRRORING; | |
} | |
if (this.mirroring === 0) { | |
return this.HORIZONTAL_MIRRORING; | |
} | |
return this.VERTICAL_MIRRORING; | |
}, | |
getMapperName: function() { | |
if (this.mapperType >= 0 && this.mapperType < this.mapperName.length) { | |
return this.mapperName[this.mapperType]; | |
} | |
return "Unknown Mapper, "+this.mapperType; | |
}, | |
mapperSupported: function() { | |
return typeof JSNES.Mappers[this.mapperType] !== 'undefined'; | |
}, | |
createMapper: function() { | |
if (this.mapperSupported()) { | |
return new JSNES.Mappers[this.mapperType](this.nes); | |
} | |
else { | |
this.nes.ui.updateStatus("This ROM uses a mapper not supported by JSNES: "+this.getMapperName()+"("+this.mapperType+")"); | |
return null; | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.DummyUI = function(nes) { | |
this.nes = nes; | |
this.enable = function() {}; | |
this.updateStatus = function() {}; | |
this.writeAudio = function() {}; | |
this.writeFrame = function() {}; | |
}; | |
if (typeof jQuery !== 'undefined') { | |
(function($) { | |
$.fn.JSNESUI = function(roms) { | |
var parent = this; | |
var UI = function(nes) { | |
var self = this; | |
self.nes = nes; | |
/* | |
* Create UI | |
*/ | |
self.root = $('<div></div>'); | |
self.screen = $('<canvas class="nes-screen" width="256" height="240"></canvas>').appendTo(self.root); | |
if (!self.screen[0].getContext) { | |
parent.html("Your browser doesn't support the <code><canvas></code> tag. Try Google Chrome, Safari, Opera or Firefox!"); | |
return; | |
} | |
self.romContainer = $('<div class="nes-roms" style="display:none;"></div>').appendTo(self.root); | |
self.romSelect = $('<select></select>').appendTo(self.romContainer); | |
self.controls = $('<div class="nes-controls" style="display:none;"></div>').appendTo(self.root); | |
self.buttons = { | |
restart: $('<input type="button" value="start" class="nes-restart" >').appendTo(self.controls), | |
pause: $('').appendTo(self.controls), | |
sound: $('').appendTo(self.controls), | |
zoom: $('<input type="button" value="zoom in" class="nes-zoom">').appendTo(self.controls) | |
}; | |
self.status = $('<p class="nes-status">Booting up...</p>').appendTo(self.root); | |
self.root.appendTo(parent); | |
/* | |
* ROM loading | |
*/ | |
self.romSelect.change(function() { | |
self.loadROM(); | |
}); | |
/* | |
* Buttons | |
*/ | |
self.buttons.pause.click(function() { | |
if (self.nes.isRunning) { | |
self.nes.stop(); | |
self.updateStatus("Paused"); | |
self.buttons.pause.attr("value", "resume"); | |
} | |
else { | |
self.nes.start(); | |
self.buttons.pause.attr("value", "pause"); | |
} | |
}); | |
function restartmario(){ | |
self.loadROM(); | |
self.nes.reloadRom(); | |
self.nes.start(); | |
} | |
window.onload=restartmario; | |
self.buttons.restart.click(function() { | |
self.loadROM(); | |
self.nes.reloadRom(); | |
self.nes.start(); | |
}); | |
self.buttons.sound.click(function() { | |
if (self.nes.opts.emulateSound) { | |
self.nes.opts.emulateSound = false; | |
self.buttons.sound.attr("value", "enable sound"); | |
} | |
else { | |
self.nes.opts.emulateSound = true; | |
self.buttons.sound.attr("value", "disable sound"); | |
} | |
}); | |
self.zoomed = true; | |
self.buttons.zoom.click(function() { | |
if (self.zoomed) { | |
self.screen.animate({ | |
width: '405px', | |
height: '380px' | |
}); | |
//self.buttons.zoom.attr("value", "zoom in"); | |
self.zoomed = false; | |
} | |
else { | |
self.screen.animate({ | |
width: '405px', | |
height: '380px' | |
}); | |
//self.buttons.zoom.attr("value", "zoom out"); | |
self.zoomed = true; | |
} | |
}); | |
/* | |
* Lightgun experiments with mouse | |
* (Requires jquery.dimensions.js) | |
*/ | |
if ($.offset) { | |
self.screen.mousedown(function(e) { | |
if (self.nes.mmap) { | |
self.nes.mmap.mousePressed = true; | |
// FIXME: does not take into account zoom | |
self.nes.mmap.mouseX = e.pageX - self.screen.offset().left; | |
self.nes.mmap.mouseY = e.pageY - self.screen.offset().top; | |
} | |
}).mouseup(function() { | |
setTimeout(function() { | |
if (self.nes.mmap) { | |
self.nes.mmap.mousePressed = false; | |
self.nes.mmap.mouseX = 0; | |
self.nes.mmap.mouseY = 0; | |
} | |
}, 500); | |
}); | |
} | |
if (typeof roms != 'undefined') { | |
self.setRoms(roms); | |
} | |
/* | |
* Canvas | |
*/ | |
self.canvasContext = self.screen[0].getContext('2d'); | |
if (!self.canvasContext.getImageData) { | |
parent.html("Your browser doesn't support writing pixels directly to the <code><canvas></code> tag. Try the latest versions of Google Chrome, Safari, Opera or Firefox!"); | |
return; | |
} | |
self.canvasImageData = self.canvasContext.getImageData(0, 0, 256, 240); | |
self.resetCanvas(); | |
/* | |
* Keyboard | |
*/ | |
$(document). | |
bind('keydown', function(evt) { | |
self.nes.keyboard.keyDown(evt); | |
}). | |
bind('keyup', function(evt) { | |
self.nes.keyboard.keyUp(evt); | |
}). | |
bind('keypress', function(evt) { | |
self.nes.keyboard.keyPress(evt); | |
}); | |
/* | |
* Sound | |
*/ | |
self.dynamicaudio = new DynamicAudio({ | |
swf: nes.opts.swfPath+'dynamicaudio.swf' | |
}); | |
}; | |
UI.prototype = { | |
loadROM: function() { | |
var self = this; | |
self.updateStatus("Downloading..."); | |
$.ajax({ | |
url: escape(self.romSelect.val()), | |
xhr: function() { | |
var xhr = $.ajaxSettings.xhr(); | |
if (typeof xhr.overrideMimeType !== 'undefined') { | |
// Download as binary | |
xhr.overrideMimeType('text/plain; charset=x-user-defined'); | |
} | |
self.xhr = xhr; | |
return xhr; | |
}, | |
complete: function(xhr, status) { | |
var i, data; | |
if (JSNES.Utils.isIE()) { | |
var charCodes = JSNESBinaryToArray( | |
xhr.responseBody | |
).toArray(); | |
data = String.fromCharCode.apply( | |
undefined, | |
charCodes | |
); | |
} | |
else { | |
data = xhr.responseText; | |
} | |
self.nes.loadRom(data); | |
self.nes.start(); | |
self.enable(); | |
self.screen.animate({ | |
width: '405px', | |
height: '380px' | |
}); | |
} | |
}); | |
}, | |
resetCanvas: function() { | |
this.canvasContext.fillStyle = 'black'; | |
// set alpha to opaque | |
this.canvasContext.fillRect(0, 0, 256, 240); | |
// Set alpha | |
for (var i = 3; i < this.canvasImageData.data.length-3; i += 4) { | |
this.canvasImageData.data[i] = 0xFF; | |
} | |
}, | |
/* | |
* | |
* nes.ui.screenshot() --> return <img> element :) | |
*/ | |
screenshot: function() { | |
var data = this.screen[0].toDataURL("image/png"), | |
img = new Image(); | |
img.src = data; | |
return img; | |
}, | |
/* | |
* Enable and reset UI elements | |
*/ | |
enable: function() { | |
this.buttons.pause.attr("disabled", null); | |
if (this.nes.isRunning) { | |
this.buttons.pause.attr("value", "pause"); | |
} | |
else { | |
this.buttons.pause.attr("value", "resume"); | |
} | |
this.buttons.restart.attr("disabled", null); | |
if (this.nes.opts.emulateSound) { | |
this.buttons.sound.attr("value", "disable sound"); | |
} | |
else { | |
this.buttons.sound.attr("value", "enable sound"); | |
} | |
}, | |
updateStatus: function(s) { | |
this.status.text(s); | |
}, | |
setRoms: function(roms) { | |
this.romSelect.children().remove(); | |
//$("<option>Select a ROM...</option>").appendTo(this.romSelect); | |
for (var groupName in roms) { | |
if (roms.hasOwnProperty(groupName)) { | |
var optgroup = $('<optgroup></optgroup>'). | |
attr("label", groupName); | |
for (var i = 0; i < roms[groupName].length; i++) { | |
$('<option>'+roms[groupName][i][0]+'</option>') | |
.attr("value", roms[groupName][i][1]) | |
.appendTo(optgroup); | |
} | |
this.romSelect.append(optgroup); | |
} | |
} | |
}, | |
writeAudio: function(samples) { | |
return this.dynamicaudio.writeInt(samples); | |
}, | |
writeFrame: function(buffer, prevBuffer) { | |
var imageData = this.canvasImageData.data; | |
var pixel, i, j; | |
for (i=0; i<256*240; i++) { | |
pixel = buffer[i]; | |
if (pixel != prevBuffer[i]) { | |
j = i*4; | |
imageData[j] = pixel & 0xFF; | |
imageData[j+1] = (pixel >> 8) & 0xFF; | |
imageData[j+2] = (pixel >> 16) & 0xFF; | |
prevBuffer[i] = pixel; | |
} | |
} | |
this.canvasContext.putImageData(this.canvasImageData, 0, 0); | |
} | |
}; | |
return UI; | |
}; | |
})(jQuery); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JSNES, based on Jamie Sanders' vNES | |
Copyright (C) 2010 Ben Firshman | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
JSNES.Utils = { | |
copyArrayElements: function(src, srcPos, dest, destPos, length) { | |
for (var i = 0; i < length; ++i) { | |
dest[destPos + i] = src[srcPos + i]; | |
} | |
}, | |
copyArray: function(src) { | |
var dest = new Array(src.length); | |
for (var i = 0; i < src.length; i++) { | |
dest[i] = src[i]; | |
} | |
return dest; | |
}, | |
fromJSON: function(obj, state) { | |
for (var i = 0; i < obj.JSON_PROPERTIES.length; i++) { | |
obj[obj.JSON_PROPERTIES[i]] = state[obj.JSON_PROPERTIES[i]]; | |
} | |
}, | |
toJSON: function(obj) { | |
var state = {}; | |
for (var i = 0; i < obj.JSON_PROPERTIES.length; i++) { | |
state[obj.JSON_PROPERTIES[i]] = obj[obj.JSON_PROPERTIES[i]]; | |
} | |
return state; | |
}, | |
isIE: function() { | |
return (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)); | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment