Fixed timing of CPU opcodes with page cross.

--- emulator/core/units/cpu.coffee
+++ emulator/core/units/cpu.coffee
@@ -113,6 +113,8 @@
         operation         = @readOperation()
         instruction       = operation.instruction
         addressingMode    = operation.addressingMode
+        @pageCrossed      = false
+        @pageCrossEnabled = operation.pageCrossEnabled
         @emptyReadCycles  = operation.emptyReadCycles
         @emptyWriteCycles = operation.emptyWriteCycles
         instruction addressingMode()
@@ -313,11 +315,9 @@
         (base + offset) & 0xFF

     getIndexedAddressWord : (base, offset) ->
-        @emptyReadCycles = 1 if @$isPageCrossed base, offset
+        @pageCrossed = (base & 0xFF00) != ((base + offset) & 0xFF00)
+        @emptyReadCycles++ if @pageCrossEnabled and @pageCrossed
         (base + offset) & 0xFFFF
-
-    isPageCrossed: (base, offset) ->
-        (base & 0xFF00) != ((base + offset) & 0xFF00)

     getSignedByte: (value) ->
         if value >= 0x80 then value - 0x100 else value
@@ -638,6 +638,7 @@
         if condition
             @programCounter = address
             @tick()
+            @tick() if @pageCrossed

     rotateAccumulatorOrMemory: (address, rotation, transferCarry) ->
         if address?
@@ -672,359 +673,360 @@
         # 0 operation instruction
         ###########################################################

-        @registerOperation 0x1A, @NOP, @impliedMode,   0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0x3A, @NOP, @impliedMode,   0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0x5A, @NOP, @impliedMode,   0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0x7A, @NOP, @impliedMode,   0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0xDA, @NOP, @impliedMode,   0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0xEA, @NOP, @impliedMode,   0, 0 # 2 cycles
-        @registerOperation 0xFA, @NOP, @impliedMode,   0, 0 # 2 cycles (undocumented operation)
-
-        @registerOperation 0x80, @NOP, @immediateMode, 0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0x82, @NOP, @immediateMode, 0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0x89, @NOP, @immediateMode, 0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0xC2, @NOP, @immediateMode, 0, 0 # 2 cycles (undocumented operation)
-        @registerOperation 0xE2, @NOP, @immediateMode, 0, 0 # 2 cycles (undocumented operation)
-
-        @registerOperation 0x04, @NOP, @zeroPageMode,  0, 0 # 3 cycles (undocumented operation)
-        @registerOperation 0x44, @NOP, @zeroPageMode,  0, 0 # 3 cycles (undocumented operation)
-        @registerOperation 0x64, @NOP, @zeroPageMode,  0, 0 # 3 cycles (undocumented operation)
-
-        @registerOperation 0x14, @NOP, @zeroPageXMode, 1, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0x34, @NOP, @zeroPageXMode, 1, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0x54, @NOP, @zeroPageXMode, 1, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0x74, @NOP, @zeroPageXMode, 1, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0xD4, @NOP, @zeroPageXMode, 1, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0xF4, @NOP, @zeroPageXMode, 1, 0 # 4 cycles (undocumented operation)
-
-        @registerOperation 0x0C, @NOP, @absoluteMode,  0, 0 # 4 cycles (undocumented operation)
-
-        @registerOperation 0x1C, @NOP, @absoluteXMode, 0, 0 # 5 cycles (undocumented operation)
-        @registerOperation 0x3C, @NOP, @absoluteXMode, 0, 0 # 5 cycles (undocumented operation)
-        @registerOperation 0x5C, @NOP, @absoluteXMode, 0, 0 # 5 cycles (undocumented operation)
-        @registerOperation 0x7C, @NOP, @absoluteXMode, 0, 0 # 5 cycles (undocumented operation)
-        @registerOperation 0xDC, @NOP, @absoluteXMode, 0, 0 # 5 cycles (undocumented operation)
-        @registerOperation 0xFC, @NOP, @absoluteXMode, 0, 0 # 5 cycles (undocumented operation)
+        @registerOperation 0x1A, @NOP, @impliedMode,   0, 0, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0x3A, @NOP, @impliedMode,   0, 0, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0x5A, @NOP, @impliedMode,   0, 0, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0x7A, @NOP, @impliedMode,   0, 0, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0xDA, @NOP, @impliedMode,   0, 0, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0xEA, @NOP, @impliedMode,   0, 0, 0 # 2 cycles
+        @registerOperation 0xFA, @NOP, @impliedMode,   0, 0, 0 # 2 cycles (undocumented operation)
+
+        @registerOperation 0x80, @NOP, @immediateMode, 0, 1, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0x82, @NOP, @immediateMode, 0, 1, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0x89, @NOP, @immediateMode, 0, 1, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0xC2, @NOP, @immediateMode, 0, 1, 0 # 2 cycles (undocumented operation)
+        @registerOperation 0xE2, @NOP, @immediateMode, 0, 1, 0 # 2 cycles (undocumented operation)
+
+        @registerOperation 0x04, @NOP, @zeroPageMode,  0, 1, 0 # 3 cycles (undocumented operation)
+        @registerOperation 0x44, @NOP, @zeroPageMode,  0, 1, 0 # 3 cycles (undocumented operation)
+        @registerOperation 0x64, @NOP, @zeroPageMode,  0, 1, 0 # 3 cycles (undocumented operation)
+
+        @registerOperation 0x14, @NOP, @zeroPageXMode, 0, 2, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0x34, @NOP, @zeroPageXMode, 0, 2, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0x54, @NOP, @zeroPageXMode, 0, 2, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0x74, @NOP, @zeroPageXMode, 0, 2, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0xD4, @NOP, @zeroPageXMode, 0, 2, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0xF4, @NOP, @zeroPageXMode, 0, 2, 0 # 4 cycles (undocumented operation)
+
+        @registerOperation 0x0C, @NOP, @absoluteMode,  0, 1, 0 # 4 cycles (undocumented operation)
+
+        @registerOperation 0x1C, @NOP, @absoluteXMode, 1, 1, 0 # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0x3C, @NOP, @absoluteXMode, 1, 1, 0 # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0x5C, @NOP, @absoluteXMode, 1, 1, 0 # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0x7C, @NOP, @absoluteXMode, 1, 1, 0 # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0xDC, @NOP, @absoluteXMode, 1, 1, 0 # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0xFC, @NOP, @absoluteXMode, 1, 1, 0 # 4 (+1) cycles (undocumented operation)

         ###########################################################
         # Clear flag instructions
         ###########################################################

-        @registerOperation 0x18, @CLC, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0x58, @CLI, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0xD8, @CLD, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0xB8, @CLV, @impliedMode, 0, 0 # 2 cycles
+        @registerOperation 0x18, @CLC, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x58, @CLI, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0xD8, @CLD, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0xB8, @CLV, @impliedMode, 0, 0, 0 # 2 cycles

         ###########################################################
         # Set flag instructions
         ###########################################################

-        @registerOperation 0x38, @SEC, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0x78, @SEI, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0xF8, @SED, @impliedMode, 0, 0 # 2 cycles
+        @registerOperation 0x38, @SEC, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x78, @SEI, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0xF8, @SED, @impliedMode, 0, 0, 0 # 2 cycles

         ###########################################################
         # Memory write instructions
         ###########################################################

-        @registerOperation 0x85, @STA, @zeroPageMode,  0, 0 # 3 cycles
-        @registerOperation 0x95, @STA, @zeroPageXMode, 1, 0 # 4 cycles
-        @registerOperation 0x8D, @STA, @absoluteMode,  0, 0 # 4 cycles
-        @registerOperation 0x9D, @STA, @absoluteXMode, 1, 0 # 5 cycles
-        @registerOperation 0x99, @STA, @absoluteYMode, 1, 0 # 5 cycles
-        @registerOperation 0x81, @STA, @indirectXMode, 1, 0 # 6 cycles
-        @registerOperation 0x91, @STA, @indirectYMode, 1, 0 # 6 cycles
-
-        @registerOperation 0x86, @STX, @zeroPageMode,  0, 0 # 3 cycles
-        @registerOperation 0x96, @STX, @zeroPageYMode, 1, 0 # 4 cycles
-        @registerOperation 0x8E, @STX, @absoluteMode,  0, 0 # 4 cycles
-
-        @registerOperation 0x87, @SAX, @zeroPageMode,  0, 0 # 3 cycles (undocumented operation)
-        @registerOperation 0x97, @SAX, @zeroPageYMode, 1, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0x8F, @SAX, @absoluteMode,  0, 0 # 4 cycles (undocumented operation)
-        @registerOperation 0x83, @SAX, @indirectXMode, 1, 0 # 6 cycles (undocumented operation)
-
-        @registerOperation 0x84, @STY, @zeroPageMode,  0, 0 # 3 cycles
-        @registerOperation 0x94, @STY, @zeroPageXMode, 1, 0 # 4 cycles
-        @registerOperation 0x8C, @STY, @absoluteMode,  0, 0 # 4 cycles
+        @registerOperation 0x85, @STA, @zeroPageMode,  0, 0, 0 # 3 cycles
+        @registerOperation 0x95, @STA, @zeroPageXMode, 0, 1, 0 # 4 cycles
+        @registerOperation 0x8D, @STA, @absoluteMode,  0, 0, 0 # 4 cycles
+        @registerOperation 0x9D, @STA, @absoluteXMode, 0, 1, 0 # 5 cycles
+        @registerOperation 0x99, @STA, @absoluteYMode, 0, 1, 0 # 5 cycles
+        @registerOperation 0x81, @STA, @indirectXMode, 0, 1, 0 # 6 cycles
+        @registerOperation 0x91, @STA, @indirectYMode, 0, 1, 0 # 6 cycles
+
+        @registerOperation 0x86, @STX, @zeroPageMode,  0, 0, 0 # 3 cycles
+        @registerOperation 0x96, @STX, @zeroPageYMode, 0, 1, 0 # 4 cycles
+        @registerOperation 0x8E, @STX, @absoluteMode,  0, 0, 0 # 4 cycles
+
+        @registerOperation 0x87, @SAX, @zeroPageMode,  0, 0, 0 # 3 cycles (undocumented operation)
+        @registerOperation 0x97, @SAX, @zeroPageYMode, 0, 1, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0x8F, @SAX, @absoluteMode,  0, 0, 0 # 4 cycles (undocumented operation)
+        @registerOperation 0x83, @SAX, @indirectXMode, 0, 1, 0 # 6 cycles (undocumented operation)
+
+        @registerOperation 0x84, @STY, @zeroPageMode,  0, 0, 0 # 3 cycles
+        @registerOperation 0x94, @STY, @zeroPageXMode, 0, 1, 0 # 4 cycles
+        @registerOperation 0x8C, @STY, @absoluteMode,  0, 0, 0 # 4 cycles

         ###########################################################
         # Memory read instructions
         ###########################################################

-        @registerOperation 0xA9, @LDA, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xA5, @LDA, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xB5, @LDA, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0xAD, @LDA, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0xBD, @LDA, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0xB9, @LDA, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0xA1, @LDA, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0xB1, @LDA, @indirectYMode, 0, 0 # 5 (+1) cycles
-
-        @registerOperation 0xA2, @LDX, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xA6, @LDX, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xB6, @LDX, @zeroPageYMode, 1, 0 # 4      cycles
-        @registerOperation 0xAE, @LDX, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0xBE, @LDX, @absoluteYMode, 0, 0 # 4 (+1) cycles
-
-        @registerOperation 0xA0, @LDY, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xA4, @LDY, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xB4, @LDY, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0xAC, @LDY, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0xBC, @LDY, @absoluteXMode, 0, 0 # 4 (+1) cycles
-
-        @registerOperation 0xA7, @LAX, @zeroPageMode,  0, 0, # 3      cycles (undocumented operation)
-        @registerOperation 0xB7, @LAX, @zeroPageYMode, 1, 0, # 4      cycles (undocumented operation)
-        @registerOperation 0xAF, @LAX, @absoluteMode,  0, 0, # 4      cycles (undocumented operation)
-        @registerOperation 0xBF, @LAX, @absoluteYMode, 0, 0, # 4 (+1) cycles (undocumented operation)
-        @registerOperation 0xA3, @LAX, @indirectXMode, 1, 0, # 6      cycles (undocumented operation)
-        @registerOperation 0xB3, @LAX, @indirectYMode, 0, 0, # 5 (+1) cycles (undocumented operation)
+        @registerOperation 0xA9, @LDA, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xA5, @LDA, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xB5, @LDA, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0xAD, @LDA, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0xBD, @LDA, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0xB9, @LDA, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0xA1, @LDA, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0xB1, @LDA, @indirectYMode, 1, 0, 0 # 5 (+1) cycles
+
+        @registerOperation 0xA2, @LDX, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xA6, @LDX, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xB6, @LDX, @zeroPageYMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0xAE, @LDX, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0xBE, @LDX, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+
+        @registerOperation 0xA0, @LDY, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xA4, @LDY, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xB4, @LDY, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0xAC, @LDY, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0xBC, @LDY, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+
+        @registerOperation 0xA7, @LAX, @zeroPageMode,  0, 0, 0, # 3      cycles (undocumented operation)
+        @registerOperation 0xB7, @LAX, @zeroPageYMode, 0, 1, 0, # 4      cycles (undocumented operation)
+        @registerOperation 0xAF, @LAX, @absoluteMode,  0, 0, 0, # 4      cycles (undocumented operation)
+        @registerOperation 0xBF, @LAX, @absoluteYMode, 1, 0, 0, # 4 (+1) cycles (undocumented operation)
+        @registerOperation 0xA3, @LAX, @indirectXMode, 0, 1, 0, # 6      cycles (undocumented operation)
+        @registerOperation 0xB3, @LAX, @indirectYMode, 1, 0, 0, # 5 (+1) cycles (undocumented operation)

         ###########################################################
         # Register transfer instructions
         ###########################################################

-        @registerOperation 0xAA, @TAX, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0xA8, @TAY, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0x8A, @TXA, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0x98, @TYA, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0x9A, @TXS, @impliedMode, 0, 0 # 2 cycles
-        @registerOperation 0xBA, @TSX, @impliedMode, 0, 0 # 2 cycles
+        @registerOperation 0xAA, @TAX, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0xA8, @TAY, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x8A, @TXA, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x98, @TYA, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x9A, @TXS, @impliedMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0xBA, @TSX, @impliedMode, 0, 0, 0 # 2 cycles

         ###########################################################
         # Stack push instructions
         ###########################################################

-        @registerOperation 0x48, @PHA, @impliedMode, 0, 0 # 3 cycles
-        @registerOperation 0x08, @PHP, @impliedMode, 0, 0 # 3 cycles
+        @registerOperation 0x48, @PHA, @impliedMode, 0, 0, 0 # 3 cycles
+        @registerOperation 0x08, @PHP, @impliedMode, 0, 0, 0 # 3 cycles

         ###########################################################
         # Stack pull instructions
         ###########################################################

-        @registerOperation 0x68, @PLA, @impliedMode, 1, 0 # 4 cycles
-        @registerOperation 0x28, @PLP, @impliedMode, 1, 0 # 4 cycles
+        @registerOperation 0x68, @PLA, @impliedMode, 0, 1, 0 # 4 cycles
+        @registerOperation 0x28, @PLP, @impliedMode, 0, 1, 0 # 4 cycles

         ###########################################################
         # Accumulator bitwise instructions
         ###########################################################

-        @registerOperation 0x29, @AND, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0x25, @AND, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0x35, @AND, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0x2D, @AND, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0x3D, @AND, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x39, @AND, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x21, @AND, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0x31, @AND, @indirectYMode, 0, 0 # 5 (+1) cycles
-
-        @registerOperation 0x09, @ORA, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0x05, @ORA, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0x15, @ORA, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0x0D, @ORA, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0x1D, @ORA, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x19, @ORA, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x01, @ORA, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0x11, @ORA, @indirectYMode, 0, 0 # 5 (+1) cycles
-
-        @registerOperation 0x49, @EOR, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0x45, @EOR, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0x55, @EOR, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0x4D, @EOR, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0x5D, @EOR, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x59, @EOR, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x41, @EOR, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0x51, @EOR, @indirectYMode, 0, 0 # 5 (+1) cycles
-
-        @registerOperation 0x24, @BIT, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0x2C, @BIT, @absoluteMode,  0, 0 # 4      cycles
+        @registerOperation 0x29, @AND, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0x25, @AND, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0x35, @AND, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0x2D, @AND, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0x3D, @AND, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x39, @AND, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x21, @AND, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0x31, @AND, @indirectYMode, 1, 0, 0 # 5 (+1) cycles
+
+        @registerOperation 0x09, @ORA, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0x05, @ORA, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0x15, @ORA, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0x0D, @ORA, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0x1D, @ORA, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x19, @ORA, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x01, @ORA, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0x11, @ORA, @indirectYMode, 1, 0, 0 # 5 (+1) cycles
+
+        @registerOperation 0x49, @EOR, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0x45, @EOR, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0x55, @EOR, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0x4D, @EOR, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0x5D, @EOR, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x59, @EOR, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x41, @EOR, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0x51, @EOR, @indirectYMode, 1, 0, 0 # 5 (+1) cycles
+
+        @registerOperation 0x24, @BIT, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0x2C, @BIT, @absoluteMode,  0, 0, 0 # 4      cycles

         ###########################################################
         # Increment instructions
         ###########################################################

-        @registerOperation 0xE6, @INC, @zeroPageMode,  0, 1 # 5 cycles
-        @registerOperation 0xF6, @INC, @zeroPageXMode, 1, 1 # 6 cycles
-        @registerOperation 0xEE, @INC, @absoluteMode,  0, 1 # 6 cycles
-        @registerOperation 0xFE, @INC, @absoluteXMode, 1, 1 # 7 cycles
-
-        @registerOperation 0xE8, @INX, @impliedMode,   0, 0 # 2 cycles
-        @registerOperation 0xC8, @INY, @impliedMode,   0, 0 # 2 cycles
+        @registerOperation 0xE6, @INC, @zeroPageMode,  0, 0, 1 # 5 cycles
+        @registerOperation 0xF6, @INC, @zeroPageXMode, 0, 1, 1 # 6 cycles
+        @registerOperation 0xEE, @INC, @absoluteMode,  0, 0, 1 # 6 cycles
+        @registerOperation 0xFE, @INC, @absoluteXMode, 0, 1, 1 # 7 cycles
+
+        @registerOperation 0xE8, @INX, @impliedMode,   0, 0, 0 # 2 cycles
+        @registerOperation 0xC8, @INY, @impliedMode,   0, 0, 0 # 2 cycles

         ###########################################################
         # Decrement instructions
         ###########################################################

-        @registerOperation 0xC6, @DEC, @zeroPageMode,  0, 1 # 5 cycles
-        @registerOperation 0xD6, @DEC, @zeroPageXMode, 1, 1 # 6 cycles
-        @registerOperation 0xCE, @DEC, @absoluteMode,  0, 1 # 6 cycles
-        @registerOperation 0xDE, @DEC, @absoluteXMode, 1, 1 # 7 cycles
-
-        @registerOperation 0xCA, @DEX, @impliedMode,   0, 0 # 2 cycles
-        @registerOperation 0x88, @DEY, @impliedMode,   0, 0 # 2 cycles
+        @registerOperation 0xC6, @DEC, @zeroPageMode,  0, 0, 1 # 5 cycles
+        @registerOperation 0xD6, @DEC, @zeroPageXMode, 0, 1, 1 # 6 cycles
+        @registerOperation 0xCE, @DEC, @absoluteMode,  0, 0, 1 # 6 cycles
+        @registerOperation 0xDE, @DEC, @absoluteXMode, 0, 1, 1 # 7 cycles
+
+        @registerOperation 0xCA, @DEX, @impliedMode,   0, 0, 0 # 2 cycles
+        @registerOperation 0x88, @DEY, @impliedMode,   0, 0, 0 # 2 cycles

         ###########################################################
         # Comparison instructions
         ###########################################################

-        @registerOperation 0xC9, @CMP, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xC5, @CMP, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xD5, @CMP, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0xCD, @CMP, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0xDD, @CMP, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0xD9, @CMP, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0xC1, @CMP, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0xD1, @CMP, @indirectYMode, 0, 0 # 5 (+1) cycles
-
-        @registerOperation 0xE0, @CPX, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xE4, @CPX, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xEC, @CPX, @absoluteMode,  0, 0 # 4      cycles
-
-        @registerOperation 0xC0, @CPY, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xC4, @CPY, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xCC, @CPY, @absoluteMode,  0, 0 # 4      cycles
+        @registerOperation 0xC9, @CMP, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xC5, @CMP, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xD5, @CMP, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0xCD, @CMP, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0xDD, @CMP, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0xD9, @CMP, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0xC1, @CMP, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0xD1, @CMP, @indirectYMode, 1, 0, 0 # 5 (+1) cycles
+
+        @registerOperation 0xE0, @CPX, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xE4, @CPX, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xEC, @CPX, @absoluteMode,  0, 0, 0 # 4      cycles
+
+        @registerOperation 0xC0, @CPY, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xC4, @CPY, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xCC, @CPY, @absoluteMode,  0, 0, 0 # 4      cycles

         ###########################################################
         # Branching instructions
         ###########################################################

-        @registerOperation 0x90, @BCC, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-        @registerOperation 0xB0, @BCS, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-
-        @registerOperation 0xD0, @BNE, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-        @registerOperation 0xF0, @BEQ, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-
-        @registerOperation 0x50, @BVC, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-        @registerOperation 0x70, @BVS, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-
-        @registerOperation 0x10, @BPL, @relativeMode, 0, 0 # 2 (+1/+2) cycles
-        @registerOperation 0x30, @BMI, @relativeMode, 0, 0 # 2 (+1/+2) cycles
+        @registerOperation 0x90, @BCC, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+        @registerOperation 0xB0, @BCS, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+
+        @registerOperation 0xD0, @BNE, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+        @registerOperation 0xF0, @BEQ, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+
+        @registerOperation 0x50, @BVC, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+        @registerOperation 0x70, @BVS, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+
+        @registerOperation 0x10, @BPL, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles
+        @registerOperation 0x30, @BMI, @relativeMode, 0, 0, 0 # 2 (+1/+2) cycles

         ###########################################################
         # Jump / subroutine instructions
         ###########################################################

-        @registerOperation 0x4C, @JMP, @absoluteMode, 0, 0 # 3 cycles
-        @registerOperation 0x6C, @JMP, @indirectMode, 0, 0 # 5 cycles
-        @registerOperation 0x20, @JSR, @absoluteMode, 1, 0 # 6 cycles
-        @registerOperation 0x60, @RTS, @impliedMode,  1, 0 # 6 cycles
+        @registerOperation 0x4C, @JMP, @absoluteMode, 0, 0, 0 # 3 cycles
+        @registerOperation 0x6C, @JMP, @indirectMode, 0, 0, 0 # 5 cycles
+        @registerOperation 0x20, @JSR, @absoluteMode, 0, 1, 0 # 6 cycles
+        @registerOperation 0x60, @RTS, @impliedMode,  0, 1, 0 # 6 cycles

         ###########################################################
         # Interrupt control instructions
         ###########################################################

-        @registerOperation 0x00, @BRK, @impliedMode, 0, 0 # 7 cycles
-        @registerOperation 0x40, @RTI, @impliedMode, 1, 0 # 6 cycles
+        @registerOperation 0x00, @BRK, @impliedMode, 0, 0, 0 # 7 cycles
+        @registerOperation 0x40, @RTI, @impliedMode, 0, 1, 0 # 6 cycles

         ###########################################################
         # Addition / subtraction instructions
         ###########################################################

-        @registerOperation 0x69, @ADC, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0x65, @ADC, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0x75, @ADC, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0x6D, @ADC, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0x7D, @ADC, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x79, @ADC, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0x61, @ADC, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0x71, @ADC, @indirectYMode, 0, 0 # 5 (+1) cycles
-
-        @registerOperation 0xE9, @SBC, @immediateMode, 0, 0 # 2      cycles
-        @registerOperation 0xEB, @SBC, @immediateMode, 0, 0 # 2      cycles (undocumented operation)
-        @registerOperation 0xE5, @SBC, @zeroPageMode,  0, 0 # 3      cycles
-        @registerOperation 0xF5, @SBC, @zeroPageXMode, 1, 0 # 4      cycles
-        @registerOperation 0xED, @SBC, @absoluteMode,  0, 0 # 4      cycles
-        @registerOperation 0xFD, @SBC, @absoluteXMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0xF9, @SBC, @absoluteYMode, 0, 0 # 4 (+1) cycles
-        @registerOperation 0xE1, @SBC, @indirectXMode, 1, 0 # 6      cycles
-        @registerOperation 0xF1, @SBC, @indirectYMode, 0, 0 # 5 (+1) cycles
+        @registerOperation 0x69, @ADC, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0x65, @ADC, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0x75, @ADC, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0x6D, @ADC, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0x7D, @ADC, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x79, @ADC, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0x61, @ADC, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0x71, @ADC, @indirectYMode, 1, 0, 0 # 5 (+1) cycles
+
+        @registerOperation 0xE9, @SBC, @immediateMode, 0, 0, 0 # 2      cycles
+        @registerOperation 0xEB, @SBC, @immediateMode, 0, 0, 0 # 2      cycles (undocumented operation)
+        @registerOperation 0xE5, @SBC, @zeroPageMode,  0, 0, 0 # 3      cycles
+        @registerOperation 0xF5, @SBC, @zeroPageXMode, 0, 1, 0 # 4      cycles
+        @registerOperation 0xED, @SBC, @absoluteMode,  0, 0, 0 # 4      cycles
+        @registerOperation 0xFD, @SBC, @absoluteXMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0xF9, @SBC, @absoluteYMode, 1, 0, 0 # 4 (+1) cycles
+        @registerOperation 0xE1, @SBC, @indirectXMode, 0, 1, 0 # 6      cycles
+        @registerOperation 0xF1, @SBC, @indirectYMode, 1, 0, 0 # 5 (+1) cycles

         ###########################################################
         # Shifting instructions
         ###########################################################

-        @registerOperation 0x0A, @ASL, @accumulatorMode, 0, 0 # 2 cycles
-        @registerOperation 0x06, @ASL, @zeroPageMode,    0, 1 # 5 cycles
-        @registerOperation 0x16, @ASL, @zeroPageXMode,   1, 1 # 6 cycles
-        @registerOperation 0x0E, @ASL, @absoluteMode,    0, 1 # 6 cycles
-        @registerOperation 0x1E, @ASL, @absoluteXMode,   1, 1 # 7 cycles
-
-        @registerOperation 0x4A, @LSR, @accumulatorMode, 0, 0 # 2 cycles
-        @registerOperation 0x46, @LSR, @zeroPageMode,    0, 1 # 5 cycles
-        @registerOperation 0x56, @LSR, @zeroPageXMode,   1, 1 # 6 cycles
-        @registerOperation 0x4E, @LSR, @absoluteMode,    0, 1 # 6 cycles
-        @registerOperation 0x5E, @LSR, @absoluteXMode,   1, 1 # 7 cycles
-
-        @registerOperation 0x2A, @ROL, @accumulatorMode, 0, 0 # 2 cycles
-        @registerOperation 0x26, @ROL, @zeroPageMode,    0, 1 # 5 cycles
-        @registerOperation 0x36, @ROL, @zeroPageXMode,   1, 1 # 6 cycles
-        @registerOperation 0x2E, @ROL, @absoluteMode,    0, 1 # 6 cycles
-        @registerOperation 0x3E, @ROL, @absoluteXMode,   1, 1 # 7 cycles
-
-        @registerOperation 0x6A, @ROR, @accumulatorMode, 0, 0 # 2 cycles
-        @registerOperation 0x66, @ROR, @zeroPageMode,    0, 1 # 5 cycles
-        @registerOperation 0x76, @ROR, @zeroPageXMode,   1, 1 # 6 cycles
-        @registerOperation 0x6E, @ROR, @absoluteMode,    0, 1 # 6 cycles
-        @registerOperation 0x7E, @ROR, @absoluteXMode,   1, 1 # 7 cycles
+        @registerOperation 0x0A, @ASL, @accumulatorMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x06, @ASL, @zeroPageMode,    0, 0, 1 # 5 cycles
+        @registerOperation 0x16, @ASL, @zeroPageXMode,   0, 1, 1 # 6 cycles
+        @registerOperation 0x0E, @ASL, @absoluteMode,    0, 0, 1 # 6 cycles
+        @registerOperation 0x1E, @ASL, @absoluteXMode,   0, 1, 1 # 7 cycles
+
+        @registerOperation 0x4A, @LSR, @accumulatorMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x46, @LSR, @zeroPageMode,    0, 0, 1 # 5 cycles
+        @registerOperation 0x56, @LSR, @zeroPageXMode,   0, 1, 1 # 6 cycles
+        @registerOperation 0x4E, @LSR, @absoluteMode,    0, 0, 1 # 6 cycles
+        @registerOperation 0x5E, @LSR, @absoluteXMode,   0, 1, 1 # 7 cycles
+
+        @registerOperation 0x2A, @ROL, @accumulatorMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x26, @ROL, @zeroPageMode,    0, 0, 1 # 5 cycles
+        @registerOperation 0x36, @ROL, @zeroPageXMode,   0, 1, 1 # 6 cycles
+        @registerOperation 0x2E, @ROL, @absoluteMode,    0, 0, 1 # 6 cycles
+        @registerOperation 0x3E, @ROL, @absoluteXMode,   0, 1, 1 # 7 cycles
+
+        @registerOperation 0x6A, @ROR, @accumulatorMode, 0, 0, 0 # 2 cycles
+        @registerOperation 0x66, @ROR, @zeroPageMode,    0, 0, 1 # 5 cycles
+        @registerOperation 0x76, @ROR, @zeroPageXMode,   0, 1, 1 # 6 cycles
+        @registerOperation 0x6E, @ROR, @absoluteMode,    0, 0, 1 # 6 cycles
+        @registerOperation 0x7E, @ROR, @absoluteXMode,   0, 1, 1 # 7 cycles

         ###################################################################
         # Hybrid instructions
         ###################################################################

-        @registerOperation 0xC7, @DCP, @zeroPageMode,  0, 1 # 5 cycles (undocumented operation)
-        @registerOperation 0xD7, @DCP, @zeroPageXMode, 1, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0xCF, @DCP, @absoluteMode,  0, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0xDF, @DCP, @absoluteXMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0xDB, @DCP, @absoluteYMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0xC3, @DCP, @indirectXMode, 1, 1 # 8 cycles (undocumented operation)
-        @registerOperation 0xD3, @DCP, @indirectYMode, 1, 1 # 8 cycles (undocumented operation)
-
-        @registerOperation 0xE7, @ISB, @zeroPageMode,  0, 1 # 5 cycles (undocumented operation)
-        @registerOperation 0xF7, @ISB, @zeroPageXMode, 1, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0xEF, @ISB, @absoluteMode,  0, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0xFF, @ISB, @absoluteXMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0xFB, @ISB, @absoluteYMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0xE3, @ISB, @indirectXMode, 1, 1 # 8 cycles (undocumented operation)
-        @registerOperation 0xF3, @ISB, @indirectYMode, 1, 1 # 8 cycles (undocumented operation)
-
-        @registerOperation 0x07, @SLO, @zeroPageMode,  0, 1 # 5 cycles (undocumented operation)
-        @registerOperation 0x17, @SLO, @zeroPageXMode, 1, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x0F, @SLO, @absoluteMode,  0, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x1F, @SLO, @absoluteXMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x1B, @SLO, @absoluteYMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x03, @SLO, @indirectXMode, 1, 1 # 8 cycles (undocumented operation)
-        @registerOperation 0x13, @SLO, @indirectYMode, 1, 1 # 8 cycles (undocumented operation)
-
-        @registerOperation 0x47, @SRE, @zeroPageMode,  0, 1 # 5 cycles (undocumented operation)
-        @registerOperation 0x57, @SRE, @zeroPageXMode, 1, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x4F, @SRE, @absoluteMode,  0, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x5F, @SRE, @absoluteXMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x5B, @SRE, @absoluteYMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x43, @SRE, @indirectXMode, 1, 1 # 8 cycles (undocumented operation)
-        @registerOperation 0x53, @SRE, @indirectYMode, 1, 1 # 8 cycles (undocumented operation)
-
-        @registerOperation 0x27, @RLA, @zeroPageMode,  0, 1 # 5 cycles (undocumented operation)
-        @registerOperation 0x37, @RLA, @zeroPageXMode, 1, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x2F, @RLA, @absoluteMode,  0, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x3F, @RLA, @absoluteXMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x3B, @RLA, @absoluteYMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x23, @RLA, @indirectXMode, 1, 1 # 8 cycles (undocumented operation)
-        @registerOperation 0x33, @RLA, @indirectYMode, 1, 1 # 8 cycles (undocumented operation)
-
-        @registerOperation 0x67, @RRA, @zeroPageMode,  0, 1 # 5 cycles (undocumented operation)
-        @registerOperation 0x77, @RRA, @zeroPageXMode, 1, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x6F, @RRA, @absoluteMode,  0, 1 # 6 cycles (undocumented operation)
-        @registerOperation 0x7F, @RRA, @absoluteXMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x7B, @RRA, @absoluteYMode, 1, 1 # 7 cycles (undocumented operation)
-        @registerOperation 0x63, @RRA, @indirectXMode, 1, 1 # 8 cycles (undocumented operation)
-        @registerOperation 0x73, @RRA, @indirectYMode, 1, 1 # 8 cycles (undocumented operation)
-
-        @registerOperation 0xCB, @AXS, @immediateMode, 0, 0 # 2 cycles (undocumented operation)
-
-    registerOperation: (operationCode, instruction, addressingMode, emptyReadCycles, emptyWriteCycles) ->
+        @registerOperation 0xC7, @DCP, @zeroPageMode,  0, 0, 1 # 5 cycles (undocumented operation)
+        @registerOperation 0xD7, @DCP, @zeroPageXMode, 0, 1, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0xCF, @DCP, @absoluteMode,  0, 0, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0xDF, @DCP, @absoluteXMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0xDB, @DCP, @absoluteYMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0xC3, @DCP, @indirectXMode, 0, 1, 1 # 8 cycles (undocumented operation)
+        @registerOperation 0xD3, @DCP, @indirectYMode, 0, 1, 1 # 8 cycles (undocumented operation)
+
+        @registerOperation 0xE7, @ISB, @zeroPageMode,  0, 0, 1 # 5 cycles (undocumented operation)
+        @registerOperation 0xF7, @ISB, @zeroPageXMode, 0, 1, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0xEF, @ISB, @absoluteMode,  0, 0, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0xFF, @ISB, @absoluteXMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0xFB, @ISB, @absoluteYMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0xE3, @ISB, @indirectXMode, 0, 1, 1 # 8 cycles (undocumented operation)
+        @registerOperation 0xF3, @ISB, @indirectYMode, 0, 1, 1 # 8 cycles (undocumented operation)
+
+        @registerOperation 0x07, @SLO, @zeroPageMode,  0, 0, 1 # 5 cycles (undocumented operation)
+        @registerOperation 0x17, @SLO, @zeroPageXMode, 0, 1, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x0F, @SLO, @absoluteMode,  0, 0, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x1F, @SLO, @absoluteXMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x1B, @SLO, @absoluteYMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x03, @SLO, @indirectXMode, 0, 1, 1 # 8 cycles (undocumented operation)
+        @registerOperation 0x13, @SLO, @indirectYMode, 0, 1, 1 # 8 cycles (undocumented operation)
+
+        @registerOperation 0x47, @SRE, @zeroPageMode,  0, 0, 1 # 5 cycles (undocumented operation)
+        @registerOperation 0x57, @SRE, @zeroPageXMode, 0, 1, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x4F, @SRE, @absoluteMode,  0, 0, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x5F, @SRE, @absoluteXMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x5B, @SRE, @absoluteYMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x43, @SRE, @indirectXMode, 0, 1, 1 # 8 cycles (undocumented operation)
+        @registerOperation 0x53, @SRE, @indirectYMode, 0, 1, 1 # 8 cycles (undocumented operation)
+
+        @registerOperation 0x27, @RLA, @zeroPageMode,  0, 0, 1 # 5 cycles (undocumented operation)
+        @registerOperation 0x37, @RLA, @zeroPageXMode, 0, 1, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x2F, @RLA, @absoluteMode,  0, 0, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x3F, @RLA, @absoluteXMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x3B, @RLA, @absoluteYMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x23, @RLA, @indirectXMode, 0, 1, 1 # 8 cycles (undocumented operation)
+        @registerOperation 0x33, @RLA, @indirectYMode, 0, 1, 1 # 8 cycles (undocumented operation)
+
+        @registerOperation 0x67, @RRA, @zeroPageMode,  0, 0, 1 # 5 cycles (undocumented operation)
+        @registerOperation 0x77, @RRA, @zeroPageXMode, 0, 1, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x6F, @RRA, @absoluteMode,  0, 0, 1 # 6 cycles (undocumented operation)
+        @registerOperation 0x7F, @RRA, @absoluteXMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x7B, @RRA, @absoluteYMode, 0, 1, 1 # 7 cycles (undocumented operation)
+        @registerOperation 0x63, @RRA, @indirectXMode, 0, 1, 1 # 8 cycles (undocumented operation)
+        @registerOperation 0x73, @RRA, @indirectYMode, 0, 1, 1 # 8 cycles (undocumented operation)
+
+        @registerOperation 0xCB, @AXS, @immediateMode, 0, 0, 0 # 2 cycles (undocumented operation)
+
+    registerOperation: (operationCode, instruction, addressingMode, pageCrossEnabled, emptyReadCycles, emptyWriteCycles) ->
         @operationsTable[operationCode] =
             instruction: instruction
             addressingMode: addressingMode
+            pageCrossEnabled: pageCrossEnabled
             emptyReadCycles: emptyReadCycles
             emptyWriteCycles: emptyWriteCycles


if no LICENCE file is found, it now looks for LICENSE and LICENSE.txt files too

--- check_licences_in_github.coffee
+++ check_licences_in_github.coffee
@@ -5,14 +5,29 @@
 compliant = 0
 total = 0

+print = (status, name) ->
+  prefixes = ["\x1b[31m ✗ ", "\x1b[32m ✓ ", "\x1b[33m ✓ "]
+  console.log prefixes[status] + name + "\x1b[0m"
+  if status > 0
+    compliant = compliant + 1
+
 check_licence = (repo, callback) ->
   request.get "https://raw.github.com/scraperwiki/" + repo.name + '/master/LICENCE', (err, resp, body) ->
     if resp.statusCode == 200
-      console.log '\x1b[32m', '✓', repo.name, '\x1b[0m'
-      compliant = compliant + 1
+      print(1, repo.name)
+      callback(null, 1)
     else
-      console.log '\x1b[31m', '✗', repo.name, '\x1b[0m'
-    callback(null, 1)
+      request.get "https://raw.github.com/scraperwiki/" + repo.name + '/master/LICENSE', (err, resp, body) ->
+        if resp.statusCode == 200
+          print(2, repo.name + ' (LICENSE)')
+          callback(null, 1)
+        else
+          request.get "https://raw.github.com/scraperwiki/" + repo.name + '/master/LICENSE.txt', (err, resp, body) ->
+            if resp.statusCode == 200
+              print(2, repo.name + ' (LICENSE.txt)')
+            else
+              print(0, repo.name)
+            callback(null, 1)

 request.get "https://api.github.com/orgs/scraperwiki/repos", (err, resp, body) ->
   repos = JSON.parse(body)


Set time units when creating graph

Set time units when creating graph

--- src/code/models/codap-connect.coffee
+++ src/code/models/codap-connect.coffee
@@ -216,6 +216,7 @@

   createGraph: (yAttributeName)->
     @_createCollection()
+    timeUnit = TimeUnits.toString SimulationStore.store.settings.stepUnits, true

     @codapPhone.call
       action: 'create',


AppController: Show status bar menu button when updating the status bar.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -306,7 +306,7 @@
     , 'editor'

   updateStatusBar: (component, data) ->
-    {status} = @statusBar
+    {status, menuButton} = @statusBar

     if component is 'editor'
       {cursor, file} = data
@@ -323,3 +323,4 @@
     else text = ''

     status.updatePartial text
+    menuButton.show()


IDE: Swap callback and optional paneType argument in helper method.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -275,6 +275,9 @@
       @statusBar.showInformation()  if ideViewLength is 0

   forEachSubViewInIDEViews_: (callback = noop, paneType) ->
+    if typeof callback is 'string'
+      [paneType, callback] = [callback, paneType]
+
     for ideView in @ideViews
       for pane in ideView.tabView.panes
         view = pane.getSubViews().first
@@ -322,9 +325,8 @@
     @getActivePaneView().emit 'SaveRequested'

   saveAllFiles: ->
-    @forEachSubViewInIDEViews_ (view) ->
-      view.emit 'SaveRequested'
-    , 'editor'
+    @forEachSubViewInIDEViews_ 'editor', (editorPane) ->
+      editorPane.emit 'SaveRequested'

   updateStatusBar: (component, data) ->
     {status, menuButton} = @statusBar
@@ -347,6 +349,5 @@
     menuButton.show()

   doResize: ->
-    @forEachSubViewInIDEViews_ (editorPane) ->
+    @forEachSubViewInIDEViews_ 'editor', (editorPane) ->
       editorPane.aceView.ace.editor.resize()
-    , 'editor'


Collaboration: Make collaboration working after ending the session.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1243,14 +1243,20 @@

   isRealtimeSessionActive: (id, callback) ->

-    @rtm.once 'FileQueryFinished', (file) =>
-
-      if file.result.items.length > 0
-        callback yes, file
-      else
-        callback no
-
-    @rtm.fetchFileByTitle @getRealTimeFileName id
+    kallback = =>
+      @rtm.once 'FileQueryFinished', (file) =>
+
+        if file.result.items.length > 0
+          callback yes, file
+        else
+          callback no
+
+      @rtm.fetchFileByTitle @getRealTimeFileName id
+
+    if @rtm then kallback()
+    else
+      @rtm = new RealTimeManager
+      @rtm.ready => kallback()

   setSocialChannel: (channel) ->
@@ -1392,6 +1398,7 @@
         @chat.emit 'CollaborationEnded'
         @chat = null
         @modal.destroy()
+        @rtm = null
         KD.singletons.mainView.activitySidebar.emit 'ReloadMessagesRequested'

       @rtm.deleteFile @getRealTimeFileName()
@@ -1519,6 +1526,7 @@
           callback : => @modal.destroy()

     @showModal options
+    @rtm = null

   showSessionEndedModal: ->
@@ -1536,6 +1544,7 @@

     @showModal options
     @removeMachineNode()
+    @rtm = null

   handleParticipantLeaveAction: ->
@@ -1548,6 +1557,7 @@
       @broadcastMessages.push origin: KD.nick(), type: 'ParticipantWantsToLeave'
       @removeMachineNode()
       @modal.destroy()
+      @rtm = null
       KD.singletons.mainView.activitySidebar.emit 'ReloadMessagesRequested'
       KD.singletons.router.handleRoute '/IDE'


Indentation fix

Indentation fix

--- client/src/lib/bar_chart.coffee
+++ client/src/lib/bar_chart.coffee
@@ -53,11 +53,11 @@
       .attr("transform", "translate(30," + height + ")")
       .call(xAxis)
       .selectAll("text")
-      .attr("y", 2)
-      .attr("x", 9)
-      .attr("dy", "1em")
-      .attr("transform", "rotate(45)")
-      .style("text-anchor", "start")
+        .attr("y", 2)
+        .attr("x", 9)
+        .attr("dy", "1em")
+        .attr("transform", "rotate(45)")
+        .style("text-anchor", "start")

   setGAxisDomElement = (selection, data) ->
     gAxis = selection.selectAll('g.axis').data [data]


Make slider handles updatable from arrow keys (#7140)

* Make slider handles updatable from arrow keys

* Make sure not to trigger callback when keypress isn't an arrow key

* fix trailing whitespace

--- bokehjs/src/coffee/models/widgets/abstract_slider.coffee
+++ bokehjs/src/coffee/models/widgets/abstract_slider.coffee
@@ -67,6 +67,30 @@

       @sliderEl.noUiSlider.on('slide',  (_, __, values) => @_slide(values))
       @sliderEl.noUiSlider.on('change', (_, __, values) => @_change(values))
+
+      # Add keyboard support
+      keypress = (e) =>
+        value = Number(@sliderEl.noUiSlider.get())
+        switch e.which
+          when 37
+            value -= step
+          when 39
+            value += step
+          else
+            return
+
+        pretty = @model.pretty(value)
+        logger.debug("[slider keypress] value = #{pretty}")
+        @model.value = value
+        @sliderEl.noUiSlider.set(value)
+        if @valueEl?
+          @valueEl.textContent = pretty
+        @callback_wrapper?()
+
+      handle = @sliderEl.querySelector(".#{prefix}handle")
+      handle.setAttribute('tabindex', 0)
+      handle.addEventListener('click', @focus)
+      handle.addEventListener('keydown', keypress)

       toggleTooltip = (i, show) =>
         handle = @sliderEl.querySelectorAll(".#{prefix}handle")[i]


Added Renderer as Annotation base class

Added Renderer as Annotation base class

--- bokehjs/src/coffee/renderer/annotation/annotation.coffee
+++ bokehjs/src/coffee/renderer/annotation/annotation.coffee
@@ -1,7 +1,7 @@
 _ = require "underscore"
-Model = require "../../models/model"
+Renderer = require "../renderer"

-class Annotation extends Model
+class Annotation extends Renderer
   type: 'Annotation'

   defaults: ->


Suppress debug message

Suppress debug message

--- src/memhttprequest.coffee
+++ src/memhttprequest.coffee
@@ -323,8 +323,9 @@
         unless http == "HTTP/1.0" or http == "HTTP/1.1"
           return failed("Invalid response start line")
         @status = parseInt(@statusText)
-        console.log({"response-status": @status})
-        console.log({"response-header": "#{resp}\r\n\r\n"})
+        if DEBUG > 0
+          console.log({"response-status": @status})
+          console.log({"response-header": "#{resp}\r\n\r\n"})
         @responseHeaders = {}
         for line in lines
           [name, value] = line.split(":", 2)
@@ -353,7 +354,7 @@
           @response = @responseBuffer
         else
           throw new TypeError("Unsupported responseType")
-      console.log({"response-body": @response})
+      console.log({"response-body": @response}) if DEBUG > 0
       packet.discard(=> @changeState(@DONE))
     )


remove with splice

remove with splice

--- app/assets/javascripts/angular_blog/angular_app/controllers/posts_controller.js.coffee
+++ app/assets/javascripts/angular_blog/angular_app/controllers/posts_controller.js.coffee
@@ -62,7 +62,7 @@
           working_post,
           (post)->
             ctrl.data.posts ||= []
-            ctrl.data.posts.splice(index,0,post)
+            ctrl.data.posts.splice(index,1,post)
             ctrl.clear()
             ctrl.locked = false
           ,


For super-admins and app owners return app even its not approved yet, otherwise return null.

--- workers/social/lib/social/models/app.coffee
+++ workers/social/lib/social/models/app.coffee
@@ -322,14 +322,22 @@

   # Do not return not approved apps
   @one$ = secure (client, selector, options, callback)->
+    {delegate} = client.connection
     [options, callback] = [callback, options] unless callback
     @one selector, options, (err, app)->
-      if err then callback err
-      else unless app.approved then callback null
-      else callback null, app
+      if err or not app
+        return callback err
+      else unless app.approved
+        if (delegate.checkFlag 'super-admin') or   \
+           (delegate.checkFlag 'app-publisher' and \
+            delegate.getId().equals app.originId)
+          return callback null, app
+        return callback null
+      callback null, app

   @someWithRelationship: secure (client, selector, options, callback)->
     {delegate} = client.connection
+    selector or= {}

     # Just show approved apps to regular users
     if not delegate.checkFlag 'super-admin'


Workspace: Added getActivePaneFileData method for editor pane.

--- client/landing/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
+++ client/landing/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
@@ -33,6 +33,9 @@

   getActivePaneContent: ->
     return @tabView.getActivePane().subViews[0].getValue()
+
+  getActivePaneFileData: ->
+    return @tabView.getActivePane().subViews[0].getData()

   createEditorTabs: ->
     @tabHandleContainer = new ApplicationTabHandleHolder


Remove unnecessary comma dangle

Remove unnecessary comma dangle

--- src/loaders/collection-loader.coffee
+++ src/loaders/collection-loader.coffee
@@ -4,7 +4,7 @@
 Collection = require '../collection'
 AbstractLoader = require './abstract-loader'

-knownResponseKeys = ['count', 'results', '_meta']
+knownResponseKeys = ['count', 'results', 'meta']

 class CollectionLoader extends AbstractLoader

@@ -64,7 +64,7 @@
     #    time_entries: [{ id: 2, title: "te1", project_id: 6, task_id: [10, 11] }]
     #    projects: [{id: 6, title: "some project", time_entry_ids: [2] }]
     #    tasks: [{id: 10, title: "some task" }, {id: 11, title: "some other task" }]
-    #    _meta: {
+    #    meta: {
     #      count: 200,
     #      page_number: 1,
     #      page_count: 10,


Make sending messages more robust

Make sending messages more robust

--- src/public/models/remote.peer.coffee
+++ src/public/models/remote.peer.coffee
@@ -67,9 +67,7 @@
 			channel = @_connection.createDataChannel('a', @_channelConfiguration)
 			@_connection.createOffer(@_onLocalDescription)

-			@on('connect', =>
-				@_addChannel(channel)
-			)
+			@_addChannel(channel)

 		# Disconnects from the peer.
 		#
@@ -83,15 +81,30 @@
 		isConnected: ( ) ->
 			return @_connection.iceConnectionState is 'connected'

+		# Returns wether or not the data channel to this peer is open
+		#
+		# @return [Boolean] wether or not the channel is open
+		#
+		isChannelOpen: ( ) ->
+			return @_channel?.readyState is 'open'
+
 		# Sends a predefined message to the remote.
 		#
 		# @param message [Message] the message to send
 		#
-		_send: ( message ) ->
-			unless @_channel?.readyState is 'open'
+		_send: ( message, retries = 0 ) ->
+			maxRetries = 5
+
+			unless @isChannelOpen()
 				return

-			@_channel.send(message.serialize())
+			try
+				@_channel.send(message.serialize())
+			catch error
+				if retries < maxRetries
+					_( => @_send(message, retries + 1)).defer()
+				else
+					console.log 'failed to send message', message

 		# Adds a new data channel, and adds event bindings to it.
 		#
@@ -174,8 +187,6 @@
 		# @param event [Event] the channel open event
 		#
 		_onChannelOpen: ( event ) =>
-			@_channelOpen = true
-
 			@_pingInterval = setInterval( ( ) =>
 				@ping( ( latency, coordinateString ) =>
 					@latency = latency
@@ -194,7 +205,6 @@
 		# @param event [Event] the channel close event
 		#
 		_onChannelClose: ( event ) =>
-			@_channelOpen is false
 			@trigger('channel.closed', @, event)

 		# Is called when a connection has been established.


fix a bug with detecting auth_token that @hsy noticed

--- src/smc-webapp/client_browser.coffee
+++ src/smc-webapp/client_browser.coffee
@@ -71,8 +71,6 @@
     idle_notification_state = show

 # end idle notifications
-
-auth_token = QueryParams.get('auth_token')

 class Connection extends client.Connection
     constructor: (opts) ->
@@ -249,11 +247,10 @@
             conn.removeAllListeners('data')
             conn.on("data", ondata)

-            if auth_token
-                @sign_in_using_auth_token
-                    auth_token : auth_token
-                    cb         : (err, resp) ->
-                        auth_token = undefined
+            auth_token = QueryParams.get('auth_token')
+            if not @_signed_in and auth_token
+                QueryParams.remove('auth_token')
+                @sign_in_using_auth_token(auth_token : auth_token)
             else if should_do_anonymous_setup()
                 do_anonymous_setup(@)


Set newBody property when rendering errors

It's expected by the Turbolinks.Renderer super class

--- src/turbolinks/error_renderer.coffee
+++ src/turbolinks/error_renderer.coffee
@@ -1,16 +1,22 @@
 #= require ./renderer

 class Turbolinks.ErrorRenderer extends Turbolinks.Renderer
-  constructor: (@html) ->
+  constructor: (html) ->
+    htmlElement = document.createElement("html")
+    htmlElement.innerHTML = html
+    @newHead = htmlElement.querySelector("head")
+    @newBody = htmlElement.querySelector("body")

   render: (callback) ->
     @renderView =>
-      @replaceDocumentHTML()
+      @replaceHeadAndBody()
       @activateBodyScriptElements()
       callback()

-  replaceDocumentHTML: ->
-    document.documentElement.innerHTML = @html
+  replaceHeadAndBody: ->
+    {head, body} = document
+    head.parentNode.replaceChild(@newHead, head)
+    body.parentNode.replaceChild(@newBody, body)

   activateBodyScriptElements: ->
     for replaceableElement in @getScriptElements()


groups: fixed a missing data check in customize view

--- client/landing/app/Applications/Groups.kdapplication/Views/groupscustomizeviews.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/groupscustomizeviews.coffee
@@ -140,7 +140,7 @@
   getBackgroundData:(data={})->
       if data.customize?.background?
         data.customize.background
-      else if data.profile.staticPage?.customize?.background?
+      else if data.profile?.staticPage?.customize?.background?
         data.profile.staticPage.customize.background
       else {}


Enable the dropdown tests.

Enable the dropdown tests.

--- test/e2e/collectionDetailSpec.coffee
+++ test/e2e/collectionDetailSpec.coffee
@@ -132,7 +132,7 @@
         expect(dropdowns.length, 'The Y-axis dropdown count is incorrect')
           .to.equal(4)

-    xit 'should display the Y-axis dropdown items', ->
+    it 'should display the Y-axis dropdown items', ->
       page.yAxisDropdowns.then (dropdowns) ->
         dropdown = _.first(dropdowns)
         # Show the dropdown.


fix lineman new (one arg per arg)

fix lineman new (one arg per arg)

--- test/spec-e2e/helpers/lineman.coffee
+++ test/spec-e2e/helpers/lineman.coffee
@@ -10,7 +10,7 @@
   new: (name, callback, done) ->
     currentLinemanPath = process.env.SPEC_TEMP_DIR
     name += "-#{new Date().getTime()}"
-    exec("new", "--coffee --stack", name, standardResponder(callback, done))
+    exec("new", "--coffee", "--stack", name, standardResponder(callback, done))
     currentLinemanPath += "/#{name}"

   build: (callback, done) ->


fix(star): Bulk star icon has never shown current state(?!)

--- internal_packages/thread-list/lib/thread-buttons.cjsx
+++ internal_packages/thread-list/lib/thread-buttons.cjsx
@@ -68,14 +68,19 @@
     selection: React.PropTypes.object.isRequired

   render: ->
-    noStars = _.every @props.selection.items(), (t) -> _.isMatch(t, {starred: false})
-    title = if noStars then "Star all" else "Remove stars from all"
+    postClickStarredState = _.every @props.selection.items(), (t) -> t.starred is false
+    title = "Remove stars from all"
+    imageName = "toolbar-star-selected.png"
+
+    if postClickStarredState
+      title = "Star all"
+      imageName = "toolbar-star.png"

     <button style={order:-104}
             className="btn btn-toolbar"
             title={title}
             onClick={@_onStar}>
-      <RetinaImg name="toolbar-star.png" mode={RetinaImg.Mode.ContentIsMask} />
+      <RetinaImg name={imageName} mode={RetinaImg.Mode.ContentIsMask} />
     </button>

   _onStar: =>


Adds sections to integration test

Adds sections to integration test

--- api/apps/articles/test/integration.test.coffee
+++ api/apps/articles/test/integration.test.coffee
@@ -133,6 +133,10 @@
         {
           title: 'Cows on the prarie'
           _id: ObjectId '5086df098523e60002000012'
+          sections: [{
+            type: "text",
+            body: "Cows on the lawn"
+          }]
           published: true
         }
       ], (err, articles) =>
@@ -140,6 +144,8 @@
           .get("http://localhost:5000/articles/5086df098523e60002000012")
           .set('X-Access-Token': @token)
           .end (err, res) ->
+            res.body.sections[0].type.should.equal 'text'
+            res.body.sections[0].body.should.equal 'Cows on the lawn'
             res.body.title.should.equal 'Cows on the prarie'
             done()


update anti cache js class names

update anti cache js class names

--- app/assets/javascripts/folio/anti-cache.coffee
+++ app/assets/javascripts/folio/anti-cache.coffee
@@ -20,11 +20,14 @@
   if immediate
     $old
       .addClass('folio-anti-cache--done')
+      .addClass('folio-anti-cache--immediate')
       .trigger('folioAntiCacheDone')
   else
     setTimeout (->
       $old
+        .removeClass('folio-anti-cache--immediate')
         .addClass('folio-anti-cache--done')
+        .addClass('folio-anti-cache--final')
         .trigger('folioAntiCacheDone')
     ), 0


Charts: show target series in table view

Closes #1137

--- app/assets/javascripts/lib/models/chart.coffee
+++ app/assets/javascripts/lib/models/chart.coffee
@@ -138,8 +138,12 @@
   # This is used to show a chart as a table
   # See base_chart_view#render_as_table
   formatted_series_hash : ->
-    # the @non_target_series() array is wrapped in underscore to fix an IE8 bug
-    items = _(@non_target_series()).map (s) =>
+    # Legacy code duplicates target series. See stacked_bar.coffee#draw
+    targets_without_duplicates = _.uniq @target_series(), false, (s) -> s.get 'label'
+    series = _.union @non_target_series(), targets_without_duplicates
+
+    # the series array is wrapped in underscore to fix an IE8 bug
+    items = _(series).map (s) =>
       type = @get 'type'
       label = s.get 'label'
       if (type == 'mekko') || (type == 'horizontal_stacked_bar')
@@ -149,6 +153,7 @@
         label: label
         present_value: Metric.autoscale_value(s.safe_present_value(), unit, 2)
         future_value:  Metric.autoscale_value(s.safe_future_value(),  unit, 2)
+
     # some charts draw series bottom to top. Let's flip the array
     return items.reverse() if @get('type') in ['vertical_stacked_bar', 'bezier']
     items


fix(message-list): allow starring messages by pressing 's'. Fixes T2430.

Summary: Although this code works as desired, I think the code itself could use some work. Also, I didn't know how I should test this. Any ideas? @bengotow

Test Plan: I'm all ears

Reviewers: bengotow

Reviewed By: bengotow

Subscribers: bengotow

Maniphest Tasks: T2430

Differential Revision: https://phab.nylas.com/D1877

--- internal_packages/thread-list/lib/thread-list-store.coffee
+++ internal_packages/thread-list/lib/thread-list-store.coffee
@@ -138,10 +138,14 @@

   _onToggleStarFocused: ->
     focused = FocusedContentStore.focused('thread')
-    return unless focused
-
-    task = new ChangeStarredTask(thread: focused, starred: !focused.starred)
-    Actions.queueTask(task)
+    cursor = FocusedContentStore.keyboardCursor('thread')
+    if focused
+      task = new ChangeStarredTask(thread: focused, starred: !focused.starred)
+    else if cursor
+      task = new ChangeStarredTask(thread: cursor, starred: !cursor.starred)
+
+    if task
+      Actions.queueTask(task)

   _onArchive: ->
     @_archiveAndShiftBy('auto')


limit tooltips at 40 names

limit tooltips at 40 names

--- app/assets/javascripts/species/views/documents/documents_tooltip_component.js.coffee
+++ app/assets/javascripts/species/views/documents/documents_tooltip_component.js.coffee
@@ -6,7 +6,10 @@
   ).property('person')

   formattedData: ( ->
-    this.get('data').join(', ')
+    data = this.get('data')
+    dataStr = data.slice(0,40).join(', ')
+
+    if data.length <= 40 then dataStr else dataStr + '...'
   ).property()

   isTaxa: ( ->


Start removing old prove option

Start removing old prove option

--- menus/atom-perl6-editor-tools.cson
+++ menus/atom-perl6-editor-tools.cson
@@ -5,10 +5,6 @@
     {
       'label': 'Perl 6 - POD Preview'
       'command': 'atom-perl6-editor-tools:toggle'
-    },
-    {
-      'label': 'Perl 6 - Run Tests (prove)'
-      'command': 'atom-perl6-editor-tools:run-tests'
     },
     { 'type': 'separator' }
   ]
@@ -21,10 +17,6 @@
         {
           'label': 'POD Preview'
           'command': 'atom-perl6-editor-tools:toggle'
-        },
-        {
-          'label': 'Run Tests (prove)'
-          'command': 'atom-perl6-editor-tools:run-tests'
         }
       ]
     ]


other works for sale (closes #4147)

other works for sale (closes #4147)

--- apps/artwork/client/setup_artwork_rails.coffee
+++ apps/artwork/client/setup_artwork_rails.coffee
@@ -12,19 +12,19 @@
     title: "Similar#{forSaleModifier} Artworks by #{artwork.artist?.name}"
   partner_artworks:
     url: "/#{artwork.partner?.default_profile_id}/works"
-    title: "More#{forSaleModifier} Works from #{artwork.partner?.name}"
+    title: "Other#{forSaleModifier} Works from #{artwork.partner?.name}"
   artist_artworks:
     url: "/artist/#{artwork.artist.id}/works"
-    title: "More#{forSaleModifier} Works by #{artwork.artist?.name}"
+    title: "Other#{forSaleModifier} Works by #{artwork.artist?.name}"
   show_artworks:
     url: "/show/#{artwork.shows[0]?.id}"
-    title: "More#{forSaleModifier} Works from #{artwork.shows[0]?.name}"
+    title: "Other#{forSaleModifier} Works from #{artwork.shows[0]?.name}"
   current_auction_artworks:
     url: "/auction/#{artwork.related?.id}"
-    title: "More#{forSaleModifier} Works from #{artwork.related?.name}"
+    title: "Other#{forSaleModifier} Works from #{artwork.related?.name}"
   closed_auction_artworks:
     url: "/auction/#{artwork.related?.id}"
-    title: "More#{forSaleModifier} Works from #{artwork.related?.name}"
+    title: "Other#{forSaleModifier} Works from #{artwork.related?.name}"

 module.exports = (model, artist) ->
   new LayeredSearchView


Specs for new fair behavior

Specs for new fair behavior

--- apps/artwork/test/client/layered-search.coffee
+++ apps/artwork/test/client/layered-search.coffee
@@ -9,6 +9,7 @@
   benv.requireWithJadeify resolve(__dirname, '../../client/layered-search'), ['template']

 Artwork = require '../../../../models/artwork'
+Fair    = require '../../../../models/fair'

 describe 'Layers, Layer', ->
   beforeEach ->
@@ -27,6 +28,38 @@
       @layers.fetch()
       @layers.url.should.include 'api/v1/related/layers'
       Backbone.sync.args[0][1].artwork.id.should.equal @artwork.id
+
+    it 'should be correctly ordered', ->
+      @layers.reset [
+        { type: 'synthetic', id: 'for-sale' }
+        { type: 'gene', id: 'foobar' }
+        { type: 'synthetic', id: 'main' }
+        { type: 'gene', id: 'bazqux' }
+      ]
+      @layers.first().id.should.equal 'main'
+      @layers.last().id.should.equal 'for-sale'
+
+  describe 'with fair', ->
+    beforeEach ->
+      @fair      = new Fair fabricate 'fair'
+      @artwork   = new Artwork fabricate 'artwork'
+      @layers    = new Layers artwork: @artwork, fair: @fair
+      @layers.reset [
+        { type: 'synthetic', id: 'for-sale' }
+        { type: 'gene', id: 'foobar' }
+        { type: 'synthetic', id: 'main' }
+        { type: 'fair', id: @fair.id }
+        { type: 'gene', id: 'bazqux' }
+      ]
+
+    it 'should set up both relationships for the fair', ->
+      @layers.fair.id.should.equal @fair.id
+      @layers.artwork.id.should.equal @artwork.id
+
+    it 'should be correctly ordered', ->
+      @layers.first().id.should.equal @fair.id
+      @layers.at(1).id.should.equal 'main'
+      @layers.last().id.should.equal 'for-sale'

   describe 'Layer', ->
     beforeEach ->
@@ -55,49 +88,78 @@
   after ->
     benv.teardown()

-  beforeEach (done) ->
-    sinon.stub Backbone, 'sync'
-    @artwork  = new Artwork fabricate 'artwork'
-    @view     = new LayeredSearchView $el: $('

'), artwork: @artwork
-    done()
+  describe 'with an artwork', ->
+    beforeEach (done) ->
+      sinon.stub Backbone, 'sync'
+      @artwork  = new Artwork fabricate 'artwork'
+      @view     = new LayeredSearchView $el: $('

'), artwork: @artwork
+      done()

-  afterEach ->
-    Backbone.sync.restore()
+    afterEach ->
+      Backbone.sync.restore()

-  describe '#setupLayers', ->
-    it 'has the artwork ID', ->
-      @view.layers.artwork.id.should.equal @artwork.id
-    it 'fetches the layer based on the artwork ID', ->
-      Backbone.sync.args[0][1].artwork.id.should.equal @artwork.id
+    describe '#setupLayers', ->
+      it 'has the artwork ID', ->
+        @view.layers.artwork.id.should.equal @artwork.id
+      it 'fetches the layer based on the artwork ID', ->
+        Backbone.sync.args[0][1].artwork.id.should.equal @artwork.id

-  describe 'rendered view', ->
-    beforeEach ->
+    describe 'rendered view', ->
+      beforeEach ->
+        @artworks  = _.times 2, -> new Artwork fabricate 'artwork'
+        @layers    = _.times 2, -> id: _.uniqueId('layer'), name: _.uniqueId('name')
+        @view.layers.reset @layers
+        @view.render()
+
+      describe '#render', ->
+        it 'has buttons for each layer', ->
+          @view.$('.layered-search-layer-button').length.should.equal @layers.length
+
+      describe '#postRender', ->
+        it 'activates the first tab', ->
+          buttons = @view.$('.layered-search-layer-button')
+          buttons.first().data('state').should.equal 'active'
+          buttons.last().data('state').should.equal 'inactive'
+
+      describe '#selectLayer', ->
+        beforeEach ->
+          @$buttons = @view.$('.layered-search-layer-button')
+          @$target  = @$buttons.last()
+          @$target.click()
+        it 'should activate the correct layer', ->
+          id = @$target.data 'id'
+          @view.__activeLayer__.id.should.equal id
+          @view.activeLayer().id.should.equal id
+        it 'should activate the button and deactivate the others', ->
+          @$target.data('state').should.equal 'active'
+          @$buttons.not(@$target).data('state').should.equal 'inactive'
+        it 'should have a spinner', ->
+          @view.$layeredSearchResults.html().should.include 'loading-spinner'
+
+  describe 'with an artwork and a fair', ->
+    beforeEach (done) ->
+      sinon.stub Backbone, 'sync'
+      @artwork  = new Artwork fabricate 'artwork'
+      @fair     = new Fair fabricate 'fair'
+      @view     = new LayeredSearchView $el: $('

'), artwork: @artwork
+
       @artworks  = _.times 2, -> new Artwork fabricate 'artwork'
-      @layers    = _.times 2, -> id: _.uniqueId('layer'), name: _.uniqueId('layer')
+      @layers    = _.times 2, -> id: _.uniqueId('layer'), name: _.uniqueId('name')
+      @view.layers.fair = @fair
+      @layers.push id: _.uniqueId('layer'), type: 'fair'
       @view.layers.reset @layers
       @view.render()

-    describe '#render', ->
-      it 'has buttons for each layer', ->
-        @view.$('.layered-search-layer-button').length.should.equal @layers.length
+      done()

-    describe '#postRender', ->
-      it 'activates the first tab', ->
-        buttons = @view.$('.layered-search-layer-button')
-        buttons.first().data('state').should.equal 'active'
-        buttons.last().data('state').should.equal 'inactive'
+    afterEach ->
+      Backbone.sync.restore()

-    describe '#selectLayer', ->
-      beforeEach ->
-        @$buttons = @view.$('.layered-search-layer-button')
-        @$target  = @$buttons.last()
-        @$target.click()
-      it 'should activate the correct layer', ->
-        id = @$target.data 'id'
-        @view.__activeLayer__.id.should.equal id
-        @view.activeLayer().id.should.equal id
-      it 'should activate the button and deactivate the others', ->
-        @$target.data('state').should.equal 'active'
-        @$buttons.not(@$target).data('state').should.equal 'inactive'
-      it 'should have a spinner', ->
-        @view.$layeredSearchResults.html().should.include 'loading-spinner'
+    it 'should have the fair as the first tab', ->
+      @$buttons = @view.$('.layered-search-layer-button')
+      @$buttons.first().text().should.equal "Works from #{@fair.get('name')}"
+
+
+
+
+


Make tests pass

Make tests pass

--- bokehjs/src/coffee/models/canvas/canvas.coffee
+++ bokehjs/src/coffee/models/canvas/canvas.coffee
@@ -44,7 +44,7 @@
     @connect(@solver.layout_reset, () => @_add_constraints())

   # Method exists so that context can be stubbed in unit tests
-  get_ctx: () -> return @canvas_el.getContext('2d')
+  get_ctx: () -> return @ctx

   get_canvas_element: () -> @canvas_el


need to create canvas for webgl output too (#6403)

--- bokehjs/src/coffee/models/canvas/canvas.coffee
+++ bokehjs/src/coffee/models/canvas/canvas.coffee
@@ -28,7 +28,7 @@
     @overlays_el = @el.appendChild(div({class: "bk-canvas-overlays"}))

     switch @model.output_backend
-      when "canvas"
+      when "canvas", "webgl"
         @canvas_el = @el.appendChild(canvas({class: "bk-canvas"}))
         @_ctx = @canvas_el.getContext('2d')
       when "svg"


payment: use existential operator

payment: use existential operator

those fields may not exist in the form

--- client/landing/app/Applications/Dashboard.kdapplication/views/producteditform.coffee
+++ client/landing/app/Applications/Dashboard.kdapplication/views/producteditform.coffee
@@ -110,9 +110,9 @@
     do (i = @inputs) =>
       title           = i.title.getValue()
       description     = i.description.getValue()
-      overageEnabled  = i.overageEnabled.getValue()
-      soldAlone       = i.soldAlone.getValue()
-      priceIsVolatile = i.priceIsVolatile.getValue()
+      overageEnabled  = i.overageEnabled?.getValue()
+      soldAlone       = i.soldAlone?.getValue()
+      priceIsVolatile = i.priceIsVolatile?.getValue()
       feeAmount       =
         unless priceIsVolatile
         then i.feeAmount.getValue() * 100
@@ -120,8 +120,8 @@
       { subscriptionType, feeUnit, feeInterval } = @getPlanInfo()

       {
-        title         : i.title.getValue()
-        description   : i.description.getValue()
+        title
+        description
         feeAmount
         feeUnit
         feeInterval


Override URL for delete to avoid urlencode issues

--- lib/sensu-dashboard/assets/javascripts/models/stash.coffee
+++ lib/sensu-dashboard/assets/javascripts/models/stash.coffee
@@ -16,6 +16,12 @@
       options.wait = true
       Backbone.create(attributes, options)

+    sync: (method, model, options) =>
+      options ||= {}
+      if method == 'delete'
+        options.url = SensuDashboard.Stashes.url + '/' + model.get('path')
+      Backbone.sync(method, model, options)
+
     remove: (options = {}) =>
       @successCallback = options.success
       @errorCallback = options.error


Combine the first two checks into one to make it more readable

--- packages/rocketchat-message-pin/client/actionButton.coffee
+++ packages/rocketchat-message-pin/client/actionButton.coffee
@@ -5,14 +5,12 @@
 		i18nLabel: 'Pin_Message'
 		action: (event, instance) ->
 			message = @_arguments[1]
+			message.pinned = true
 			Meteor.call 'pinMessage', message, (error, result) ->
 				if error
 					return Errors.throw error.reason
 		validation: (message) ->
-			if message.pinned
-				return false
-
-			if !RocketChat.settings.get('Message_AllowPinning')
+			if message.pinned or not RocketChat.settings.get('Message_AllowPinning')
 				return false

 			if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin'
@@ -27,18 +25,17 @@
 		i18nLabel: 'Unpin_Message'
 		action: (event, instance) ->
 			message = @_arguments[1]
+			message.pinned = false
 			Meteor.call 'unpinMessage', message, (error, result) ->
 				if error
 					return Errors.throw error.reason
 		validation: (message) ->
-			if not message.pinned
-				return false
-
-			if !RocketChat.settings.get('Message_AllowPinning')
+			if not message.pinned or not RocketChat.settings.get('Message_AllowPinning')
 				return false

 			if RocketChat.settings.get('Message_AllowPinningByAnyone') or RocketChat.authz.hasRole Meteor.userId(), 'admin'
 				return true

+			console.log 'UNpin-message', '---- is user the room owner', room.u?._id is Meteor.userId()
 			return room.u?._id is Meteor.userId()
-		order: 20
+		order: 21


Remove debug line.

Remove debug line.

--- services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
+++ services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
@@ -354,7 +354,6 @@
 			}

 		$scope.showBulkAcceptDialog = () ->
-			console.log "showBulkAcceptDialog"
 			showBulkActionsDialog true

 		$scope.showBulkRejectDialog = () -> showBulkActionsDialog false


Fix when the mini review panel is hidden

--- services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
+++ services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
@@ -33,9 +33,11 @@
 		# TODO Just for prototyping purposes; remove afterwards.
 		mockedUserId = '12345abc'

-		#TODO: Doesn't work anymore now entries is first indexed by doc_id
-		$scope.$watch (() -> Object.keys($scope.reviewPanel.entries).length), (nEntries) ->
-			$scope.reviewPanel.hasEntries = nEntries > 0
+		$scope.$watch (() ->
+			entries = $scope.reviewPanel.entries[$scope.editor.open_doc_id] or {}
+			Object.keys(entries).length
+		), (nEntries) ->
+			$scope.reviewPanel.hasEntries = nEntries > 0 and $scope.trackChangesFeatureFlag

 		$scope.$watch "ui.reviewPanelOpen", (reviewPanelOpen) ->
 			return if !reviewPanelOpen?


Reverse events (newest on top)

Reverse events (newest on top)

--- plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/events.coffee
+++ plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/events.coffee
@@ -23,7 +23,7 @@
       tr className: 'cluster-events',
         td colSpan: '5',
           h5 null, "Events within the last hour:"
-          for event in events
+          for event in events.reverse()
             div key: event.firstTimestamp,
               i className: "event-type #{event.type.toLowerCase()}"
               strong null,


fixing clicking histogram bar removes histogram

Former-commit-id: 15d232c13a23f532b387c30320848356e4a7542f [formerly 07878fec8bf65e8ddc8bbed0501ea6c2a3441ae0] [formerly 93c243fef8d1922f5f6475f4d6c807b40045d932 [formerly 93c243fef8d1922f5f6475f4d6c807b40045d932 [formerly 5690c6c330edb623f860720d19921390d0496029]]]
Former-commit-id: 12c37e434d8eda1303315fb7914004af007a5b86 [formerly 1d26f7de1dc3264d8f17497729e3aad879eeb2e4]
Former-commit-id: b93739788e3e70910015d378f690f47eae2e0b9f
Former-commit-id: 0263443952bad71f6243f9eecad5f432071fd072

--- app/assets/javascripts/backbone/apps/franklin/proposal/proposal_aggregate_view.coffee
+++ app/assets/javascripts/backbone/apps/franklin/proposal/proposal_aggregate_view.coffee
@@ -146,7 +146,6 @@
         @$el.addClass 'm-histogram-segment-selected'
         #@$el.find('.m-bar-percentage').hide()

-
         $bar = $target.closest('.m-histogram-bar')
         # bubble_offset = $bar.offset().top - @$el.closest('.l-message-body').offset().top + 20

@@ -160,7 +159,6 @@
         fld = "score_stance_group_#{bucket}"

         @trigger 'histogram:segment_results', bucket
-

         @$el.find('.l-message-speaker').css('z-index': 999)

@@ -179,9 +177,10 @@
     closeBarKey : (ev) -> @deselectBar() if ev.keyCode == 27 && $('#l-dialog-detachable').children().length == 0 && $('.m-point-expanded').length == 0

     deselectBar : (ev) ->
-      @$el.hide()
       $selected_bar = @$el.find('.m-bar-is-selected')
       return if $selected_bar.length == 0 || (ev && ev.type == 'mouseleave' && $selected_bar.is('.m-bar-is-hard-selected')) || $('.m-point-expanded').length > 0
+
+      @$el.hide()

       @$el.removeClass 'm-histogram-segment-selected'


Test legacy sqlite URLs (with / in box name) too

--- integration_test/cobalt.coffee
+++ integration_test/cobalt.coffee
@@ -396,6 +396,17 @@
         it 'has value 49', ->
           (JSON.parse resp.body)[0]['num*num'].should.equal 49

+      it 'redirected for legacy URLs with / in box name', (done) ->
+          legacy_boxname = boxname.replace('.', '/')
+          request.get
+            uri: "#{baseurl}/#{legacy_boxname}/0123456789/sqlite/"
+            qs: options.qs
+            followRedirect:false
+            , (err, resp, body) ->
+              resp.should.have.status 301
+              done()
+
+
     describe 'without a publishing token set in scraperwiki.json', ->
       before (done) ->
         scp_cmd "./integration_test/fixtures/scraperwiki-database.json", "scraperwiki.json", done


Adjust text so there's a space after "Delete Assignment"

--- tutor/src/components/task-plan/footer/help-tooltip.cjsx
+++ tutor/src/components/task-plan/footer/help-tooltip.cjsx
@@ -27,9 +27,8 @@
       Cancel will discard all changes and return to the calendar.

     {

-      Delete Assignment
-      will remove the assignment from students dashboards.  Students who
-      have worked the assignment will still be able to review their work.
+      Delete Assignment will remove the assignment from students
+      dashboards.  Students who have worked the assignment will still be able to review their work.

 if isPublished}
   </BS.Popover>


added remove_image method

added remove_image method

--- bokehjs/src/coffee/renderer/tile/image_source.coffee
+++ bokehjs/src/coffee/renderer/tile/image_source.coffee
@@ -34,10 +34,11 @@
       result_str = result_str.replace('{'+key+'}', value.toString())
     return result_str

-  get_images_by_extent: (xmin, ymin, xmax, ymax) ->
-
   add_image: (image_obj) ->
     @images[image_obj.cache_key] = image_obj
+
+  remove_image: (image_obj) ->
+    delete @images[image_obj.cache_key]

   get_image_url: (xmin, ymin, xmax, ymax, height, width) ->
     image_url = @string_lookup_replace(@get('url'), @get('extra_url_vars'))


style changes to rep button

style changes to rep button

--- client/Social/Members/ContentDisplays/profileview.coffee
+++ client/Social/Members/ContentDisplays/profileview.coffee
@@ -502,6 +502,7 @@
       @badgeItemsList = new UserPropertyList {}, counts : @memberData.counts
       # show "Thank You" button to admins
       @thankButton = new KDButtonView
+        cssClass   : "solid green"
         title      : "+1 rep"
         type       : "submit"
         callback   : =>


Workspace: Fixed editor pane files option.

--- client/app/CommonViews/workspace/panes/editorpane.coffee
+++ client/app/CommonViews/workspace/panes/editorpane.coffee
@@ -6,7 +6,7 @@

     super options, data

-    @files = @getOptions "files"
+    {@files} = @getOptions()

     if Array.isArray @files then @createEditorTabs() else @createSingleEditor()


Select the first result by default for tabs and bookmarks modes

--- content_scripts/vomnibar.coffee
+++ content_scripts/vomnibar.coffee
@@ -10,10 +10,11 @@
   #
   # Activate the Vomnibox.
   #
-  activateWithCompleter: (completerName, refreshInterval, initialQueryValue) ->
+  activateWithCompleter: (completerName, refreshInterval, initialQueryValue, selectFirstResult) ->
     completer = @getCompleter(completerName)
     @vomnibarUI = new VomnibarUI() unless @vomnibarUI
     completer.refresh()
+    @vomnibarUI.setInitialSelectionValue(if selectFirstResult then 0 else -1)
     @vomnibarUI.setCompleter(completer)
     @vomnibarUI.setRefreshInterval(refreshInterval)
     @vomnibarUI.show()
@@ -23,8 +24,8 @@

   activate: -> @activateWithCompleter("omni", 100)
   activateWithCurrentUrl: -> @activateWithCompleter("omni", 100, window.location.toString())
-  activateTabSelection: -> @activateWithCompleter("tabs", 0)
-  activateBookmarks: -> @activateWithCompleter("bookmarks", 0)
+  activateTabSelection: -> @activateWithCompleter("tabs", 0, null, true)
+  activateBookmarks: -> @activateWithCompleter("bookmarks", 0, null, true)
   getUI: -> @vomnibarUI

@@ -34,6 +35,9 @@
     @initDom()

   setQuery: (query) -> @input.value = query
+
+  setInitialSelectionValue: (initialSelectionValue) ->
+    @initialSelectionValue = initialSelectionValue

   setCompleter: (completer) ->
     @completer = completer
@@ -56,7 +60,7 @@
     @input.value = ""
     @updateTimer = null
     @completions = []
-    @selection = -1
+    @selection = @initialSelectionValue
     @update(true)

   updateSelection: ->
@@ -93,11 +97,11 @@
       @hide()
     else if (action == "up")
       @selection -= 1
-      @selection = @completions.length - 1 if @selection < -1
+      @selection = @completions.length - 1 if @selection < @initialSelectionValue
       @updateSelection()
     else if (action == "down")
       @selection += 1
-      @selection = -1 if @selection == @completions.length
+      @selection = @initialSelectionValue if @selection == @completions.length
       @updateSelection()
     else if (action == "enter")
       # If they type something and hit enter without selecting a completion from our list of suggestions,


connect domains to multiple vms

connect domains to multiple vms

--- client/landing/app/Applications/Environments.kdapplication/views/DomainMapperView.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/DomainMapperView.coffee
@@ -50,13 +50,25 @@
       defaultValue: switchStatus
       callback : (state) =>
         KD.remote.api.JDomain.bindVM
-          vmName    : @getData().name
-          domainName: listViewData.domainName
+          vmName       : @getData().name
+          domainName   : listViewData.domainName
+          shouldUpdate : if listViewData.hostnameAliases.length > 0 then yes else no
           state     : state
-        , (response) ->
-          new KDNotificationView
-            type : "top"
-            title: response
+        , (err, response) =>
+          if not err
+            if state is on and response.successful is yes
+              notificationMsg = "Your domain is connected to the #{@getData().name} VM."
+              listViewData.hostnameAliases.push response.hostnameAlias
+            if state is off and response.successful is yes
+              notificationMsg = "Your domain is disconnected from the #{@getData().name} VM."
+            new KDNotificationView
+                type  : "top"
+                title : notificationMsg
+          else
+            console.log err
+            new KDNotificationView
+              type  : "top"
+              title : "An error occured while performing your action. Please try again."

   viewAppended:->
     @setTemplate @pistachio()


Use parse in EvidenceCollection to add the correct model

--- core/app/backbone/collections/evidence_collection.coffee
+++ core/app/backbone/collections/evidence_collection.coffee
@@ -3,13 +3,17 @@
     # TODO: breaks with relevance > 1000
     -parseFloat(evidence.get('opinions')?.formatted_relevance || '0.0');

-  model: (attrs, options) ->
-    switch attrs.evidence_type
-      when 'FactRelation'
-        new FactRelation attrs, options
-      when 'Comment'
-        new Comment attrs, options
-      else `undefined`
+  parse: (data) ->
+    results = []
+    _.each data, (item) =>
+      switch item.evidence_type
+        when 'FactRelation'
+          results.push new FactRelation(item)
+        when 'Comment'
+          results.push new Comment(item)
+        else
+          console.info "Evidence type not supported: #{item.evidence_type}"
+    results

   initialize: (models, opts) ->
     @type = opts.type


added (workaround) load-on-scroll-to-visible-area (it would be good for KViews to fire an event once they enter the visible screen)

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeBin.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeBin.coffee
@@ -57,7 +57,7 @@
       cssClass:"clean-gray hidden"
       click:=>
         @codeBinResultView.hide()
-        # @codeBinResultView.stopResultFrame()
+        @codeBinResultView.stopResultFrame()
         @codeBinResultView.resetResultFrame()
         @codeBinResultButton.setTitle "Run Code Share"
         @resultBanner.show()
@@ -118,16 +118,17 @@

     @codeBinContainer.showPane @codeBinResultPane

-    setTimeout =>
-      @codeBinResultButton.setTitle "Reset Code Share"
-      @codeBinResultView.show()
-      @resultBanner.hide()
-      @codeBinCloseButton.show()
-      @codeBinResultView.emit "CodeBinSourceHasChanges", @getData()
-      # setTimeout =>
-      #   @codeBinResultView.stopResultFrame()
-      # , 10000
-    , 1000
+    # setTimeout =>
+    #   @codeBinResultButton.setTitle "Reset Code Share"
+    #   @codeBinResultView.show()
+    #   @resultBanner.hide()
+    #   @codeBinCloseButton.show()
+    #   @codeBinResultView.emit "CodeBinSourceHasChanges", @getData()
+    #   # setTimeout =>
+    #   #   @codeBinResultView.stopResultFrame()
+    #   # , 10000
+    # , 1000
+

   render:->
     super()
@@ -167,6 +168,23 @@
         maxHeight = view.getHeight()

     @$("pre.subview").css height:maxHeight
+
+    initiallyPausedObserver = setInterval =>
+      codeBinOffset =@$(".code-bin-source").offset().top
+      scrollViewTop = @parent.parent.parent.$().scrollTop()
+      scrollviewHeight = @parent.parent.parent.$().innerHeight()+scrollViewTop
+
+      if codeBinOffset+scrollViewTop < scrollviewHeight
+        if not @initiallyPaused
+          @initiallyPaused = true
+          @codeBinResultButton.setTitle "Reset Code Share"
+          @codeBinResultView.show()
+          @resultBanner.hide()
+          @codeBinCloseButton.show()
+          @codeBinResultView.emit "CodeBinSourceHasChanges", @getData()
+          clearInterval initiallyPausedObserver
+    ,500
+

   pistachio:->


Refactoring: cleanup.

Refactoring: cleanup.

--- app/assets/javascripts/voluntary_ranking/controllers/arguments/new_controller.js.coffee
+++ app/assets/javascripts/voluntary_ranking/controllers/arguments/new_controller.js.coffee
@@ -1,4 +1,4 @@
-Volontariat.ArgumentsNewController = Ember.ObjectController.extend(
+Volontariat.ArgumentsNewController = Ember.ObjectController.extend
   topicName: '', value: ''

   actions:
@@ -13,5 +13,4 @@
         @transitionToRoute('arguments.index', $('#thing_id').val(), 1)

     close: ->
-      @send "closeModal"
-)+      @send "closeModal"


Run through moving steps as shepherd and delegate remaining steps

--- ozaria/site/views/play/level/LevelDialogueView.coffee
+++ ozaria/site/views/play/level/LevelDialogueView.coffee
@@ -81,7 +81,7 @@
     if @doneAnimating
       @fitty = runFitty(@currentMessage.length)

-  onSpriteDialogue: (e) ->
+  setStationaryVegaText: (e) ->
     console.log('in LevelDialogueView.coffee:onSpriteDialogue with e: ', e)
     if e.message
       message = e.message.replace /<i class='(.+?)'><\/i>/, ""
@@ -112,7 +112,10 @@
             @beginDialogue(false)
         @fitty.element.addEventListener('fit', stopFitting)

-  # To make the text break in a pretty way, we need to force the white-space to normal
+  onSpriteDialogue: (e) ->
+    @beginDialogue(false)
+
+# To make the text break in a pretty way, we need to force the white-space to normal
   # because fitty wants it to expand to the maximum width. This needs to happen after
   # everything is done updating, and 50-100ms seems to work well. Setting it to 100ms
   # to give an extra little bit of time on lower end hardware.
@@ -158,38 +161,99 @@
         useModalOverlay: true
       })

-      Shepherd.on('complete', ->
-        $('#level-dialogue-view').css('display', 'unset')
+      @tutorial = [{
+        message: 'This is the intro message, welcome to Ozaria! :)'
+        targetElement: 'Intro / Center'
+      }, {
+        message: 'This is the goals section!'
+        targetElement: 'Goal List'
+        animation: 'Outline'
+      }, {
+        message: 'This is the code bank!'
+        targetElement: 'Code Bank'
+        animation: 'Outline'
+      }, {
+        message: 'This is a stationary messsage!'
+      }, {
+        message: 'This is another stationary messsage, and the last message!'
+      }]
+
+      previousButton = {
+        text: '<-'
+        action: ->
+          tour.previous()
+          # store.dispatch('tutorial/goToPreviousStep')
+      }
+      nextButton = {
+        text: '->'
+        action: ->
+          tour.next()
+          # store.dispatch('tutorial/goToNextStep')
+      }
+
+      console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+
+      @movingTutorialSteps = @tutorial.filter((s) -> s.targetElement).length
+      console.log('@movingTutorialSteps')
+      console.log(@movingTutorialSteps)
+      debugger
+
+      steps = @tutorial
+        .filter((s) -> s.targetElement)
+        .map((tutorialStep, index) ->
+          defaultButtons = []
+          if index == @movingTutorialSteps
+            defaultButtons.push(previousButton)
+          else if index == 0
+            defaultButtons.push(nextButton)
+          else
+            defaultButtons.push(previousButton)
+            defaultButtons.push(nextButton)
+
+          step = {
+            id: index
+            text: tutorialStep.message
+            buttons: defaultButtons
+          }
+
+          if tutorialStep.targetElement != 'Intro / Center'
+            step['attachOn'] = switch
+              when tutorialStep.targetElement == 'Run Button' then { element: '', on: 'top' }
+              when tutorialStep.targetElement == 'Next Button' then { element: '', on: 'top' }
+              when tutorialStep.targetElement == 'Play Button' then { element: '', on: 'top' }
+              when tutorialStep.targetElement == 'Update Button' then { element: '', on: 'top' }
+              when tutorialStep.targetElement == 'Goal List' then { element: '', on: 'left' }
+              when tutorialStep.targetElement == 'Code Bank button' then { element: '', on: 'right' }
+              when tutorialStep.targetElement == 'Code Editor Window' then { element: '', on: 'left' }
+
+          console.log('step: ')
+          console.log(step)
+          return step
+        )
+
+      console.log('tour: ')
+      console.log(tour)
+
+      tour.addSteps(steps)
+
+      @dialogueViewDisplayCss = $('#level-dialogue-view').css('display')
+      $('#level-dialogue-view').css('display', 'none')
+
+      Shepherd.on('complete', =>
+        $('#level-dialogue-view').css('display', @dialogueViewDisplayCss)
+        @setStationaryVegaText(@tutorial[@movingTutorialSteps])
       )

-      defaultButtons = [{
-        text: 'Next'
-        action: tour.next
-      }]
-
-      tour.addSteps([{
-        id: 'example-step'
-        text: 'This step is attached to the bottom of the .example-css-selector element.',
-        attachTo: {
-          element: '#goals-view'
-          on: 'bottom'
-        },
-        buttons: defaultButtons
-      }, {
-        id: 'example-step2'
-        text: 'This step is attached to the bottom of the .example-css-selector element. asdf'
-        attachTo: {
-          element: '#goals-view'
-          on: 'left'
-        }
-        buttons: defaultButtons
-      }])
-
-      $('#level-dialogue-view').css('display', 'none')
-      tour.on('show', ->
+      tour.on('show', =>
         # TODO: If the new current step is not a Moving Vega step, change the class, change the picture
         console.log('in shepherd tour show')
+
+        # TODO: Make it attach to each separate step - the step that is visible
         $('.shepherd-content').prepend($(''))
+      )
+
+      tour.on('end', =>
+        # TODO: Add remaining stationary steps to regular vega box
       )

       tour.start()


grouplogo : change group logo from group.customize

--- client/Main/maincontroller/mainviews/mainview.coffee
+++ client/Main/maincontroller/mainviews/mainview.coffee
@@ -71,16 +71,26 @@
     @header.addSubView @innerContainer = new KDCustomHTMLView
       cssClass  : "inner-container"

-    @innerContainer.addSubView @logo = new KDCustomHTMLView
-      tagName   : "a"
-      domId     : "koding-logo"
-      cssClass  : if entryPoint?.type is 'group' then 'group' else ''
-      partial   : ''
-      click     : (event)=>
-        KD.utils.stopDOMEvent event
-        if KD.isLoggedIn()
-        then KD.getSingleton('router').handleRoute "/Activity", {entryPoint}
-        else location.replace '/'
+    {groupsController} = KD.singletons
+    groupsController.ready =>
+      @logo = new KDCustomHTMLView
+        tagName   : "a"
+        domId     : "koding-logo"
+        cssClass  : if entryPoint?.type is 'group' then 'group' else ''
+        partial   : ''
+        click     : (event)=>
+          KD.utils.stopDOMEvent event
+          if KD.isLoggedIn()
+          then KD.getSingleton('router').handleRoute "/Activity", {entryPoint}
+          else location.replace '/'
+
+      group = groupsController.getCurrentGroup()
+      groupLogo = group.customize?.logo or ""
+      @logo.setCss 'background-image', "url(#{groupLogo})"
+
+      @innerContainer.addSubView @logo
+      @logo.setClass KD.config.environment
+

     @innerContainer.addSubView @logotype = new KDCustomHTMLView
       tagName   : "a"
@@ -90,7 +100,7 @@
         KD.utils.stopDOMEvent event
         KD.getSingleton('router').handleRoute "/", {entryPoint}

-    @logo.setClass KD.config.environment
+

     # REFACTOR NOTE: login link