Fix Remaining Specs

Fix Remaining Specs

--- spec/text-buffer-spec.coffee
+++ spec/text-buffer-spec.coffee
@@ -977,19 +977,16 @@

       describe "when the serialized buffer had unsaved changes", ->
         describe "when the disk contents were changed since serialization", ->
-          xit "loads the disk contents instead of the previous unsaved state", ->
+          it "loads the disk contents instead of the previous unsaved state", (done) ->
             buffer.setText("BUFFER CHANGE")
             fs.writeFileSync(filePath, "DISK CHANGE")

-            buffer2 = buffer.testSerialization()
-
-            waitsFor ->
-              buffer2.cachedDiskContents
-
-            runs ->
+            buffer2 = buffer.testSerialization({load: false})
+            buffer2.load().then ->
               expect(buffer2.getPath()).toBe(buffer.getPath())
               expect(buffer2.getText()).toBe("DISK CHANGE")
               expect(buffer2.isModified()).toBeFalsy()
+              done()

         describe "when the disk contents are the same since serialization", ->
           [previousText] = []
@@ -1240,7 +1237,7 @@
         done()

   describe "modified status", ->
-    [filePath] = []
+    [filePath, modifiedHandler, doneFunc] = []

     beforeEach (done) ->
       filePath = join(temp.dir, 'atom-tmp-file')
@@ -1251,129 +1248,118 @@

     afterEach ->
       buffer?.destroy()
-
-    xit "reports the modified status changing to true or false after the user changes buffer", ->
-      modifiedHandler = jasmine.createSpy("modifiedHandler")
-      buffer.onDidChangeModified modifiedHandler
-
-      expect(buffer.isModified()).toBeFalsy()
-      buffer.insert([0,0], "hi")
-      expect(buffer.isModified()).toBe true
-
-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
+      modifiedHandler = null
+      doneFunc = null
+
+    describe "after the user changes buffer", ->
+      beforeEach (done) ->
+        doneFunc = done
+        modifiedHandler = jasmine.createSpy("modifiedHandler").and.callFake ->
+          doneFunc()
+        buffer.onDidChangeModified modifiedHandler
+
+        expect(buffer.isModified()).toBeFalsy()
+        buffer.insert([0,0], "hi")
+        expect(buffer.isModified()).toBe true
+
+      beforeEach (done) ->
         expect(modifiedHandler).toHaveBeenCalledWith(true)

-        modifiedHandler.reset()
+        modifiedHandler.calls.reset()
         buffer.insert([0,2], "ho")
-
-      waits buffer.stoppedChangingDelay * 2
-
-      runs ->
-        expect(modifiedHandler).not.toHaveBeenCalled()
-
-        modifiedHandler.reset()
+        setTimeout(->
+          expect(modifiedHandler).not.toHaveBeenCalled()
+          done()
+        , buffer.stoppedChangingDelay * 2)
+
+      it "reports the modified status changing to true or false", (done) ->
+        modifiedHandler.calls.reset()
+        doneFunc = ->
+          expect(modifiedHandler).toHaveBeenCalledWith(false)
+          done()
         buffer.undo()
         buffer.undo()

-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
-        expect(modifiedHandler).toHaveBeenCalledWith(false)
-
-    xit "reports the modified status changing to false after a modified buffer is saved", ->
-      modifiedHandler = jasmine.createSpy("modifiedHandler")
-      buffer.onDidChangeModified modifiedHandler
-      buffer.insert([0,0], "hi")
-
-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
+    describe "after a modified buffer is saved", ->
+      beforeEach (done) ->
+        doneFunc = done
+        modifiedHandler = jasmine.createSpy("modifiedHandler").and.callFake ->
+          doneFunc()
+        buffer.onDidChangeModified modifiedHandler
+        buffer.insert([0,0], "hi")
+
+      it "reports the modified status changing to false", (done) ->
         expect(buffer.isModified()).toBe true

-        modifiedHandler.reset()
+        modifiedHandler.calls.reset()
         buffer.save()

         expect(modifiedHandler).toHaveBeenCalledWith(false)
         expect(buffer.isModified()).toBe false
-        modifiedHandler.reset()
-
+        modifiedHandler.calls.reset()
+        doneFunc = ->
+          expect(modifiedHandler).toHaveBeenCalledWith(true)
+          expect(buffer.isModified()).toBe true
+          done()
         buffer.insert([0, 0], 'x')

-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
-        expect(modifiedHandler).toHaveBeenCalledWith(true)
+    describe "after a modified buffer is reloaded", ->
+      beforeEach (done) ->
+        doneFunc = done
+        modifiedHandler = jasmine.createSpy("modifiedHandler").and.callFake ->
+          doneFunc()
+        buffer.onDidChangeModified modifiedHandler
+        buffer.insert([0,0], "hi")
+
+      it "reports the modified status changing to false after a modified buffer is reloaded", ->
         expect(buffer.isModified()).toBe true

-    xit "reports the modified status changing to false after a modified buffer is reloaded", ->
-      modifiedHandler = jasmine.createSpy("modifiedHandler")
-      buffer.onDidChangeModified modifiedHandler
-      buffer.insert([0,0], "hi")
-
-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
-        expect(buffer.isModified()).toBe true
-
-        modifiedHandler.reset()
+        modifiedHandler.calls.reset()
         buffer.reload()

         expect(modifiedHandler).toHaveBeenCalledWith(false)
         expect(buffer.isModified()).toBe false

-        modifiedHandler.reset()
+        modifiedHandler.calls.reset()
+        doneFunc = ->
+          expect(modifiedHandler).toHaveBeenCalledWith(true)
+          expect(buffer.isModified()).toBe true
+          done()
         buffer.insert([0, 0], 'x')

-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
-        expect(modifiedHandler).toHaveBeenCalledWith(true)
-        expect(buffer.isModified()).toBe true
-
-    xit "reports the modified status changing to false after a buffer to a non-existent file is saved", ->
-      buffer.destroy()
-      fs.removeSync(filePath)
-      expect(fs.existsSync(filePath)).toBeFalsy()
-
-      buffer = new TextBuffer({filePath, load: false})
-      modifiedHandler = jasmine.createSpy("modifiedHandler")
-      buffer.load().then ->
-        done()
-
-      runs ->
+    describe "after a buffer to a non-existent file is saved", ->
+      beforeEach (done) ->
+        buffer.destroy()
+        fs.removeSync(filePath)
+        expect(fs.existsSync(filePath)).toBeFalsy()
+
+        buffer = new TextBuffer({filePath, load: false})
+        buffer.load().then ->
+          done()
+
+      beforeEach (done) ->
+        doneFunc = done
+        modifiedHandler = jasmine.createSpy("modifiedHandler").and.callFake ->
+          doneFunc()
         buffer.onDidChangeModified modifiedHandler
         buffer.insert([0,0], "hi")

-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
+      it "reports the modified status changing to false", (done) ->
         expect(buffer.isModified()).toBe true

-        modifiedHandler.reset()
+        modifiedHandler.calls.reset()
         buffer.save()

         expect(fs.existsSync(filePath)).toBeTruthy()
         expect(modifiedHandler).toHaveBeenCalledWith(false)
         expect(buffer.isModified()).toBe false

-        modifiedHandler.reset()
+        modifiedHandler.calls.reset()
+        doneFunc = ->
+          expect(modifiedHandler).toHaveBeenCalledWith(true)
+          expect(buffer.isModified()).toBe true
+          done()
         buffer.insert([0, 0], 'x')
-
-      waitsFor ->
-        modifiedHandler.calls.count() is 1
-
-      runs ->
-        expect(modifiedHandler).toHaveBeenCalledWith(true)
-        expect(buffer.isModified()).toBe true

     it "returns false for an empty buffer with no path", ->
       buffer.destroy()
@@ -1770,33 +1756,39 @@

       expect(eventHandler).toHaveBeenCalledWith(filePath)

-    xit "stops listening to events on previous path and begins listening to events on new path", ->
-      changeHandler = null
-      originalPath = join(temp.dir, 'original.txt')
-      newPath = join(temp.dir, 'new.txt')
-      fs.writeFileSync(originalPath, "")
-
-      saveAsBuffer = new TextBuffer({filePath: originalPath, load: true})
-
-      waitsFor ->
-        saveAsBuffer.loaded
-
-      runs ->
-        changeHandler = jasmine.createSpy('changeHandler')
+    describe "when the path is changed", ->
+      [changeHandler, originalPath, newPath, saveAsBuffer, doneFunc] = []
+      beforeEach (done) ->
+        changeHandler = null
+        originalPath = join(temp.dir, 'original.txt')
+        newPath = join(temp.dir, 'new.txt')
+        fs.writeFileSync(originalPath, "")
+
+        saveAsBuffer = new TextBuffer({filePath: originalPath, load: false})
+        saveAsBuffer.load().then ->
+          done()
+
+      beforeEach (done) ->
+        doneFunc = ->
+          # No-op
+
+        changeHandler = jasmine.createSpy('changeHandler').and.callFake ->
+          doneFunc()
         saveAsBuffer.onDidChange changeHandler
         saveAsBuffer.saveAs(newPath)
         expect(changeHandler).not.toHaveBeenCalled()

         fs.writeFileSync(originalPath, "should not trigger buffer event")
-
-      waits 20
-
-      runs ->
-        expect(changeHandler).not.toHaveBeenCalled()
+        setTimeout(->
+          expect(changeHandler).not.toHaveBeenCalled()
+          done()
+        , 20)
+
+      it "stops listening to events on previous path and begins listening to events on new path", (done) ->
+        doneFunc = ->
+          expect(changeHandler).toHaveBeenCalled()
+          done()
         fs.writeFileSync(newPath, "should trigger buffer event")
-
-      waitsFor ->
-        changeHandler.calls.count() > 0

     describe "if the 'backup' option is true", ->
       [backupFilePath, saveAsBuffer] = []


Rename `Editor` attach and remove events in accordance w/ new scheme

'editor-open' -> 'editor:attached'
'before-remove' -> 'editor:will-be-removed'

--- src/wrap-guide.coffee
+++ src/wrap-guide.coffee
@@ -9,7 +9,7 @@
       if rootView.parents('html').length
         @appendToEditorPane(rootView, editor)

-    rootView.on 'editor-open', (e, editor) =>
+    rootView.on 'editor:attached', (e, editor) =>
       @appendToEditorPane(rootView, editor)

   @appendToEditorPane: (rootView, editor, config) ->


Add id

Add id

--- index.cjsx
+++ index.cjsx
@@ -230,7 +230,7 @@
     componentWillUnmount: ->
       window.removeEventListener 'game.response', @handleResponse
     render: ->
-

+

         <link rel="stylesheet" href={join(relative(ROOT, __dirname), 'assets', 'exp-calc.css')} />
         <Grid>
           <Col xs={shipRow}>


Add author

Add author

--- index.cjsx
+++ index.cjsx
@@ -21,6 +21,7 @@
   priority: 0.1
   displayName: [<FontAwesome key={0} name='compass' />, ' 未卜先知']
   description: '战况预知'
+  author: [Chiba]
   reactClass: React.createClass
     getInitialState: ->
       afterFriendHp: [0, 0, 0, 0, 0, 0]


fix hp object

fix hp object

--- index.cjsx
+++ index.cjsx
@@ -145,8 +145,8 @@

         when '/kcsapi/api_req_battle_midnight/battle'
           flag = true
-          nowFriendHp = afterFriendHp
-          nowEnemyHp = afterEnemyHp
+          nowFriendHp = Object.clone afterFriendHp
+          nowEnemyHp = Object.clone afterEnemyHp
           if body.api_hougeki?
             hougeki = body.api_hougeki
             for damageFrom, i in hougeki.api_at_list


fix pre ship information

fix pre ship information

--- index.cjsx
+++ index.cjsx
@@ -162,6 +162,8 @@
     continue if damage <= 0
     afterHp[i + 5] -= damage
   afterHp
+
+formationFlag = false

 module.exports =
   name: 'prophet'
@@ -185,14 +187,26 @@
     handleResponse: (e) ->
       {method, path, body, postBody} = e.detail
       {afterHp, nowHp, maxHp, damageHp, shipName, shipLv, enemyInfo, getShip, enemyFormation, enemyTyku} = @state
-      if path != '/kcsapi/api_req_sortie/battleresult'
-        enemyState = [0, 0]
+      if path == '/kcsapi/api_req_map/start' || formationFlag
+        @setState
+          enemyInformation: 0
+          enemyTyku: 0
+        formationFlag = false
       flag = false
       switch path
         when '/kcsapi/api_req_map/start'
           jsonId = null
           flag = true
-          shipLv[i] = -1 for i in [6..11]
+          shipLv[i] = -1 for i in [0..11]
+          _deck = window._decks[postBody.api_deck_id - 1]
+          {_ships} = window
+          for shipId, i in _deck.api_ship
+            continue if shipId == -1
+            shipName[i] = _ships[shipId].api_name
+            shipLv[i] = _ships[shipId].api_lv
+            maxHp[i] = _ships[shipId].api_maxhp
+            nowHp[i] = _ships[shipId].api_nowhp
+            afterHp[i] = _ships[shipId].api_nowhp
           for tmp, i in shipLv
             damageHp[i] = 0
           getShip = null
@@ -292,6 +306,7 @@
             afterHp = hougekiAttack afterHp, body.api_hougeki
           damageHp = getDamage damageHp, nowHp, afterHp, 1

+
         when '/kcsapi/api_req_battle_midnight/sp_midnight'
           for tmp, i in shipLv
             shipLv[i] = -1
@@ -352,6 +367,7 @@
           else
             enemyInfo = null
             getShip = null
+          formationFlag = true

       return unless flag
       @setState


fix bug

fix bug

--- index.cjsx
+++ index.cjsx
@@ -46,6 +46,7 @@
     continue if tmp == -1
     for t, j in $ships[tmp].api_maxeq
       continue if t == 0
+      continue if slot[i][j] == -1
       item = $slotitems[slot[i][j]]
       if item.api_type[3] in [6, 7, 8]
         totalTyku += Math.floor(Math.sqrt(t) * item.api_tyku)


Adding engine modules

Adding engine modules

--- src/engine.coffee
+++ src/engine.coffee
@@ -1,121 +1,63 @@
 ( ($) ->
   defaults =
     FPS: 33.3333
+    age: 0
     ambientLight: 1
     backgroundColor: "#FFFFFF"
     cameraTransform: Matrix.IDENTITY
+    excludedModules: []
+    includedModules: []
+    objects: []
+    paused: false

-  shadowCanvas = $("<canvas width=640 height=480 />").powerCanvas()
-  hudCanvas = $("<canvas width=640 height=480 />").powerCanvas()
-
-  hudCanvas.font("bold 9pt consolas, 'Courier New', 'andale mono', 'lucida console', monospace")
-
-  ###*
-  The engine holds a bunch of game objects and fires off cool events.
-
-  @name Engine
-  @constructor
-  ###
   window.Engine = (I) ->
     I ||= {}

     $.reverseMerge I, defaults

     intervalId = null
-    savedState = null
-    age = 0
-    paused = false

     queuedObjects = []
-    objects = []

     update = ->
-      objects = objects.select (object) ->
+      I.objects = I.objects.select (object) ->
         object.update()

-      objects = objects.concat(queuedObjects)
+      I.objects = I.objects.concat(queuedObjects)
       queuedObjects = []

       self.trigger "update"
-
-    drawDeveloperOverlay = (canvas) ->
-      #TODO: Move this into the debug draw method of the objects themselves
-      canvas.withTransform I.cameraTransform, (canvas) ->
-        objects.each (object) ->
-          canvas.fillColor 'rgba(255, 0, 0, 0.5)'
-          canvas.fillRect(object.bounds().x, object.bounds().y, object.bounds().width, object.bounds().height)
-
-      canvas.fillColor 'rgba(0, 0, 0, 0.5)'
-      canvas.fillRect(430, 10, 200, 60)
-      canvas.fillColor '#fff'
-      canvas.fillText("Developer Mode. Press Esc to resume", 440, 25)
-      canvas.fillText("Left click to add boxes", 440, 43)
-      canvas.fillText("Right click red boxes to edit properties", 440, 60)

     draw = ->
-      if I.ambientLight < 1
-        shadowContext = shadowCanvas.context()
-        shadowContext.globalCompositeOperation = "source-over"
-        shadowCanvas.clear()
-        # Fill with shadows
-        shadowCanvas.fill("rgba(0, 0, 0, #{1 - I.ambientLight})")
-
-        # Etch out the light
-        shadowContext.globalCompositeOperation = "destination-out"
-        shadowCanvas.withTransform I.cameraTransform, (shadowCanvas) ->
-          objects.each (object, i) ->
-            if object.illuminate
-              shadowContext.globalAlpha = 1
-              object.illuminate(shadowCanvas)
-
       canvas.withTransform I.cameraTransform, (canvas) ->
         if I.backgroundColor
           canvas.fill(I.backgroundColor)

-        objects.invoke("draw", canvas, hudCanvas)
-
-      if I.ambientLight < 1
-        shadows = shadowCanvas.element()
-        canvas.drawImage(shadows, 0, 0, shadows.width, shadows.height, 0, 0, shadows.width, shadows.height)
+        I.objects.invoke("draw", canvas)

-      hud = hudCanvas.element()
-      canvas.drawImage hud, 0, 0, hud.width, hud.height, 0, 0, hud.width, hud.height
-
-      drawDeveloperOverlay(canvas) if paused
+      self.trigger "draw", canvas

     step = ->
-      unless paused
+      unless I.paused
         update()
-        age += 1
+        I.age += 1

       draw()

     canvas = I.canvas || $("<canvas />").powerCanvas()
-
-    construct = (entityData) ->
-      if entityData.class
-        entityData.class.constantize()(entityData)
-      else
-        GameObject(entityData)

     self = Core(I).extend
       add: (entityData) ->
-        obj = construct entityData
+        obj = GameObject.construct entityData

-        if intervalId && !paused
+        if intervalId && !I.paused
           queuedObjects.push obj
         else
-          objects.push obj
-
-      construct: construct
-
-      #TODO: This is only used in testing and should be removed when possible
-      age: ->
-        age
-
+          I.objects.push obj
+
       #TODO: This is a bad idea in case access is attempted during update
       objects: ->
-        objects
+        I.objects

       objectAt: (x, y) ->
         targetObject = null
@@ -131,24 +73,24 @@
         return targetObject

       eachObject: (iterator) ->
-        objects.each iterator
+        I.objects.each iterator

       find: (selector) ->
         results = []

         matcher = EngineSelector.generate(selector)

-        objects.each (object) ->
+        I.objects.each (object) ->
           results.push object if matcher.match object

         $.extend results, EngineSelector.instanceMethods

       collides: (bounds, sourceObject) ->
-        objects.inject false, (collided, object) ->
+        I.objects.inject false, (collided, object) ->
           collided || (object.solid() && (object != sourceObject) && object.collides(bounds))

       rayCollides: (source, direction, sourceObject) ->
-        hits = objects.map (object) ->
+        hits = I.objects.map (object) ->
           hit = object.solid() && (object != sourceObject) && Collision.rayRectangle(source, direction, object.centeredBounds())
           hit.object = object if hit

@@ -163,22 +105,6 @@
             nearestHit = hit

         nearestHit
-
-      rewind: () ->
-
-
-      saveState: () ->
-        savedState = objects.map (object) ->
-          $.extend({}, object.I)
-
-      loadState: (newState) ->
-        if newState ||= savedState
-          objects = newState.map (objectData) ->
-            construct $.extend({}, objectData)
-
-      reload: () ->
-        objects = objects.map (object) ->
-          construct object.I

       start: () ->
         unless intervalId
@@ -191,13 +117,13 @@
         intervalId = null

       play: ->
-        paused = false
+        I.paused = false

       pause: ->
-        paused = true
+        I.paused = true

       paused: ->
-        paused
+        I.paused

       setFramerate: (newFPS) ->
         I.FPS = newFPS
@@ -208,6 +134,14 @@
     self.attrAccessor "backgroundColor"
     self.attrAccessor "cameraTransform"
     self.include Bindable
-
+
+    defaultModules = ["Shadows", "HUD", "Developer", "SaveState"]
+    modules = defaultModules.concat(I.includedModules)
+    modules = modules.without(I.excludedModules)
+
+    modules.each (moduleName) ->
+      self.include Engine[moduleName]
+
     return self
 )(jQuery)
+


moving clear out of camera transform

moving clear out of camera transform

--- src/engine.coffee
+++ src/engine.coffee
@@ -135,12 +135,12 @@
       self.trigger "afterUpdate"

     draw = ->
-      I.canvas.withTransform I.cameraTransform, (canvas) ->
-        if I.clear
-          canvas.clear()
-        else if I.backgroundColor
-          canvas.fill(I.backgroundColor)
-
+      if I.clear
+        I.canvas.clear()
+      else if I.backgroundColor
+        I.canvas.fill(I.backgroundColor)
+
+      I.canvas.withTransform I.cameraTransform, (canvas) ->
         self.trigger "beforeDraw", canvas

         if I.zSort


Tests: Trigger build.

Tests: Trigger build.

--- tests/src/activity/post.coffee
+++ tests/src/activity/post.coffee
@@ -20,6 +20,7 @@
     helpers.postComment(browser)

     browser.end()
+

   postMessageAndSeeIfItsPostedOnlyOnce: (browser) ->


Update.

Update.

--- nointro.coffee
+++ nointro.coffee
@@ -1,22 +1,20 @@
 url = require 'url'
 fs = require 'fs'
+path = require 'path'
 request = require 'request'
 unzip = require 'unzip'
 streamBuffers = require 'stream-buffers'

+date = '2015-03-03'
 module.exports.getROM = (rom) ->
-  date = '2015-03-03'
-  romURL = url.format
-    protocol: 'https'
-    hostname: 'archive.org'
-    pathname: [
-      'download'
-      "No-Intro-Collection_#{date}"
-      "#{rom.nointro_console}.zip"
-      "#{rom.nointro_console}%2F#{rom.nointro_name}.zip"
-    ].join '/'
   new Promise (resolve, reject) ->
-    request romURL
+    request url.format
+      protocol: 'https'
+      hostname: 'archive.org'
+      pathname: path.join 'download',
+        "No-Intro-Collection_#{date}",
+        "#{rom.nointro_console}.zip",
+        "#{rom.nointro_console}%2F#{rom.nointro_name}.zip"
     .pipe unzip.Parse()
     .on 'entry', (entry) ->
       if entry.type is 'File'
@@ -31,4 +29,4 @@

 module.exports.hasROM = (rom, cb) ->
   new Promise (resolve, reject) ->
-    resolve(true)
+    resolve true


adding more destructive methods

adding more destructive methods

--- test/point.coffee
+++ test/point.coffee
@@ -112,6 +112,13 @@

     ok Point(7, 6).equal(p1.floor())

+  test "#floor$", ->
+    p1 = Point(7.2, 6.9)
+
+    p1.floor$()
+
+    ok Point(7, 6).equal(p1)
+
   test "#equal", ->
     ok Point(7, 8).equal(Point(7, 8))


Fix YavaScript tests

Fix YavaScript tests


Linebreak plugin allows multiple rows of buttons

--- plugins/linebreak.coffee
+++ plugins/linebreak.coffee
@@ -1,15 +1,45 @@
 #     Hallo - a rich text editing jQuery UI widget
 #     (c) 2011 Henri Bergius, IKS Consortium
 #     Hallo may be freely distributed under the MIT license
+#
+# ============================================================
+#
+#   Hallo linebreak plugin
+#   (c) 2011 Liip AG, Switzerland
+#   This plugin may be freely distributed under the MIT license.
+#
+#   The linebreak plugin allows linebreaks between editor buttons by wrapping each row in a div.
+#   It requires that all widgets have an id consisting of the uuid and the name for the surrounding element
+#   ()
+#
+#   The only option is 'after', which should be an array of widgetnames, after which a linebreak should be inserted
+#
 ((jQuery) ->
     jQuery.widget "IKS.hallolinebreak",
         options:
             editable: null
             toolbar: null
             uuid: ""
+            after: [] # array of widgetnames after which a linebreak should occur

         _create: ->
-            @options.toolbar.append jQuery("
")
+            buttonsets = jQuery('.ui-buttonset', @options.toolbar)
+            queuedButtonsets = jQuery()
+            rowcounter = 0
+
+            for row in @options.after
+                rowcounter++
+                for buttonset in buttonsets
+                    queuedButtonsets = jQuery(queuedButtonsets).add(jQuery(buttonset))
+                    if buttonset.id == @options.uuid + '-' + row
+                        queuedButtonsets.wrapAll('
')
+                        buttonsets = buttonsets.not(queuedButtonsets)
+                        queuedButtonsets = jQuery()
+                        break
+
+            if buttonsets.length > 0
+                rowcounter++
+                buttonsets.wrapAll('
')

         _init: ->


Correct assertions for insert newline test

--- test/src/system/block_formatting_test.coffee
+++ test/src/system/block_formatting_test.coffee
@@ -337,13 +337,14 @@
               typeCharacters "\n\n\n", ->

                 document = getDocument()
-                assert.equal document.getBlockCount(), 3
-                done()
-
-                block = document.getBlockAtIndex(1)
+                assert.equal document.getBlockCount(), 2
+
+                block = document.getBlockAtIndex(0)
                 assert.deepEqual block.getAttributes(), []
                 assert.equal block.toString(), "\n\n\n"

-                block = document.getBlockAtIndex(2)
+                block = document.getBlockAtIndex(1)
                 assert.deepEqual block.getAttributes(), ["heading"]
                 assert.equal block.toString(), "abc\n"
+
+                done()


Update Model.find/fetch to accept an options object instead of a single callback

Callbacks:
- options.success(instance)
- options.error(res, xhr)

--- assets/javascripts/model.js.coffee
+++ assets/javascripts/model.js.coffee
@@ -6,19 +6,22 @@
   @_id_counter: 0
   @model_name: '_default'

-  @find: (params, callback) ->
+  @find: (params, options = {}) ->
     if params.id && (cid = @id_mapping[@model_name]?[params.id])
       params.cid = cid

     if params.cid
       instance = @instances.all[params.cid]
-      callback?(instance)
-      return instance
+      if !params.hasOwnProperty('entity') || instance.get('entity') == params.entity
+        options.success?(instance)
+        return instance
+      else
+        delete params.cid

     if params.id
-      @fetch(params, callback)
+      @fetch(params, options)

-  @fetch: (params, callback) ->
+  @fetch: (params, options) ->
     console.warn("You need to define #{@name}::fetch(params, callback)!")

   # delete reference


Added methods to initialize game

Added methods to initialize game

--- public/javascripts/game.puzzle.coffee
+++ public/javascripts/game.puzzle.coffee
@@ -1,40 +1,51 @@
-class puzzleGame
-  constructor: (@debug) ->
-  init: ->
-    if @debug
-      console.log('debug enabled')
+jQuery(document).ready ->

-jQuery(document).ready ->
-  $('#test').click ->
-    xsplit = 4
-    ysplit = 4
-    tiles = xsplit * ysplit
-    imgWidth = $('#defaultImg').width()
-    imgHeight = $('#defaultImg').height()
-    tileWidth = imgWidth/xsplit
-    tileHeight = imgHeight/ysplit
-    console.log(imgWidth, imgHeight, tileWidth, tileHeight)
-    i = 0
-    col = 0
-    while col < ysplit
-      row = 0
-      while row < xsplit
-        tile = $('#defaultImg').clone()
-        $(tile).draggable()
-        pos = $('#defaultImg').position()
-        $(tile).css {
+  class puzzleGame
+    constructor: (@debug, @xsplit, @ysplit, @answers) ->
+
+    init: (@resources) ->
+      primImg = $('#defaultImg')
+      $(primImg).css 'background-image', 'url(' + @resources[0]['High resolution image'] + ')'
+      tiles = @xsplit * @ysplit
+      imgWidth = primImg.width()
+      imgHeight = primImg.height()
+      tileWidth = imgWidth/@xsplit
+      tileHeight = imgHeight/@ysplit
+      i = 0
+      col = 0
+      while col < @ysplit
+        row = 0
+        while row < @xsplit
+          tile = $(primImg.clone())
+          tile.draggable()
+          tile.addClass 'tile'
+          tile.removeAttr 'id', ''
+          tile.css {
+            'background-image': primImg.css 'background-image'
             'background-position': -row*tileWidth+'px ' + -col*tileHeight+'px',
             'width': tileWidth,
             'height': tileHeight
           }
-        $('main').append(tile)
-        i++
-        row++
-        console.log('created', i, 'tile', i*tileWidth+'px ' + i*tileHeight+'px', row, col)
-      col++
-    $('#defaultImg').hide()
-    currentGame = new puzzleGame 'true'
-    currentGame.init()
+          tile
+          $('#gameArea').append(tile)
+          i++
+          row++
+          if @debug
+            console.log('created', i, 'tile at', row, col)
+        col++
+      primImg.hide()
+      if @debug
+        console.log('current selector', primImg, '--- Width', imgWidth, 'Height', imgHeight, 'TileWidth', tileWidth, 'TileHight',tileHeight)
+        console.log('solution', @resources[0])
+    reset: ->
+      console.log(@resources)
+      console.log('abstract reset method')
+  currentGame = new puzzleGame true, 4, 4, 8
     return
+
+  $('#reset').click ->
+    currentGame.reset()
+    return
+
   return


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/array_extensions.coffee
+++ src/array_extensions.coffee
@@ -8,7 +8,7 @@

 @name average
 @methodOf Array#
-@returns {Number} The average (arithmetic mean) of the l.
+@returns {Number} The average (arithmetic mean) of the list o.
 ###
 Array::average = ->
   @sum()/@length


Added additional and more in depth tests for _build_session(), including a complicated 'catch all' test. All tests currently pass.

--- test/suite.coffee
+++ test/suite.coffee
@@ -31,6 +31,22 @@
     it 'should return an empty list', ->
       suite._build_session().should.eql([])

+    describe 'With one of each pre/post runner', ->
+      before_a = before_each_a = after_a = after_each_a = null
+
+      before_each ->
+        before_a = new Runner()
+        before_each_a = new Runner()
+        after = new Runner()
+        after_each_a = new Runner()
+        suite.add_before before_a
+        suite.add_before_each before_each_a
+        suite.add_after after_a
+        suite.add_after_each after_each_a
+
+      it 'it should return an empty list', ->
+        suite._build_session().should.eql([])
+
     describe 'With tests', ->
       test_a = test_b = null

@@ -88,8 +104,117 @@
           result = suite._build_session()
           result.should.eql([test_a, after_each_a, test_b, after_each_a])

-    describe 'With suites', ->
-      # TODO: Add in depth suite in suite tests.
+      describe 'and a subsuite', ->
+        subsuite_a = null
+
+        before_each ->
+          subsuite_a = new Suite()
+          suite.add_suite subsuite_a
+
+        it 'it should return [test_a, test_b]', ->
+          result = suite._build_session()
+          result.should.eql([test_a, test_b])
+
+        describe ', now to the subsuite add a test', ->
+          subtest_a = null
+
+          before_each ->
+            subtest_a = new Test()
+            subsuite_a.add_test subtest_a
+
+          it 'it should return [test_a, test_b, subtest_a]', ->
+            result = suite._build_session()
+            result.should.eql([test_a, test_b, subtest_a])
+
+          describe 'and a before_each', ->
+            subbefore_each = null
+
+            before_each ->
+              subbefore_each = new Runner()
+              subsuite_a.add_before_each subbefore_each
+
+            it 'it should return [test_a, test_b, subbefore_each, subtest_a]', ->
+              result = suite._build_session()
+              result.should.eql([test_a, test_b, subbefore_each, subtest_a])
+
+            describe '. Now, add a before_each to the root suite', ->
+              before_each_a = null
+
+              before_each ->
+                before_each_a = new Runner()
+                suite.add_before_each before_each_a
+
+              it 'it should return [before_each_a, test_a, before_each_a, '+
+                  'test_b, before_each_a, subbefore_each, subtest_a]', ->
+                result = suite._build_session()
+                result.should.eql([before_each_a, test_a, before_each_a,
+                  test_b, before_each_a, subbefore_each, subtest_a])
+
+    describe 'With a complicated catch-all suite/test/runner example', ->
+      root_before = null
+      root_after_each = null
+      root_test = null
+      suba_suite = subb_suite = null
+      suba_before = suba_after = null
+      suba_before_each = null
+      suba_test_a = suba_test_b = null
+      subb_test = null
+
+      before_each ->
+        root_before = new Runner()
+        root_after_each = new Runner()
+        root_test = new Test()
+        suba_suite = new Suite()
+        subb_suite = new Suite()
+        suba_before = new Runner()
+        suba_before_each = new Runner()
+        suba_after = new Runner()
+        suba_test_a = new Test()
+        suba_test_b = new Test()
+        subb_test = new Test()
+
+        suite.add_before root_before
+        suite.add_after_each root_after_each
+        suite.add_test root_test
+        suite.add_suite suba_suite
+        suite.add_suite subb_suite
+        suba_suite.add_before suba_before
+        suba_suite.add_before_each suba_before_each
+        suba_suite.add_after suba_after
+        suba_suite.add_test suba_test_a
+        suba_suite.add_test suba_test_b
+        subb_suite.add_test subb_test
+
+      it 'should return the expected result.', ->
+        result = suite._build_session()
+
+        # This dict and loop will help us debug any issues that arrise.
+        names =
+          root_before: root_before
+          root_after_each: root_after_each
+          root_test: root_test
+          suba_suite: suba_suite
+          subb_suite: subb_suite
+          suba_before: suba_before
+          suba_before_each: suba_before_each
+          suba_after: suba_after
+          suba_test_a: suba_test_a
+          suba_test_b: suba_test_b
+          subb_test: subb_test
+
+        named_results = []
+        for r in result
+          match = 'unknown'
+          for name, val of names
+            if val is r
+              match = name
+          named_results.push match
+
+        named_results.should.eql([
+          'root_before', 'root_test', 'root_after_each',
+          'suba_before', 'suba_before_each', 'suba_test_a', 'root_after_each',
+          'suba_before_each', 'suba_test_b', 'root_after_each', 'suba_after',
+          'subb_test', 'root_after_each'])

   describe '#add_suite()', ->
     suite = null


Add a method to explicitely refresh subscription feature

--- services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee
+++ services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee
@@ -61,6 +61,9 @@
 		}, "$pull": {
 			invited_emails: email
 		}, callback
+
+	refreshSubscription: (user_id, callback=(err)->) ->
+		SubscriptionUpdater._setUsersMinimumFeatures user_id, callback

 	deleteSubscription: (subscription_id, callback = (error) ->) ->
 		SubscriptionLocator.getSubscription subscription_id, (err, subscription) ->


Key bindings; more tweaks and fixes.

Key bindings; more tweaks and fixes.

- There's no need to keep `@keyToCommandRegistry`; it's regenerated
  whenever it's needed.

--- background_scripts/commands.coffee
+++ background_scripts/commands.coffee
@@ -113,6 +113,7 @@
           currentMapping[key] = registryEntry
         keys = rest
     chrome.storage.local.set normalModeKeyStateMapping: keyMapping
+    @keyToCommandRegistry = {} # We don't need this any more, so free up the memory.

   # An ordered listing of all available commands, grouped by type. This is the order they will
   # be shown in the help page.


Update test0.coffee

Update test0.coffee

--- test/test0.coffee
+++ test/test0.coffee
@@ -8,7 +8,23 @@

 describe 'Array1', ->
+	beforeEach (done)->
+		console.log 'beforeEach'
+		done()
+
+	afterEach (done)->
+		console.log 'afterEach'
+		done()
+
 	describe '#indexOf()', ->
+		before (done)->
+			console.log 'before'
+			done()
+
+		after (done)->
+			console.log 'after'
+			done()
+
 		it 'should return -1 when the value is not present', (done)->
 			assert.equal(-1, [1,2,3].indexOf(5))
 			assert.equal(-1, [1,2,3].indexOf(0))


Simplified the mecha log implementations

--- src/common/mecha.log.coffee
+++ src/common/mecha.log.coffee
@@ -3,11 +3,11 @@

 #mechaDebug = true

-mecha.log = (if console? and console.log? then () -> console.log.apply console, arguments else () -> return)
-mecha.logDebug = (if mechaDebug? and mechaDebug and console? and console.log? then () -> console.log.apply console, arguments else () -> return)
-mecha.logInternalError = (if console? and console.error? then () -> console.error.apply console, arguments else () -> return)
-mecha.logApiError = (if console? and console.error? then () -> console.error.apply console, arguments else () -> return)
-mecha.logApiWarning = (if console? and console.warn? then () -> console.warn.apply console, arguments else () -> return)
+mecha.log = (if console? and console.log? then -> console.log arguments... else -> return)
+mecha.logDebug = (if mechaDebug? and mechaDebug and console? and console.log? then -> console.log arguments... else -> return)
+mecha.logInternalError = (if console? and console.error? then -> console.error arguments... else -> return)
+mecha.logApiError = (if console? and console.error? then -> console.error arguments... else -> return)
+mecha.logApiWarning = (if console? and console.warn? then -> console.warn arguments... else -> return)
 mecha.logException = (locationName, error) ->
   logArgs = ["Uncaught exception in `#{locationName}`:\n"]
   logArgs.push (if error.message? then "#{error.message}\n" else error)


Tested all browsers and left config stubbed out

--- config/karma/run.coffee
+++ config/karma/run.coffee
@@ -19,7 +19,7 @@
   port: 9876
   colors: true
   logLevel: 'INFO'
-  browsers: ['PhantomJS']
+  browsers: ['PhantomJS'] # ['Firefox', 'Chrome', 'Safari']

 TEST_GROUPS = require('../test_groups')


Don't return done

Don't return done

--- spec/Subgraph.coffee
+++ spec/Subgraph.coffee
@@ -16,7 +16,6 @@
   before (done) ->
     loader = new noflo.ComponentLoader root
     loader.listComponents done
-    done
   beforeEach (done) ->
     loader.load 'Graph', (err, instance) ->
       return done err if err


better environment detection (node or browser)

--- src/hinoki.coffee
+++ src/hinoki.coffee
@@ -59,6 +59,8 @@
       path,
       cacheTarget
     ).promise
+
+  hinoki.isNodejs = fsModule?.statSync? and fsModule?.readdirSync?

   # monomorphic
   hinoki.PromiseAndCacheTarget = (promise, cacheTarget) ->
@@ -410,7 +412,7 @@
   # of all `*.js` and `*.coffee` files in `filepath`.
   # if `filepath` is a directory recurse into every file and subdirectory.

-  if fs? and pathModule?
+  if hinoki.isNodejs
     # TODO better name
     hinoki.requireSource = (filepath) ->
       unless 'string' is typeof filepath
@@ -419,7 +421,7 @@

     # TODO call this something like fromExports
     hinoki.baseRequireSource = (filepath, object) ->
-      stat = fs.statSync(filepath)
+      stat = fsModule.statSync(filepath)
       if stat.isFile()
         extension = pathModule.extname(filepath)

@@ -443,7 +445,7 @@
           object[key].__file = filepath

       else if stat.isDirectory()
-        filenames = fs.readdirSync(filepath)
+        filenames = fsModule.readdirSync(filepath)
         filenames.forEach (filename) ->
           hinoki.baseRequireSource pathModule.join(filepath, filename), object

@@ -473,6 +475,8 @@
       return source

     if 'string' is typeof arg
+      unless hinoki.isNodejs
+        throw new Error 'string sources only work on Node.js because they need the filesystem module to be present'
       return hinoki.source hinoki.requireSource arg

     if 'object' is typeof arg


Get rid of need for _sockjs_onload

Get rid of need for _sockjs_onload

--- src/iframe.coffee
+++ src/iframe.coffee
@@ -12,11 +12,11 @@

   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+

-

Don't panic!


Refactor respond_{js,json,plain}

Refactor respond_{js,json,plain}

--- node-http-server.coffee
+++ node-http-server.coffee
@@ -6,13 +6,11 @@

 respond_js = (res, code, js) ->
-  res.writeHead code, {'Content-Type': 'application/javascript'}
-  res.end js
+  _respond_text res, code, 'application/javascript', js

 respond_json = (res, code, x) ->
-  res.writeHead code, {'Content-Type': 'application/json'}
-  res.end JSON.stringify x, null, 2
+  _respond_text res, code, 'application/json', JSON.stringify x, null, 2

 respond_not_found = (res) ->
@@ -50,8 +48,15 @@

 respond_plain = (res, code, text) ->
-  res.writeHead code, {'Content-Type': 'text/plain'}
-  res.end text
+  _respond_text res, code, 'text/plain', text
+
+
+_respond_text = (res, code, mime, text) ->
+  data = new Buffer text, 'utf8'
+  res.writeHead code, {
+    'Content-Type': mime
+  }
+  res.end data

 module.exports = {


SplitView: performance refactoring WIP

SplitView: performance refactoring WIP

--- src/components/split/splitview.coffee
+++ src/components/split/splitview.coffee
@@ -7,26 +7,29 @@

   constructor:(options = {},data)->

-    options.type      or= "vertical"    # "vertical" or "horizontal"
-    options.resizable  ?= yes           # yes or no
-    options.sizes     or= ["50%","50%"] # an Array of Strings such as ["50%","50%"] or ["500px","150px",null] and null for the available rest area
-    options.minimums  or= null          # an Array of Strings
-    options.maximums  or= null          # an Array of Strings
-    options.views     or= null          # an Array of KDViews
-    options.fixed     or= []            # an Array of Booleans
-    options.duration  or= 200           # a Number in miliseconds
-    options.separator or= null          # a KDView instance or null for default separator
+    options.type      or= "vertical"        # "vertical" or "horizontal"
+    options.resizable  ?= yes               # yes or no
+    options.sizes     or= ['50%','50%']     # an Array of Strings such as ["50%","50%"] or ["500px","150px",null] and null for the available rest area
+    options.minimums  or= [0,0]             # an Array of Strings
+    options.maximums  or= ['100%','100%']   # an Array of Strings
+    options.views     or= null              # an Array of KDViews
+    options.fixed     or= []                # an Array of Booleans
+    options.duration  or= 200               # a Number in miliseconds
+    options.separator or= null              # a KDView instance or null for default separator
     options.colored    ?= no
     options.animated   ?= yes           # a Boolean
     options.type        = options.type.toLowerCase()
+    options.cssClass    = KD.utils.curry "kdsplitview kdsplitview-#{options.type}", options.cssClass

     super options,data

-    @setClass "kdsplitview kdsplitview-#{@getOptions().type} #{@getOptions().cssClass}"
     @panels       = []
     @panelsBounds = []
     @resizers     = []
     @sizes        = []
+    @minimums     = []
+    @maximums     = []
+    @size         = 0

   viewAppended:->

@@ -47,19 +50,20 @@
   _createPanels:->

     panelCount = @getOptions().sizes.length
-    @panels = (@_createPanel i for i in [0...panelCount])
+    @panels    = [@_createPanel(0), @_createPanel(1)]

   _createPanel:(index)->

-    {type, fixed, minimums, maximums} = @getOptions()
+    log @sizes[index],"////////"
+    {type, fixed} = @getOptions()
     panel = new KDSplitViewPanel
       cssClass : "kdsplitview-panel panel-#{index}"
       index    : index
       type     : type
-      size     : @_sanitizeSize @sizes[index]
-      fixed    : yes                            if fixed[index]
-      minimum  : @_sanitizeSize minimums[index] if minimums
-      maximum  : @_sanitizeSize maximums[index] if maximums
+      size     : @sizes[index]
+      fixed    : !!fixed[index]
+      minimum  : @minimums[index]
+      maximum  : @maximums[index]

     panel.on "KDObjectWillBeDestroyed", => @_panelIsBeingDestroyed panel
     @emit "SplitPanelCreated", panel
@@ -97,9 +101,9 @@
     @sizes        = @sizes.slice(0,index).concat(@sizes.slice(index+1))
     @panelsBounds = @panelsBounds.slice(0,index).concat(@panelsBounds.slice(index+1))

-    o.minimums.splice index, 1
-    o.maximums.splice index, 1
-    o.views.splice    index, 1 if o.views[index]?
+    @minimums[index] = 0
+    @maximums[index] = @_getSize()
+    o.views[index]   = null  if o.views[index]?

   # CREATE RESIZERS

@@ -131,50 +135,55 @@

   # HELPERS
   _sanitizeSizes:->
+
     @_setMinsAndMaxs()
-    o             = @getOptions()
-    nullCount     = 0
-    totalOccupied = 0
-    splitSize     = @_getSize()
-
-    # newSizes = for size,i in (if @sizes.length > 0 then @sizes else o.sizes)
-    newSizes = for size,i in o.sizes
-      if size is null
-        nullCount++
-        null
-      else
-        panelSize = @_sanitizeSize size
-        @_getLegitPanelSize size,i
-        # check maxs and mins
-        totalOccupied += panelSize
-        panelSize
-
-    @sizes = for size in newSizes
-      if size is null
-        nullSize = (splitSize - totalOccupied) / nullCount
-        Math.round nullSize
-      else
-        Math.round size
-
-    return @sizes
-
-  _sanitizeSize:(size)->
-    if "number" is typeof size or /px$/.test(size)
-      parseInt size, 10
+    {sizes} = @getOptions()
+    ss      = @_getSize()
+    s       = []
+    s[0]    = @_getLegitPanelSize @_sanitizeSize(sizes[0]), 0
+    s[1]    = @_getLegitPanelSize @_sanitizeSize(sizes[1]), 1
+    st      = s[0] + s[1]
+
+    if st > ss
+      s[1] = ss - s[0]
+    else if st < ss
+      if sizes[0] and (not sizes[1] or sizes[1] is 'auto')
+        s[1] = ss - s[0]
+      else if sizes[1] and (not sizes[0] or sizes[0] is 'auto')
+        s[0] = ss - s[1]
+
+
+    @size  = ss
+    log s, sizes, '-----------'
+    @sizes = s
+
+
+  _sanitizeSize: (size) ->
+
+    size = if "number" is typeof size then size
+    else if /px$/.test size    then parseInt size, 10
     else if /%$/.test size
-      splitSize = @_getSize()
-      splitSize / 100 * parseInt size, 10
+    then @_getSize() / 100 * parseInt size, 10
+    else @_getSize() / 2
+    size

   _setMinsAndMaxs:->
-    @getOptions().minimums ?= []
-    @getOptions().maximums ?= []
-    panelAmount = @getOptions().sizes.length or 2
-    for i in [0...panelAmount]
-      @getOptions().minimums[i] = if @getOptions().minimums[i] then @_sanitizeSize @getOptions().minimums[i] else -1
-      @getOptions().maximums[i] = if @getOptions().maximums[i] then @_sanitizeSize @getOptions().maximums[i] else 99999
+
+    {minimums, maximums} = @getOptions()
+
+    @minimums[0] = @_sanitizeSize minimums[0]
+    @minimums[1] = @_sanitizeSize minimums[1]
+    @maximums[0] = @_sanitizeSize maximums[0]
+    @maximums[1] = @_sanitizeSize maximums[1]
+

   _getSize:->
-    if @getOptions().type is "vertical" then @getWidth() else @getHeight()
+
+    if @size then @size
+    else if @getOptions().type is "vertical"
+    then @getWidth()
+    else @getHeight()
+

   _setSize:(size)->
     if @getOptions().type is "vertical" then @setWidth size else @setHeight size
@@ -184,14 +193,14 @@
     $parent = @$().parent()
     if type is "vertical" then $parent.width() else $parent.height()

-  _getLegitPanelSize:(size,index)->
-    size =
-      if @getOptions().minimums[index] > size
-        @getOptions().minimums[index]
-      else if @getOptions().maximums[index] < size
-        @getOptions().maximums[index]
-      else
-        size
+
+  _getLegitPanelSize: (size, index) ->
+
+    min = @minimums[index] or 0
+    max = @maximums[index] or @_getSize()
+    log min, max, size, Math.min Math.max(min, size), max
+    return Math.min Math.max(min, size), max
+

   _resizePanels:->


Calculate progress and completion

Calculate progress and completion

--- src/components/student-dashboard.cjsx
+++ src/components/student-dashboard.cjsx
@@ -4,6 +4,7 @@
 {StudentDashboardStore, StudentDashboardActions} = require '../flux/student-dashboard'
 LoadableItem = require './loadable-item'
 moment = require 'moment'
+isStepComplete = (step) -> step.is_completed

 DUMMY_COURSE_DATA = {
   type: { tag: "physics", title: "Physics" }
@@ -86,7 +87,11 @@

   render: ->
     event=@props.event
-    <EventRow feedback="In Progress" event=event cssClass="reading">
+    feedback = switch
+      when _.all(event.steps,isStepComplete) then "Complete"
+      when _.any(event.steps,isStepComplete) then "In progress"
+      else "Not started"
+    <EventRow feedback={feedback} event=event cssClass="reading">
         {event.title} | reference view
     </EventRow>

@@ -97,7 +102,11 @@

   render: ->
     event=@props.event
-    <EventRow feedback="In Progress" event=event cssClass="homework">
+    feedback = if moment(event.due_at).isBefore() # Past due, show correct/incorrect
+      "#{_.all(event.steps, isStepComplete)}/#{event.steps.length} complete"
+    else
+      "?/? correct" # TODO: needs added to feed or an alternate calculation determined
+    <EventRow feedback={feedback} event=event cssClass="homework">
         {event.title} | view feedback | recover credit
     </EventRow>


tweak reading title input box

tweak reading title input box

--- src/components/task-plan/reading.cjsx
+++ src/components/task-plan/reading.cjsx
@@ -184,8 +184,14 @@
       <BS.Panel bsStyle="default" className="create-reading" footer={footer}>

{headerText}

-          Name
-          <input ref="title" id="reading-title" type="text" onChange={@setTitle} value={plan?.title}/>
+          Title
+          <input
+            ref="title"
+            id="reading-title"
+            type="text"
+            value={plan.title}
+            placeholder="Enter Title"
+            onChange={@setTitle} />

           Due Date


Handle doc title inference from filename a bit more gracefully.

--- src/DocImport.coffee
+++ src/DocImport.coffee
@@ -42,7 +42,7 @@
 docFromFile = (filename, lastModifiedTime, html) ->
   doc = docFromHtml html

-  doc.title = filename
+  doc.title ||= filename.replace(/\.[^\.]+$/, "") # Strip off file extension
   doc.lastModifiedTime = doc.creationTime = lastModifiedTime

   for chapter in doc.chapters


Updated RequestHandler spec to fake the sign method on the HttpRequest object.

--- test/unit/request_handler.spec.coffee
+++ test/unit/request_handler.spec.coffee
@@ -16,7 +16,10 @@

 MockService = AWS.util.inherit AWS.Service,
   constructor: (config) -> AWS.Service.call(this, config)
-  buildRequest: -> this.newHttpRequest()
+  buildRequest: ->
+    req = this.newHttpRequest()
+    req.sign = ->
+    req
   extractData: (httpResponse) ->
     return httpResponse.body
   extractError: (httpResponse) ->


Atom: Open new tabs at the end

Atom: Open new tabs at the end

--- config/atom_config.cson
+++ config/atom_config.cson
@@ -15,5 +15,7 @@
   "exception-reporting":
     userId: "0f9c4bca-c1e4-c885-1374-c2dd26290ade"
   "spell-check": {}
+  tabs:
+    addNewTabsAtEnd: true
   welcome:
     showOnStartup: false


Get rid of Atom config

Get rid of Atom config

--- config/atom_config.cson
+++ config/atom_config.cson
@@ -1,19 +0,0 @@
-"*":
-  core:
-    telemetryConsent: "limited"
-    themes: [
-      "one-light-ui"
-      "one-light-syntax"
-    ]
-  editor:
-    fontFamily: "Menlo"
-    fontSize: 15
-    invisibles: {}
-    softWrap: true
-  "exception-reporting":
-    userId: "0f9c4bca-c1e4-c885-1374-c2dd26290ade"
-  "spell-check": {}
-  tabs:
-    addNewTabsAtEnd: true
-  welcome:
-    showOnStartup: false


[PUBDEV-5102] Populate metalearner_fold_column list (#59)

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -203,7 +203,7 @@
   findFormField = (name) -> find _form, (field) -> field.name is name

   do ->
-    [ trainingFrameParameter, validationFrameParameter, responseColumnParameter, ignoredColumnsParameter, offsetColumnsParameter, weightsColumnParameter, foldColumnParameter, interactionsParameter] = map [ 'training_frame', 'validation_frame', 'response_column', 'ignored_columns', 'offset_column', 'weights_column', 'fold_column', 'interactions' ], findFormField
+    [ trainingFrameParameter, validationFrameParameter, responseColumnParameter, ignoredColumnsParameter, offsetColumnsParameter, weightsColumnParameter, foldColumnParameter, interactionsParameter, metalearnerFoldColumnParameter] = map [ 'training_frame', 'validation_frame', 'response_column', 'ignored_columns', 'offset_column', 'weights_column', 'fold_column', 'interactions' , 'metalearner_fold_column'], findFormField

     if trainingFrameParameter
       if responseColumnParameter or ignoredColumnsParameter
@@ -236,6 +236,9 @@

                 if interactionsParameter
                   interactionsParameter.values H2O.Util.columnLabelsFromFrame(frame)
+
+                if metalearnerFoldColumnParameter
+                  metalearnerFoldColumnParameter.values columnValues

           return


style

style

--- bokehjs/src/coffee/action/callback.coffee
+++ bokehjs/src/coffee/action/callback.coffee
@@ -8,7 +8,7 @@
     args = @get("args")
     names = _.keys(args)
     values = _.map(_.values(args), (k) => @resolve_ref(k))
-    func = new Function names..., "value", @get("body")
+    func = new Function(names..., "value", @get("body"))
     func(values..., value)

   defaults: ->


fix the error tyku

fix the error tyku

--- index.cjsx
+++ index.cjsx
@@ -48,9 +48,9 @@
       continue if t == 0
       item = $slotitems[slot[i][j]]
       if item.api_type[3] in [6, 7, 8]
-        totalTyku += Math.floor(Math.sqrt(item.api_tyku * t))
+        totalTyku += Math.floor(Math.sqrt(t) * item.api_tyku)
       else if item.api_type[3] == 10 && item.api_type[2] == 11
-        totalTyku += Math.floor(Math.sqrt(item.api_tyku * t))
+        totalTyku += Math.floor(Math.sqrt(t) * item.api_tyku)
   totalTyku

 updateJson = (jsonId, jsonContent) ->


Adding more endpoints to addresses

Adding more endpoints to addresses

--- src/features/address.coffee
+++ src/features/address.coffee
@@ -28,3 +28,12 @@
 				uri = 'addresses/fields'

 			return @m.Request uri, 'GET', null, callback, error
+
+		`// @if TARGET=='nodejs'
+		`
+		Update: (customer, id, data, callback, error) ->
+
+			return @m.Request 'customers/'+customer+'/addresses/'+id, 'PUT', data, callback, error
+
+		`// @endif
+		`


1. Added an id in constructor 2. Clear timeouts on stop() 3. Enhanced wildcard subscriptions

--- src/RedisPort.coffee
+++ src/RedisPort.coffee
@@ -1,9 +1,9 @@
+_                = require "underscore"
 assert           = require "assert"
 async            = require "async"
-{ EventEmitter } = require "events"
 path             = require "path"
 redis            = require "redis"
-_                = require "underscore"
+{ EventEmitter } = require "events"

 log = require "./log"

@@ -18,7 +18,7 @@
 	client:           null

 	# @property [Object] Interval collection the resets the expire flags
-	ephemerals:       {}
+	ephemerals:       null

 	# @property [Number] Milliseconds to expire
 	ephemeralExpire:  15000
@@ -39,10 +39,10 @@
 	subscriber:       null

 	# @property [Object] Subscription registry
-	subscriptions:    {}
+	subscriptions:    null

 	# @property [Object] Wildcard queries
-	wildcards:        {}
+	wildcards:        null

 	# Constructor
 	#
@@ -54,7 +54,7 @@
 	# @option project [String] Project name
 	# @option prefix [String] Main prefix
 	#
-	constructor: (options) ->
+	constructor: (options, @id) ->
 		{ @redisHost, @redisPort, @host, @env, @project } = options

 		assert @[attr], "`#{attr}` is required" for attr in [
@@ -65,6 +65,8 @@
 			"project"   # project name
 		]

+		@id or= Math.round Math.random() * 10000
+
 		@ephemeralExpire  = options.ephemeralExpire  or @ephemeralExpire
 		@ephemeralRefresh = options.ephemeralRefresh or @ephemeralRefresh
 		@prefix           = options.prefix           or @prefix
@@ -76,44 +78,65 @@
 	# @param [Function] Callback function
 	#
 	start: (cb) ->
-		log.debug "redis-port: Connecting to #{@redisHost}:#{@redisPort}"
+		log.debug "#{@id}: connecting to #{@redisHost}:#{@redisPort}"
+
+		@ephemerals    = {}
+		@subscriptions = {}
+		@wildcards     = {}

 		@subscriber = redis.createClient @redisPort, @redisHost, retry_max_delay: 10000

 		@subscriber.on "pmessage", (pattern, channel, key) =>
-			log.debug "pmessage", pattern, key
-			sub = @subscriptions[pattern]
-			return log.debug "No subscription for #{pattern}" unless sub
+			log.debug "#{@id}: pmessage", pattern, key

 			switch key
 				when "set"
-					@get sub.path, (error, service) =>
-						return log.error "redis-port: Get error #{error.message}" if error
-
-						sub.fn service
+					if pattern.length - 1 is pattern.indexOf "*"
+						wildcard    = @wildcards[pattern]
+						serviceRole = channel.replace "__keyspace@0__:", ""
+
+						@get serviceRole, (error, service) ->
+							return log.error "get error #{error.message}" if error
+
+							wildcard.fn service
+
+					else
+						sub = @subscriptions[pattern]
+						return log.debug "#{@id}: no subscription for #{pattern}" unless sub
+
+						@get sub.path, (error, service) =>
+							return log.error "get error #{error.message}" if error
+
+							sub.fn service
 				# when "expired"

 		@subscriber.on "error", (error) =>
-			log.warn "redis-port: Redis client error: #{error.message}"
+			log.warn "Redis client error: #{error.message}"
 			@emit "reconnect"

 		@client = redis.createClient @redisPort, @redisHost, retry_max_delay: 10000

 		@client.once "connect", (error) =>
-			log.debug "redis-port: Connected."
+			log.debug "#{@id}: Connected."
 			@emit "started"
 			cb?()

 		@client.on "error", (error) =>
-			log.warn "redis-port: Redis client error: #{error.message}"
+			log.warn "Redis client error: #{error.message}"
 			@emit "reconnect"

 	# Stop the client
 	#
 	stop: ->
-		@client.quit()
-		@subscriber.quit()
+		log.debug "#{@id}: stopping"
+
+		@client.end()
+		@subscriber.end()
+
+		clearTimeout timeout for p, timeout of @ephemerals
+
 		@emit "stopped"
+		log.debug "#{@id}: stopped"

 	# Persistantly set a key-value
 	#
@@ -124,7 +147,7 @@
 	pset: (p, data, cb) ->
 		p = @_cleanPath p
 		@client.set p, JSON.stringify(data), (error, result) ->
-			log.debug "set", p, result
+			log.debug "#{@id}: set", p, result
 			return cb error if error
 			cb()

@@ -146,8 +169,8 @@
 	get: (p, cb) ->
 		p = @_cleanPath p

-		@client.get p, (error, data) ->
-			log.debug "get", p
+		@client.get p, (error, data) =>
+			log.debug "#{@id}: get", p
 			return cb error if error
 			cb null, JSON.parse data

@@ -160,14 +183,14 @@
 		p = @_cleanPath p

 		@client.keys "#{p}*", (error, keys) =>
-			log.debug "keys", "#{p}*", keys
+			log.debug "#{@id}: del keys", "#{p}*", keys
 			return cb error if error

 			async.eachSeries keys, ((k, cb) =>
 				clearTimeout @ephemerals[k]

 				@client.del k, (error, result) =>
-					log.debug "del", k, result
+					log.debug "#{@id}: del", k, result
 					return cb error if error
 					cb()
 			), (error) =>
@@ -193,12 +216,12 @@
 		p = @_cleanPath p

 		@client.psetex p, @ephemeralExpire, JSON.stringify(data), (error, result) =>
-			log.debug "setex", p, @ephemeralExpire
+			log.debug "#{@id}: setex", p, @ephemeralExpire
 			return cb error if error

 			updateExpire = =>
 				@client.pexpire p, @ephemeralExpire, (error, result) =>
-					log.debug "expire", p, result, @ephemeralRefresh
+					log.debug "#{@id}: expire", p, result, @ephemeralRefresh
 					return log.error "Error setting expire on #{p}: #{error.message}" if error
 					@ephemerals[p] = setTimeout updateExpire, @ephemeralRefresh

@@ -224,9 +247,12 @@
 	#
 	list: (p, cb) ->
 		p = @_cleanPath p
+		p = p.replace "*", "" if p.length - 1 is p.indexOf "*"
+
+		log.debug "#{@id}: list", "#{p}*"

 		@client.keys "#{p}*", (error, keys) =>
-			log.debug "keys", "#{p}*", keys
+			log.debug "#{@id}: list keys", "#{p}*", keys
 			return cb error if error

 			ks = []
@@ -235,24 +261,14 @@

 			cb null, ks

-	checkWildcard: (role, cb) ->
-		wildcardKey = _.chain @wildcards
-			.keys()
-			.find (w) -> role.match new RegExp w
-			.value()
-
-		return cb() unless wildcardKey
-
-		@addSubscription role, @wildcards[wildcardKey].fn
-
-		cb()
-
 	# Register a service
 	#
 	# @param [String, Object] Role or object with role and port
 	# @param [Function] Callback function
 	#
 	register: (role, cb) ->
+		log.debug "#{@id}: register", role
+
 		if typeof role is 'object'
 			port = role.port
 			role = role.role
@@ -264,12 +280,7 @@
 				port = 10000 + Math.floor Math.random() * 55000

 			@set "services/#{role}", { host: @host, port: port, role: role }, (error, stat) =>
-				return cb error if error
-
-				@checkWildcard role, (error) =>
-					return cb error if error
-
-					cb null, port
+				cb error, port

 	# Free a service, simply deletes and emits a free event
 	#
@@ -286,49 +297,30 @@
 				return cb error if error
 				cb()

-	# Add a subscription on a role
+	# Set a watch function on a role
 	#
 	# @param [String] Role name
 	# @param [Function] Watch function, is executed when the role is set
 	#
-	addSubscription: (role, fn) =>
+	query: (role, fn) ->
+		log.debug "#{@id}: query", role
+
 		p = @_cleanPath "services/#{role}"

 		subscriptionKey = "__keyspace@0__:#{p}"
 		@subscriber.psubscribe subscriptionKey
-		log.debug "Subscribing to #{p}"
-
-		@subscriptions[subscriptionKey] = path: p, fn: fn, role: role
-
-		@get p, (error, service) =>
-			fn service if not error and service
-
-	# Set a watch function on a role
-	#
-	# @param [String] Role name
-	# @param [Function] Watch function, is executed when the role is set
-	#
-	query: (role, fn) ->
-		if role.length - 1 isnt role.indexOf "*"
-			# no wildcard
-			@addSubscription role, fn
+
+		if role.length - 1 is role.indexOf "*"
+			@wildcards[subscriptionKey] = path: p, fn: fn, role: role
+
+			@getServices role, (error, services) ->
+				fn service for service in services

 		else
-			# wildcard
-			wildcard = role.replace "*", ""
-
-			@getServices wildcard, (error, services) =>
-				for service in services
-					@addSubscription service.role, fn
-
-					role = role.replace "*", ""
-					unless @wildcards[role]
-						@wildcards[role] =
-							fn:    fn
-							roles: []
-
-					unless service.role in @wildcards[role].roles
-						@wildcards[role].roles.push service.role
+			@subscriptions[subscriptionKey] = path: p, fn: fn, role: role
+
+			@get p, (error, service) =>
+				fn service if service

 	# Get current known services
 	#
@@ -338,9 +330,14 @@
 	getServices: (wildcard, cb) ->
 		unless cb
 			cb       = wildcard
-			wildcard = ""
-
-		@list "#{@servicesPath}/#{wildcard}", (error, roles) =>
+			wildcard = null
+
+		queryPath  = @servicesPath
+		queryPath += "/#{wildcard}" if wildcard
+
+		log.debug "#{@id}: get services", wildcard, queryPath
+
+		@list queryPath, (error, roles) =>
 			return cb error if error

 			services = []
@@ -350,14 +347,15 @@
 					services.push s
 					cb()
 			), (error) =>
-				return cb error if error
-				cb null, services
+				cb error, services

 	# Get the current active ports
 	#
 	# @param [Function] Callback function
 	#
 	getPorts: (cb) ->
+		log.debug "#{@id}: get ports"
+
 		@getServices (error, services) =>
 			return cb error if error


Fix sound bug

Fix sound bug

--- src/js/sound/generations/g0/s1.coffee
+++ src/js/sound/generations/g0/s1.coffee
@@ -28,7 +28,7 @@
   build = (context, parameters) ->
     osc = context.createOscillator()
     osc.type = parameters.oscType
-    osc.frequency.value = parameters.ofcFreq
+    osc.frequency.value = parameters.oscFreq

     lfo = context.createOscillator()
     lfo.type = parameters.lfoType


DRYed up rotation logic

DRYed up rotation logic

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -354,6 +354,18 @@
           y = -@panelHeight + 1

     [x, y]
+
+
+  _getRotation: (anchor, angle) ->
+    switch anchor
+      when 'left'
+        [0, 1, 0, angle]
+      when 'right'
+        [0, 1, 0, -angle]
+      when 'top'
+        [1, 0, 0, angle]
+      when 'bottom'
+        [1, 0, 0, -angle]

   _setShader: (i, anchor, deg) ->
@@ -471,13 +483,9 @@
       else
         deg *= 2 unless i is 0

+      rotation = @_getRotation anchor, deg
       if options.fracture
-        rotation = [1, 1, 1, deg]
-      else
-        if anchor is 'left' or anchor is 'right'
-          rotation = [0, 1, 0, deg]
-        else
-          rotation = [1, 0, 0, -deg]
+        rotation = [1, 1, 1, rotation[3]]

       panel.style[css.transform] = @_transform @_getXy(i, anchor), rotation

@@ -538,13 +546,7 @@
     @lastAngle = angle = @_normalizeAngle angle
     angle /=  @_getPanelType anchor

-    if anchor is 'right' or anchor is 'bottom'
-      angle = -angle
-
-    if anchor is 'left' or anchor is 'right'
-      rotation = [0, 1, 0, angle]
-    else
-      rotation = [1, 0, 0, -angle]
+    rotation = @_getRotation anchor, angle

     for panel, i in @panels[anchor]
       panel.style[css.transform] = @_transform @_getXy(i, anchor), rotation
@@ -571,14 +573,7 @@
         , 0

     @lastAngle = angle = @_normalizeAngle angle
-
-    if anchor is 'right' or anchor is 'bottom'
-      angle = -angle
-
-    if anchor is 'left' or anchor is 'right'
-      rotation = [0, 1, 0, angle]
-    else
-      rotation = [1, 0, 0, -angle]
+    rotation = @_getRotation anchor, angle

     @panels[anchor][1].style[css.transform] = @_transform @_getXy(1, anchor), rotation


lib name as var for better minification

lib name as var for better minification

--- oridomi.coffee
+++ oridomi.coffee
@@ -8,6 +8,8 @@
 # Copyright 2014, MIT License

+libName = 'OriDomi'
+
 # This variable is set to true and negated later if the browser does
 # not support OriDomi.
 isSupported = true
@@ -17,7 +19,7 @@

 # Used for informing the developer which required feature the browser lacks.
 supportWarning = (prop) ->
-  console?.warn "OriDomi: Missing support for `#{ prop }`."
+  console?.warn "#{ libName }: Missing support for `#{ prop }`."
   isSupported = false

@@ -171,7 +173,7 @@

 # List of browser prefixes for testing CSS3 properties.
 prefixList = ['Webkit', 'Moz', 'ms']
-baseName   = 'oridomi'
+baseName   = libName.toLowerCase()
 # CSS classes used by style rules.
 elClasses  =
   active:       'active'
@@ -403,7 +405,7 @@
   # `1` indicates a forward cascade, `2` is backwards. It is disabled by default.
   ripple: 0
   # This CSS class is applied to OriDomi elements so they can be easily targeted later.
-  oriDomiClass: 'oridomi'
+  oriDomiClass: libName.toLowerCase()
   # This is a multiplier that determines the darkness of shading.
   # If you need subtler shading, set this to a value below 1.
   shadingIntensity: 1
@@ -443,7 +445,7 @@
     @el = document.querySelector @el if typeof @el is 'string'
     # Make sure element is valid.
     unless @el and @el.nodeType is 1
-      console?.warn 'OriDomi: First argument must be a DOM element'
+      console?.warn "#{ libName }: First argument must be a DOM element"
       return

     # Fill in passed options with defaults.
@@ -527,7 +529,7 @@
       else
         count = panelConfig.length
         unless 99 <= panelConfig.reduce((p, c) -> p + c) <= 100.1
-          throw new Error 'OriDomi: Panel percentages do not sum to 100'
+          throw new Error "#{ libName }: Panel percentages do not sum to 100"

       # Clone a new mask element and append it to a panel element prototype.
       mask = cloneEl maskProto, true, 'mask' + classSuffix
@@ -1331,7 +1333,7 @@
     methodName = options
     # Check if method exists and warn if it doesn't.
     unless typeof (method = OriDomi::[methodName]) is 'function'
-      console?.warn "OriDomi: No such method `#{ methodName }`"
+      console?.warn "#{ libName }: No such method `#{ methodName }`"
       return @

     for el in @


removed useless default properties

removed useless default properties

--- oridomi.coffee
+++ oridomi.coffee
@@ -245,12 +245,6 @@
     @panelWidth = @width / @vPanels
     @panelHeight = @height / @hPanels

-    # Set our current fold angle at `0` and `isFoldedUp` as `false`.
-    @lastAngle = 0
-    @isFoldedUp = false
-    # `isFrozen` records if the oriDomi effect is temporarily disabled for easier
-    # manipulation of the target's inner contents later.
-    @isFrozen = false
     # Set an array of anchor names.
     @_anchors = ['left', 'right', 'top', 'bottom']
     # oriDomi starts oriented with the left anchor.


update.

update.

--- src/main/public/nz/ai/SampleAI.coffee
+++ src/main/public/nz/ai/SampleAI.coffee
@@ -45,7 +45,7 @@
         setup: (param) ->
           # 移動射撃
           param.setShotCommand()
-          param.setMoveCommand()
+          param.setBackCommand(5)
           return true
       }
       {


Add record querying to FixtureAdapter.

Add record querying to FixtureAdapter.

--- app/scripts/store.coffee
+++ app/scripts/store.coffee
@@ -1 +1,8 @@
-Syrup.ApplicationAdapter = DS.FixtureAdapter
+Syrup.ApplicationAdapter = DS.FixtureAdapter.extend
+    queryFixtures: (records, query, type)->
+        console.log('in queryFixtures')
+        records.filter (record)->
+            for own key, value of query
+                if record[key] != value
+                    return false
+            return true


dead code

dead code

--- app/scripts/utils.coffee
+++ app/scripts/utils.coffee
@@ -1,10 +1,4 @@
 angular.module('vitalsigns')
-  .factory 'skipStateTransition', () ->
-    skip = false
-    (_)->
-      if _? then skip = _
-      return skip
-
   .factory 'Selection', ()->
     class Selection
       constructor: (initString, delim)->


register end checker too, to flush pending tags from the template mask

--- src/linker.coffee
+++ src/linker.coffee
@@ -67,9 +67,9 @@
 # this hooks on new instanziated templates and tries to
 # complete the structure with the given html design
 hook = (tpl) ->
-    tpl.xml.use (parent, tag, next) ->
+    # register checker for creating tags
+    tpl.register 'new', (parent, tag, next) ->
         elems = parent._elems
-
         # when this is a tag created from data structure
         return next(tag) unless elems?

@@ -78,7 +78,7 @@

             if typeof el is 'string' or typeof el is 'number'
                 elems.shift() # rm text
-                parent.text? el, append:on
+                parent.text?(el, append:on)
                 do repeat

             else if match tag, el
@@ -88,7 +88,29 @@

             else # create new tag
                 # create and insert the new tag from el and delay work
-                new_tag parent, el, repeat
+                new_tag(parent, el, repeat)
+        do repeat
+    # register checker for closing tags
+    tpl.register 'end', (tag, next) ->
+        elems = tag._elems
+        # when this is a tag created from data structure
+        return next(tag) unless elems?
+
+        repeat = ->
+            el = elems[0]
+
+            if typeof el is 'string' or typeof el is 'number'
+                elems.shift() # rm text
+                tag.text?(el, append:on)
+                do repeat
+
+            else unless el?
+                # list is empty
+                next(tag)
+
+            else # create new tag
+                # create and insert the new tag from el and delay work
+                new_tag(tag, el, repeat)
         do repeat

 ##


fixes

fixes

--- app/socket_server.coffee
+++ app/socket_server.coffee
@@ -1,6 +1,7 @@
 _ = require("underscore")
 dateFormat = require('dateformat')
 mongoose = require 'mongoose'
+f = require('util').format

 User = mongoose.model 'User'
 Hero = mongoose.model 'Hero'
@@ -31,38 +32,38 @@
         message.text = "Wrong /roll format"
         message.allow_send = false

-    return message
+    cb message

 player_event = (message, cb)->
     message.event_type = "event"
     message.text = message.text.slice(4)
-    return message
+    cb message

 master_event = (message, cb)->
     message.event_type = "master_event"
     message.text = message.text.slice(7)
-    return message
+    cb message

 master_as = (message, cb)->
     words = message.text.split ' '
-    message.username = "" + words[1] + ""
+    message.username = f "%s", words[1]
     message.text = words.slice(2).join " "
-    return message
+    cb message

 help = (message, is_master, cb)->
     message.event_type = "system_message"
-    message.text = "Command list:
"+
-        "
/me blah-blah — you do blah-blah as event
"+
-        "
/roll XdY+Z — you roll dice
"
+    message.text = "Command list:
"
+    message.text += "
/me blah-blah — you do blah-blah as event
"
+    message.text += "
/roll XdY+Z — you roll dice
"
     if is_master
         message.text += "
/event blah-blah — show blah-blah as global event
"
         message.text += "
/as Name blah-blah — say blah-blah as Name
"
         message.text += "
/kick Player — kick player from room
"
     message.text += "
"
     message.allow_send = false
-    return message
+    cb message

 show_stats = (message, player, cb)->
     message.allow_send = false
@@ -78,7 +79,7 @@
             message.text = "Wrong hero name"
         else
             message.event_type = "master_event"
-            message.text = player + " description:
" + hero[0].description
+            message.text = f "%s description:
%s", player, hero[0].description

         cb message

@@ -120,7 +121,8 @@
                                 send_message socket, msg
                     when 'as'
                         if data.is_master
-                            return send_message socket, master_as(message)
+                            master_as message, (msg)->
+                                send_message socket, msg
                     when 'help'
                         help message, data.is_master, (msg)->
                             send_message socket, msg
@@ -199,7 +201,7 @@
             socket.join(room.name)
             socket.join(hero.displayname)
             if data.is_master
-                data.displayname = ""+hero.displayname+''
+                data.displayname = f "%s", hero.displayname
             else
                 data.displayname = hero.displayname
             socket.broadcast.to(data.room.name).emit "new_player",
@@ -256,7 +258,7 @@
         message.text = "Wrong player to kick"
         message.allow_send = false
     message.out_of_history = true
-    return message
+    cb message

 on_get_history = (socket)->
     socket.get "data", (err, data)->


Improved array readability

Improved array readability

--- src/logger.coffee
+++ src/logger.coffee
@@ -11,7 +11,7 @@
 { stdout, stderr } = process

 # Constants
-[INFO,WARN,ERROR,VERBOSE] = TAGS = ["INFO", "WARN", "ERROR", "VERBS"]
+[ INFO, WARN, ERROR, VERBOSE ] = TAGS = [ "INFO", "WARN", "ERROR", "VERBS" ]
 LEFT_MARGIN = _.maxBy(TAGS, _.size).length + 1
 TAG_INDICATOR = ': '
 LEFT_PADSTRING_LONG_LINES = _.repeat(" ", LEFT_MARGIN + TAG_INDICATOR.length)


logging

logging

--- assets/js/student.coffee
+++ assets/js/student.coffee
@@ -23,10 +23,9 @@
         false

 dollarCharacterConsideredHarmful = () ->
-        $("#scratch").append $("
"+
+        $("#scratch").parent().append $("
"+
                                 "Sorry, but for security reasons the dollar character is not allowed"+
                                 "
")
-        $('.alert-error').show 'blind', 1000
         return

 $('#scratch').keyup ->


fix FuzzySet invocation and dangerous indentation in while loop leading to infinite looping

--- src/answer-checker.coffee
+++ src/answer-checker.coffee
@@ -11,8 +11,8 @@
 # this calls FuzzySet on every consecutive combination of words from the guess
 # by https://github.com/natgaertner
 module.exports = (guess, answer) ->
-  result = keymax(pseudoPowerSet(answer.split(' ')), (element) ->
-    match = FuzzySet.get(element)
+  result = keymax(pseudoPowerSet(guess.split(' ')), (element) ->
+    match = FuzzySet([answer]).get(element)
     if match == null
       0
     else
@@ -40,7 +40,7 @@
   set = []
   len = 1
   while len <= words.length
-        start = 0
+    start = 0
     while start <= words.length - len
       set.push words.slice(start, start + len).join(' ')
       start++


Account SSHKeys form data setting logic fixed

--- client/app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee
+++ client/app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee
@@ -42,36 +42,41 @@
     super options,data

 class AccountSshKeyForm extends KDFormView
+
+  constructor:->
+
+    super
+
+    @titleLabel = new KDLabelView
+      for      : "sshtitle"
+      title    : "Label"
+
+    @titleInput = new KDInputView
+      placeholder  : "Label your SSH key here..."
+      name         : "sshtitle"
+      label        : @titleLabel
+
+    @keyTextLabel = new KDLabelView
+      for      : "sshkey"
+      title    : "SSH Key"
+
+    @keyTextarea = new KDInputView
+      placeholder  : "Paste your SSH key here..."
+      type         : "textarea"
+      name         : "sshkey"
+      cssClass     : "light"
+      label        : @keyTextLabel
+
   viewAppended:->

     @addSubView formline1 = new KDCustomHTMLView
       tagName : "div"
       cssClass : "formline"

-    formline1.addSubView @titleLabel = new KDLabelView
-      for      : "sshtitle"
-      title    : "Label"
-
-    formline1.addSubView @titleInput = new KDInputView
-      placeholder  : "Label your SSH key here..."
-      name         : "sshtitle"
-      label        : @titleLabel
-
-    formline1.addSubView @keyTextLabel = new KDLabelView
-      for      : "sshkey"
-      title    : "SSH Key"
-
-    formline1.addSubView @keyTextarea = new KDInputView
-      placeholder  : "Paste your SSH key here..."
-      type         : "textarea"
-      name         : "sshkey"
-      cssClass     : "light"
-      label        : @keyTextLabel
-
-    {key, title} = @data
-
-    @titleInput.setValue  title if title
-    @keyTextarea.setValue key   if key
+    formline1.addSubView @titleLabel
+    formline1.addSubView @titleInput
+    formline1.addSubView @keyTextLabel
+    formline1.addSubView @keyTextarea

     @addSubView formline2 = new KDCustomHTMLView
       cssClass : "button-holder"
@@ -104,11 +109,17 @@
     @domElement = $ "

"

   viewAppended:->
+
     super
+
     @form = form = new AccountSshKeyForm
       delegate : this
       cssClass : "posrelative"
-    , @getData()
+
+    {title, key} = @getData()
+
+    form.titleInput.setValue  title if title
+    form.keyTextarea.setValue key   if key

     @info = info = new KDCustomHTMLView
       tagName  : "span"
@@ -138,11 +149,8 @@
     @swappable.swapViews()

   cancelItem:->
-    @getData().key = @form.keyTextarea.getValue()
-    if @getData().key
-      @swappable.swapViews()
-    else
-      @deleteItem()
+    {key} = @getData()
+    if key then @swappable.swapViews() else @deleteItem()

   deleteItem:->
     @getDelegate().emit "RemoveItem", @


update atom config

update atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,10 +1,56 @@
 "*":
   "atom-beautify":
     _analyticsUserId: "3ce0c612-67ef-4345-bc9f-54e528cb1895"
+    apex: {}
+    arduino: {}
+    c: {}
+    cfml: {}
+    coffeescript: {}
+    cpp: {}
+    cs: {}
+    css: {}
+    d: {}
+    ejs: {}
+    erb: {}
+    fortran: {}
+    general: {}
+    gherkin: {}
+    handlebars: {}
+    html: {}
+    jade: {}
+    java: {}
+    js: {}
     js_brace_style: "none"
     js_end_with_comma: true
     js_end_with_newline: true
     js_jslint_happy: true
+    json: {}
+    jsx: {}
+    latex: {}
+    less: {}
+    marko: {}
+    mustache: {}
+    objectivec: {}
+    pawn: {}
+    perl: {}
+    php: {}
+    python: {}
+    riot: {}
+    ruby: {}
+    rust: {}
+    sass: {}
+    scss: {}
+    spacebars: {}
+    sql: {}
+    svg: {}
+    swig: {}
+    tss: {}
+    twig: {}
+    typescript: {}
+    vala: {}
+    visualforce: {}
+    xml: {}
+    xtemplate: {}
   "autocomplete-plus": {}
   autosave:
     enabled: true


set seti ui and syntax for atom editor

set seti ui and syntax for atom editor

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -9,8 +9,11 @@
 'core':
   'audioBeep': false
   'disabledPackages': [
-    'background-tips'
     'exception-reporting'
     'metrics'
   ]
   'projectHome': '~/Projects'
+  'themes': [
+    'seti-ui'
+    'seti-syntax'
+  ]


Bump the config stuff

Bump the config stuff

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,35 +1,36 @@
-'global':
-  'editor':
-    'showIndentGuide': true
-    'fontFamily': 'Menlo'
-    'fontSize': 15
-    'invisibles': {}
-  'core':
-    'ignoredNames': [
-      '.bundle'
-      '.git'
-      'log'
-      'repositories'
-      'tmp'
-      'vendor'
+"*":
+  editor:
+    showIndentGuide: true
+    fontFamily: "Menlo"
+    invisibles: {}
+    fontSize: 15
+    softWrapAtPreferredLineLength: true
+  core:
+    ignoredNames: [
+      ".bundle"
+      ".git"
+      "log"
+      "repositories"
+      "tmp"
+      "vendor"
     ]
-    'themes': [
-      'unity-ui'
-      'glacier-syntax'
+    themes: [
+      "unity-ui"
+      "glacier-syntax"
     ]
-    'hideGitIgnoredFiles': true
-    'disabledPackages': [
-      'background-tips'
-      'exception-reporting'
-      'metrics'
+    hideGitIgnoredFiles: true
+    disabledPackages: [
+      "background-tips"
+      "exception-reporting"
+      "metrics"
     ]
-  'spell-check':
-    'grammars': [
-      'text.plain'
-      'source.gfm'
-      'text.git-commit'
+  "spell-check":
+    grammars: [
+      "text.plain"
+      "source.gfm"
+      "text.git-commit"
     ]
-  'welcome':
-    'showOnStartup': false
-  'release-notes':
-    'viewedVersion': '0.89.0'
+  welcome:
+    showOnStartup: false
+  "release-notes":
+    viewedVersion: "0.89.0"


Enable/disable from buttons on all input events (not just key events)

Fixes #1836

--- app/assets/javascripts/main.js.coffee
+++ app/assets/javascripts/main.js.coffee
@@ -14,7 +14,7 @@

   closest_submit.disable() if field.val() is ""

-  field.on "keyup", ->
+  field.on "input", ->
     if $(@).val() is ""
       closest_submit.disable()
     else


#14 받는쪽에서 created_at 정보 추출해서 제공하도록 수정

#14 받는쪽에서 created_at 정보 추출해서 제공하도록 수정

--- app/assets/javascripts/view.js.coffee
+++ app/assets/javascripts/view.js.coffee
@@ -692,6 +692,9 @@
         temp[++h] = mt.name
         temp[++h] = ' : '
         temp[++h] = mt.contents
+        temp[++h] = ''
+        temp[++h] = ''
+        temp[++h] = mt.created_at
         temp[++h] = '
'
         ) for mt in mts
         temp[++h] = '
'
@@ -755,6 +758,8 @@
     for $mt in $mt_list when Number($mt.attr("data-id")) < Number($self.attr("data-id"))
       str += '
'
       str += $mt.find('.fw-main').html()
+      str += ''
+      str += $mt.find('.time').text()
       str += '
'
     str += '
'
     # delete button 제거


fix coffee lint errors

fix coffee lint errors

--- app/assets/javascripts/welcome.coffee
+++ app/assets/javascripts/welcome.coffee
@@ -1,6 +1,6 @@
 # Place all the behaviors and hooks related to the matching controller here.
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://coffeescript.org/
-input = document.getElementById('form-input');
-options = {componentRestrictions:{country:'ie'}};
-autocomplete = new google.maps.places.Autocomplete(input,options);
+input = document.getElementById('form-input')
+options = {componentRestrictions:{country:'ie'}}
+autocomplete = new google.maps.places.Autocomplete(input,options)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/matrix.coffee
+++ src/matrix.coffee
@@ -272,7 +272,7 @@
   Returns a matrix that corresponds to a skew of skewX, skewY.
   @see Matrix#skew
   @param {Number} skewX The angle of skew in the x dimension.
-  @param {Number} skewY The amount to translate in the y dimension.
+  @param {Number} skewY The angle of  in the y dimension.
   @return {Matrix} A matrix transformation representing a translation by tx and ty.
   ###
   Matrix.skew = (skewX, skewY) ->


small fix for the wallet_set_transaction_fee in preferences

--- app/js/controllers/preferences.coffee
+++ app/js/controllers/preferences.coffee
@@ -90,7 +90,7 @@
         pf = $scope.model.transaction_fee
         calls = [
                 Wallet.set_setting('timeout', $scope.model.timeout),
-                WalletAPI.set_transaction_fee(pf),
+                WalletAPI.set_transaction_fee(Number(pf).toFixed(2)),
                 Wallet.set_setting('interface_locale', $scope.model.language_locale)
                 Wallet.set_setting('interface_theme', $scope.model.theme)
                 Wallet.set_setting('default_vote', $scope.voting.default_vote)


fix bug in extended context

fix bug in extended context

--- app/scripts/result_controllers.coffee
+++ app/scripts/result_controllers.coffee
@@ -99,8 +99,9 @@
                 id = (linkCorpusId or mainCorpusId)

                 [matchSentenceStart, matchSentenceEnd] = findMatchSentence hitContext
-                {matchStart, matchEnd} = hitContext.match
-
+                matchStart = hitContext.match.start
+                matchEnd = hitContext.match.end
+
                 for j in [0...hitContext.tokens.length]
                     wd = hitContext.tokens[j]
                     wd.position = j


Remove logic accidentally added in 771afa1

--- src/object.coffee
+++ src/object.coffee
@@ -136,7 +136,6 @@
     for key, i in properties
       property = properties[i] = @property(key)
       property.isBatchingChanges = true
-      properties.push(property)
     result = wrappedFunction.call(this)
     for property in properties
       property.isBatchingChanges = false


Preparee for BringCast on Windows 8.1

Preparee for BringCast on Windows 8.1

--- src/coffee/clients.coffee
+++ src/coffee/clients.coffee
@@ -220,6 +220,12 @@
   ]

   windows81: [
+    #{
+      #title: 'BringCast'
+      #scheme: 'bringcast:'
+      #icon: 'windows/bringcast@2x.png'
+	  #install: 'http://bringcast.com/'
+    #},
     {
       title: 'iTunes'
       scheme: 'itpc://'


Split remove and clear methods

Split remove and clear methods

--- cache.coffee
+++ cache.coffee
@@ -48,14 +48,16 @@
     @_addModel(model_store, model, now) for model in models
     return @

-  clear: (url, ids) ->
-    (@store_by_url[url] = {}; return @) unless models
+  remove: (url, ids) ->
     if model_store = @store_by_url[url]
-      if _.isArray(ids) # many
+      if _.isArray(ids) # manya
         delete model_store[id] for id in ids
       else # one
         delete model_store[id]
     return @
+
+  clear: (url, ids) ->
+    (@store_by_url[url] = {}; return @)

   _createModel: (model_store, data, model_type, now) ->
     if _.isObject(data)


CUI.util.isEqual: New method to check if objects are equal.

--- src/base/util.coffee
+++ src/base/util.coffee
@@ -495,6 +495,40 @@
 	@inArray: (value, array) ->
 		array.indexOf(value)

+	@isEqual: (x, y) ->
+		#// if both are function
+		if x instanceof Function
+			if y instanceof Function
+				return x.toString() == y.toString()
+			return false
+
+		if x == null or x == undefined or y == null or y == undefined
+			return x == y
+
+		if x == y or x.valueOf() == y.valueOf()
+			return true
+
+		# if one of them is date, they must had equal valueOf
+		if x instanceof Date
+			return false
+
+		if y instanceof Date
+			return false
+
+		# if they are not function or strictly equal, they both need to be Objects
+		if not (x instanceof Object)
+			return false
+
+		if not (y instanceof Object)
+			return false
+
+		p = Object.keys(x)
+		if Object.keys(y).every( (i) -> return p.indexOf(i) != -1 )
+			return p.every((i) => return @isEqual(x[i], y[i]))
+		else
+			return false
+
+
 	@isMap: (v) ->
 		@isPlainObject(v)


team-grid: playing with the pattern

team-grid: playing with the pattern


set SYNCED_ALL note to modified when modified

--- app/assets/javascripts/app.coffee
+++ app/assets/javascripts/app.coffee
@@ -146,6 +146,13 @@
     vm.set_md(vm.ace_editor.getValue())
     # TODO optimize performance
     enmlRenderer.render_html($('#md_html_div'), vm.get_md()).catch (error) => alert('render error: ' + error)
+    # change note status to MODIFIED if original status is SYNCED_ALL
+    p = noteManager.find_note_by_guid(vm.get_guid()).then (note) =>
+      if note? && note.status == noteManager.NOTE_STATUS.SYNCED_ALL
+        return noteManager.update_note({guid: note.guid, status: noteManager.NOTE_STATUS.MODIFIED})
+    p.then(
+      console.log('current note status set to MODIFIED')
+    ).catch (error) => alert('set current note status to MODIFIED failed')

   # ------------------------------------------------------------------------------------------------------------------
   # Operations for notes


folder path method

folder path method

--- app/assets/javascripts/models/folder.js.coffee
+++ app/assets/javascripts/models/folder.js.coffee
@@ -23,6 +23,18 @@
     count
   ).property() # 'children.@each','files.@each'

+  folderPath: (->
+    full_name = [@get('title')]
+    parent_ref = @.get('parents.0')
+    while parent_ref and not parent_ref?.isRoot
+      parent = FM.Folder.find(parent_ref.id)
+      full_name.unshift(parent.get('title'))
+      parent_ref = parent.get('parents.0')
+
+    full_name.unshift(FM.Folder.find('root').get('title'))
+    full_name
+  ).property('parents')
+

   flatFiles: (->
     parents = []; list = []


Fix api.call_move()

Fix api.call_move()

--- assets/coffee/api.coffee
+++ assets/coffee/api.coffee
@@ -92,11 +92,11 @@
 # data.y (int) - конечная позиция брони в ячейке по y
 # use: api.move = function(data){ console.log(data) }
 api.move = () ->
-	api.move(data.id, level_index())
+	api.call_move(data.id, level_index())

 # Вызов callback
 api.call_move = (id, y) ->
-	console.log 'Demo: {ID:', id, ', Y:' y, '}'
+	console.log 'Demo: {ID', id, ', Y:' y, '}'

 # Создать таблицу по запросу


Contain task help content

Contain task help content

--- app/classifier/tasks/generic.cjsx
+++ app/classifier/tasks/generic.cjsx
@@ -36,4 +36,6 @@
     </div>

   showHelp: ->
-    alert <Markdown className="classification-task-help">{@props.help}</Markdown>
+    alert <div className="content-container">
+      <Markdown className="classification-task-help">{@props.help}</Markdown>
+    </div>


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -13,4 +13,4 @@
     bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height

     self.clamp "x",
-      min: bounds+      min: bounds.x


fix setDirectionSilent

fix setDirectionSilent

--- app/assets/javascripts/oxalis/model/flycam3d.coffee
+++ app/assets/javascripts/oxalis/model/flycam3d.coffee
@@ -280,7 +280,7 @@

   setDirection : (d) ->

-    setDirectionSilent(d)
+    @setDirectionSilent(d)
     updateMacro(@)


fixed crystal update imports

fixed crystal update imports

--- src/crystal/update.coffee
+++ src/crystal/update.coffee
@@ -37,7 +37,10 @@
 		config = this.config()

 		# get modules
-		modules = config.modules
+		if config.imports
+			modules = config.imports
+		else
+			modules = config.modules

 	if !modules
 		return


minor fix

minor fix

--- app/assets/javascripts/views/welcome/home.js.coffee
+++ app/assets/javascripts/views/welcome/home.js.coffee
@@ -5,33 +5,39 @@
   initialize: ->
     @setElement($('#body'))
     @moveBike()
+    @setMovieSize()
+    that = @
+    $( window ).resize ->
+      that.setMovieSize()
+
+  setMovieSize: ->
     height = $(window).width()*.66
     if height > $(window).height()
       height = $(window).height()
-    $('#movie-cover .cover-container').css('min-height', height)
-    $('#movie-cover .cover-container').css('max-height', height)
+    $('#movie-cover .cover-container')
+      .css('min-height', height)
+      .css('max-height', height)

   movieShowtime: (event) ->
     event.preventDefault()
     $('#movie-cover').addClass('showing-movie')
+    height = "100%"
+    height = $(window).height() if $(window).width() < 768
+    video = """"""
     setTimeout ( ->
       $('#iframe-holder')
         .addClass('showing-movie')
-        # $('#movie-wrap .movie-container').css('min-height',$(window).height()*.9 )
-        .append('')
+        .append(video)
     ) , 1000

   moveBike: ->
     register = $('#treating-right .treating-right-text')
     wheight = $(window).height()
-
-
     $(window).scroll ->
       best = $('#best-ever').offset().top
       scroll = $(window).scrollTop()
-      p = (scroll/best)
-      if p < .05
+      if (scroll/best) < .05
         $('#wheel-spin').removeClass('wheelspun')
       else
         unless $('#wheel-spin').hasClass('wheelspun')


hide initial tutorial when user logs in

hide initial tutorial when user logs in

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -217,6 +217,9 @@
   onUserChange: (e, user) =>
     # console.log 'classify: onUserChange()'
     if User.current? # user logged in
+
+      # hide tutorial
+      @initialTutorial.end()

       # first visit, initialize preference
       unless User.current.preferences?.planet_hunter?.count?


fixed typo

fixed typo

--- test/main.spec.coffee
+++ test/main.spec.coffee
@@ -66,7 +66,7 @@
     code.indexOf("\n").should.be.equal(-1)
     done()

-  it "show emebmed code reuls", (done) ->
+  it ", resultDisplay function - show emebmed code result", (done) ->
     compressed = trm.compress()
     result = trm.resultDisplay({code: compressed.code, pid: "-999", aid: "-9999"})
     console.log result


Fix file remove/load issue

Fix file remove/load issue

--- src/coffeepad.coffee
+++ src/coffeepad.coffee
@@ -129,6 +129,7 @@
   attachListeners:->

     @fileListView.on 'removeItem', (item)=>
+      @coffeeEditor.fileName = null
       @storage.unsetKey item.data.name
       @updateFileList()

@@ -162,16 +163,16 @@

     @storage.getValue "lastFile", (file)=>

-      if not file or not @storage.data[file]?
-        file = @createNewFile()
-
-      @coffeeEditor.openFile file
+      @coffeeEditor.openFile file  if file?
+
+      @fileList.on 'ItemSelectionPerformed', (..., {items})=>
+
+        if @coffeeEditor.fileName?
+          @coffeeEditor.handleSave yes
+
+        @coffeeEditor.openFile items.first.data.name
+
       @updateFileList file
-
-      @fileList.on 'ItemSelectionPerformed', (..., {items})=>
-        @coffeeEditor.handleSave yes
-        @coffeeEditor.openFile items.first.data.name
-

   toggleHelpMode:->

@@ -219,18 +220,19 @@

   updateFileList:(newname)->

+    @loadExamples()
     prevFile = newname ? @fileList.first?.data?.name
+
     @storage.filter /file\-/, (files)=>
+
       @fileList.replaceAllItems files
-
-      if files.length is 0
-        @coffeeEditor.openFile file = @createNewFile()
-        return @updateFileList file

       if prevFile
         for item in @fileList.itemsOrdered
           if item.data.name is prevFile
             @fileList.selectItem item
+      else
+        @fileList.selectItem @fileList.itemsOrdered.last

   runJsCode:->


collision

collision

--- src/collision.coffee
+++ src/collision.coffee
@@ -36,7 +36,6 @@
   @param b The second rectangle

   @returns {Boolean} true if the rectangles overlap, false otherwise
-  @type Boolean
   ###
   rectangular: (a, b) ->
     a.x < b.x + b.width &&
@@ -78,7 +77,6 @@
   @param b

   @returns {Boolean} true is the circles overlap, false otherwise
-  @type Boolean
   ###
   circular: (a, b) ->
     r = a.radius + b.radius
@@ -98,7 +96,6 @@
   @param target

   @returns {Boolean} true if the line intersects the circle, false otherwise
-  @type Boolean
   ###
   rayCircle: (source, direction, target) ->
     radius = target.radius()
@@ -136,7 +133,6 @@
   @param target

   @returns {Boolean} true if the line intersects the rectangle, false otherwise
-  @type Boolean
   ###
   rayRectangle: (source, direction, target) ->
     xw = target.xw


stays on the same tab when another account selected

--- app/js/controllers/toolbar.coffee
+++ app/js/controllers/toolbar.coffee
@@ -14,7 +14,7 @@
     , (all_accounts) ->
         return unless all_accounts
         $scope.accounts.splice(0, $scope.accounts.length)
-        $scope.accounts.push(name) for name, a of all_accounts when a.is_my_account and name != $scope.current_account
+        $scope.accounts.push(name) for name, a of all_accounts when a.is_my_account #and name != $scope.current_account
     , true

     $scope.back = ->
@@ -48,6 +48,8 @@
             params = angular.copy($state.params)
             params.account = account
             $state.go($state.current.name, params)
+        else if $state.current.name.startsWith("account.")
+            $state.go($state.current.name, {name: account})
         else
             $state.go("account.transactions", {name: account})
         return null


Fix: キャッシュを削除する前に終了することがあるのを修正

Fix: キャッシュを削除する前に終了することがあるのを修正

--- src/core/core.coffee
+++ src/core/core.coffee
@@ -49,8 +49,9 @@

 app.on("window-all-closed", ->
   # キャッシュ削除
-  session.defaultSession.clearCache(->)
-  # アプリ終了
-  app.quit()
+  session.defaultSession.clearCache( ->
+    # アプリ終了
+    app.quit()
+  )
   return
 )


Update Node constructor

Update Node constructor

--- src/core/node.coffee
+++ src/core/node.coffee
@@ -5,8 +5,8 @@

 class Node extends Element

-  constructor: (@attrs={}, args={}) ->
-    @setKey @args
+  constructor: (@attrs={}, @sphere) ->
+    @setKey()

   id: -> @attrs.id or @_id


refactor

refactor

--- src/core/node.coffee
+++ src/core/node.coffee
@@ -10,7 +10,7 @@

   id: -> @attrs.id or @_id

-  name: -> @attrs.name
+  name: -> @get 'name'

   get: (propertyName) -> _.get @attrs, propertyName