Updated basic.coffee to use expect syntax

--- test/basic.coffee
+++ test/basic.coffee
@@ -3,26 +3,28 @@
 expect      = chai.expect

 lies        = require '../src/beautiful-lies'
-createLiar = lies.createLiar

-describe 'createLiar', ->
+lies.init()
+
+describe 'expect (basic cases)', ->
+  liar = null
+
+  beforeEach ->
+    liar = {}

   it 'Should simulate a function call', ->
-
-    liar = createLiar [
+    liar.expect
       function_name: 'someFunction'
       returns:
         value:
           someProperty: 5
-    ]

     liar.someFunction().should.deep.equal
       someProperty: 5

   describe 'When returns.self is true', ->
-    liar = null
     beforeEach ->
-      liar = createLiar
+      liar.expect
         function_name: 'superFunction'
         returns:
           self: true
@@ -31,9 +33,8 @@
       liar.superFunction().should.equal liar

   describe 'When returns.self is false', ->
-    liar = null
     beforeEach ->
-      liar = createLiar
+      liar.expect
         function_name: 'superFunction'
         returns:
           self: false
@@ -43,26 +44,13 @@
       liar.superFunction().should.equal "Superman!"

-  it 'should treat a single object the same was as an array of one', ->
-
-    liar = createLiar # Look ma, no array!
-      function_name: 'someFunction'
-      returns:
-        value:
-          someProperty: 5
-
-    liar.someFunction().should.deep.equal
-      someProperty: 5
-
-
   describe 'arguments provided', ->
-
-    liar = createLiar [
-        function_name: 'funkyFunction'
-        arguments: [ 'apples' ]
-        returns:
-          value: 98
-    ]
+    beforeEach ->
+      liar.expect
+          function_name: 'funkyFunction'
+          arguments: [ 'apples' ]
+          returns:
+            value: 98

     it 'Should not work with wrong arguments', ->

@@ -80,19 +68,19 @@
         .should.equal 98

   describe 'Multiple lies', ->
+    beforeEach ->
+      liar.expect [
+        {
+          function_name: 'authorize'
+          returns:
+            value: 98
+        },{
+          function_name: 'charge'
+          returns:
+            value: 'OK'

-    liar = createLiar [
-      {
-        function_name: 'authorize'
-        returns:
-          value: 98
-      },{
-        function_name: 'charge'
-        returns:
-          value: 'OK'
-
-      }
-    ]
+        }
+      ]

     it 'should return stuff', ->
       liar.authorize().should.equal 98
@@ -100,17 +88,16 @@

   describe 'Expectations should be nestable', ->
+    beforeEach ->
+      liar.expect
+        function_name: 'connect'
+        returns:
+          value: { status: 'open' }
+          on_value:
+            function_name: 'query'
+            returns:
+              value: '5 little pigs'

-    liar = createLiar [
-      function_name: 'connect'
-      returns:
-        value: { status: 'open' }
-        on_value: [
-          function_name: 'query'
-          returns:
-            value: '5 little pigs'
-        ]
-    ]

     it 'should be possible to call inner functions', ->

@@ -118,58 +105,53 @@
       connection.status.should.equal 'open'
       connection.query().should.equal '5 little pigs'

-it 'should match to right lie if multiple per function', ->
-  liar = createLiar [{
-    function_name: 'add'
-    arguments: [2, 3]
-    returns:
-      value: 5
-  },{
-    function_name: 'add'
-    arguments: [5, 4]
-    returns:
-      value: 9
-  }]
-  liar.add(2,3).should.equal 5
-  liar.add(5,4).should.equal 9
+  it 'should match to right lie if multiple per function', ->
+    liar.expect [{
+      function_name: 'add'
+      arguments: [2, 3]
+      returns:
+        value: 5
+    },{
+      function_name: 'add'
+      arguments: [5, 4]
+      returns:
+        value: 9
+    }]
+    liar.add(2,3).should.equal 5
+    liar.add(5,4).should.equal 9

+  describe 'Syntax checking', ->

+    it 'should validate that return has a value property', ->
+      (->
+        liar.expect
+          function_name: 'something'
+          returns:
+            values: 'somevalue' # <- spelled wrong, an "s" at the end!

-describe 'Syntax checking', ->
+        liar.something()

-  it 'should validate that return has a value property', ->
-    (->
-      liar = createLiar [
-        function_name: 'something'
-        returns:
-          values: 'somevalue' # <- spelled wrong, an "s" at the end!
-      ]
-      liar.something()
+      ).should.throw 'returns object must have property "value" or "on_value"'

-    ).should.throw 'returns object must have property "value" or "on_value"'
+    it 'should validate function_name of root', ->
+      (->
+        liar.expect
+          function: 'do_stuff' # forgot _name
+      ).should.throw 'expectation must have property "function_name"'

-  it 'should validate function_name of root', ->
-    (->
-      liar = createLiar [
-        function: 'do_stuff' # forgot _name
-      ]
-    ).should.throw 'expectation must have property "function_name"'
+    it 'should validate that arguments is an array (root)', ->
+      (->
+        liar.expect
+          function_name: 'woop'
+          arguments: 'hats' # forgot the array brackets
+        liar.woop()
+      ).should.throw 'arguments must be of type Array.'

-  it 'should validate that arguments is an array (root)', ->
-    (->
-      liar = createLiar [
-        function_name: 'woop'
-        arguments: 'hats' # forgot the array brackets
-      ]
-      liar.woop()
-    ).should.throw 'arguments must be of type Array.'
-
-  it 'should validate that function is string', ->
-    (->
-      myFunc = -> # just declare a random function
-      liar = createLiar [
-        function_name: myFunc
-        returns: 9
-      ]
-    ).should.throw 'function_name must be a string.'
+    it 'should validate that function is string', ->
+      (->
+        myFunc = -> # just declare a random function
+        liar.expect
+          function_name: myFunc
+          returns: 9
+      ).should.throw 'function_name must be a string.'


cleaning up array constructions

cleaning up array constructions

--- test/color.coffee
+++ test/color.coffee
@@ -230,7 +230,7 @@
   color = Color(123, 43, 98)
   hsl = color.toHsl()

-  equals hsl[0], 319
+  equals hsl[0].round(), 319
   equals hsl[1].toFixed(2), "0.48"
   equals hsl[2].toFixed(2), "0.33"
   equals hsl[3], 1
@@ -239,9 +239,9 @@
   color = Color(20, 45, 123)
   lightColor = color.lighten(0.1)

-  equals lightColor.r(), 27
-  equals lightColor.g(), 62
-  equals lightColor.b(), 167
+  equals lightColor.r().round(), 27
+  equals lightColor.g().round(), 61
+  equals lightColor.b().round(), 167

 test "#darken", ->
   color = Color(34, 58, 29)


More pedantic tidying in gurk.coffee

More pedantic tidying in gurk.coffee

--- src/gurk.coffee
+++ src/gurk.coffee
@@ -93,7 +93,7 @@
     @imageProcessor = new ImageProcessor(canvasWork, ctxWork, @screen.icons)

     #
-    # ----------------------------- Rendering Rewrite START
+    # Create a scene, and add this view to it.
     @scene = new Scene {
       game: @game
       debugRender: false
@@ -101,21 +101,17 @@
     }
     @scene.addView @

-
-    # ----------------------------- Rendering Rewrite END
-    #
-
-    #
-    # ----------------------------- Existing Game Lifecycle START
+    # Construct the Gurk UI and view stack.
+    $(window).keydown(@windowKeyPress)
     @stack = new Array()
+
     @buttonGrid = new ButtonGrid(ctxControl, this)
-    @playMusic(Data.splashMusic)
-    splashView = new SplashView(this)
-    @setView(splashView)
-    $(window).keydown(@windowKeyPress)
     @buttonGrid.draw()
-    # ----------------------------- Existing Game Lifecycle END
-    #
+
+
+    # Play music and show splash view
+    @playMusic Data.splashMusic
+    @setView new SplashView @

   # SceneView implementation
   # -----------------------------------------------------------------------------
@@ -167,6 +163,32 @@
       if (result != null)
         @view.processResult(result)
       @showView()
+
+  isCurrentView: (view) =>
+    return @view == view
+
+  setSize:(size) ->
+    console.log("Get contexts")
+    switch size
+      when "large"
+        @screenWidth = @screenHeight = 768
+        @controlHeight = 400
+        #Screen.SCALE = 6
+      when "normal"
+        @screenWidth = @screenHeight = 512
+        @controlHeight = 400
+        #Screen.SCALE = 4
+      when "small"
+        @screenWidth = @screenHeight = 256
+        @controlHeight = 200
+        #Screen.SCALE = 2
+      else return
+    @controlWidth = Math.floor(@controlHeight * 1.2)
+    $("#screenID").width(@screenWidth).height(@screenHeight);
+    $("#controlID").width(@controlWidth).height(@controlHeight);
+    @view?.draw()
+
+

   getScreen: () =>
     @screen
@@ -254,28 +276,6 @@
     if (@music)
       @playMusic(@music)

-  setSize:(size) ->
-    console.log("Get contexts")
-    switch size
-      when "large"
-        @screenWidth = @screenHeight = 768
-        @controlHeight = 400
-        #Screen.SCALE = 6
-      when "normal"
-        @screenWidth = @screenHeight = 512
-        @controlHeight = 400
-        #Screen.SCALE = 4
-      when "small"
-        @screenWidth = @screenHeight = 256
-        @controlHeight = 200
-        #Screen.SCALE = 2
-      else return
-    @controlWidth = Math.floor(@controlHeight * 1.2)
-    $("#screenID").width(@screenWidth).height(@screenHeight);
-    $("#controlID").width(@controlWidth).height(@controlHeight);
-    @view?.draw()
-
-
   phoneClick: (e, offsetX = 0, offsetY = 0) =>
     relMouse = (event) ->
       canoffset = $(event.currentTarget).offset();
@@ -301,7 +301,4 @@
     confirm = new ConfirmView(this, icon, title, text, yesResult, noResult)
     @pushView(confirm)

-  isCurrentView: (view) =>
-    return @view == view
-
 # -----------------------------------------------------------------------------


add assertion

add assertion

--- test/error.coffee
+++ test/error.coffee
@@ -20,6 +20,7 @@
     hinoki(source, lifetime, 'a').catch hinoki.NotFoundError, (error) ->
       test.equal error.message, "neither value nor factory found for `a` in path `a`"
       test.deepEqual error.path, ['a']
+      test.deepEqual lifetime, {}
       test.done()

   'CircularDependencyError':


Hull.parse now waits for aura to be ready

--- src/hull.coffee
+++ src/hull.coffee
@@ -63,13 +63,19 @@
     booted.util = appParts.app.sandbox.util
     booted.util.Handlebars = Handlebars
     booted.define = define
+
+    appStarted = appParts.app.start({ components: 'body' })
+
     booted.parse = (el, options={})->
-      appParts.app.core.appSandbox.start(el, options)
-    appParts.app.start({ components: 'body' }).then ->
+      appStarted.then ->
+        appParts.app.core.appSandbox.start(el, options)
+
+    appStarted.then ->
       #TODO populate the models from the remoteConfig
       booted.on 'hull.auth.login', _.bind(loginHelpers.login, undefined,  appParts.app.sandbox.data.api.model, appParts.app.core.mediator)
       booted.on 'hull.auth.update', _.bind(loginHelpers.update, undefined,  appParts.app.sandbox.data.api.model, appParts.app.core.mediator)
       booted.on 'hull.auth.logout', _.bind(loginHelpers.logout, undefined, appParts.app.sandbox.data.api.model, appParts.app.core.mediator)
+
     ,(e)->
       console.error('Unable to start Aura app:', e)
       appParts.app.stop()


Don't fail when close command fails

Don't fail when close command fails

--- src/ievm.coffee
+++ src/ievm.coffee
@@ -50,8 +50,9 @@
   @home: path.join process.env.HOME, '.ievms'

   # The command used to install virtual machines via ievms.
-  @ievmsCmd: 'curl -s https://raw.github.com/xdissent/ievms/master/ievms.sh | bash'
   # @ievmsCmd: 'cd ~/Code/ievms && cat ievms.sh | bash'
+  @ievmsCmd:
+    'curl -s https://raw.github.com/xdissent/ievms/master/ievms.sh | bash'

   # ## Class Methods

@@ -178,9 +179,15 @@
     @exec 'cmd.exe', '/c', 'start',
       'C:\\Program Files\\Internet Explorer\\iexplore.exe', url

-  close: -> @ensureRunning().then =>
+  # Close running IE windows in the virtual machine, failing silently if IE is
+  # not currently running.
+  close: -> @ensureNotMissing().then => @ensureRunning().then =>
     @debug 'close'
-    @exec 'taskkill.exe', '/f', '/im', 'iexplore.exe'
+    deferred = Q.defer()
+    success = -> deferred.resolve true
+    failure = -> deferred.resolve false
+    @exec('taskkill.exe', '/f', '/im', 'iexplore.exe').then success, failure
+    deferred.promise

   rearm: (delay=30000) -> @ensureNotMissing().then => @ensureRunning().then =>
     @debug 'rearm'


Add links to real user, where possible

Add links to real user, where possible

--- src/jira.coffee
+++ src/jira.coffee
@@ -51,6 +51,24 @@
       error = new Error(response.statusText)
       error.response = response
       throw error
+
+  lookupUserWithJira = (jira) ->
+    users = robot.brain.users()
+    result = (users[user] for user of users when users[user].email_address is jira.emailAddress) if jira
+    if result.length is 1
+      return "<@#{result[0].id}>"
+    else
+      return jira.displayName
+
+  lookupUserWithGithub = (github) ->
+    users = robot.brain.get('github-users') or []
+    result = (user for user in users when user.github is github.login) if github
+    if result?.length is 1
+      return "<@#{result[0].id}>"
+    else if github
+      return github.login
+    else
+      return "Unassigned"

   report = (project, type, msg) ->
     reporter = null
@@ -116,8 +134,8 @@
         message = """
           *[#{json.key}] - #{json.fields.summary}*
           Status: #{json.fields.status.name}
-          Assignee: #{if json.fields.assignee?.displayName then "<@#{json.fields.assignee.displayName}>" else "Unassigned"}
-          Reporter: #{json.fields.reporter.displayName}
+          Assignee: #{lookupUserWithJira json.fields.assignee}
+          Reporter: #{lookupUserWithJira json.fields.reporter}
           JIRA: #{jiraUrl}/browse/#{json.key}
         """
         json
@@ -141,7 +159,7 @@
             #{pr.htmlUrl}
             Updated: *#{moment(pr.updatedAt).fromNow()}*
             Status: #{if pr.mergeable then "Ready for merge" else "Needs rebase"}
-            Assignee: #{ if pr.assignee? then "<@#{pr.assignee.login}>" else "Unassigned" }
+            Assignee: #{lookupUserWithGithub pr.assignee}
           """
       .then () ->
         msg.send message


no test

no test

--- src/keygen.iced
+++ src/keygen.iced
@@ -88,7 +88,7 @@
   openpgp.init()
   await generate_keypair { nbits : 4096, progress_hook, userid : "Max Krohn <max@keybase.io>", passphrase : "ejjejjee"}, defer err, key
   console.log key
-test()
+#test()

 #=================================================================


Fix local storage behaviour in iOS Safari private browsing.

--- src/p13n.coffee
+++ src/p13n.coffee
@@ -112,6 +112,7 @@

             @attributes = _.clone DEFAULTS
             # FIXME: Autodetect language? Browser capabilities?
+            @localStorageEnabled = @testLocalStorageEnabled()
             @_fetch()

             @deferred = i18n.init
@@ -143,9 +144,17 @@
                                 return value.replace(grammaticalCase, options.street)

             moment.locale makeMomentLang(@getLanguage())
-
             # debugging: make i18n available from JS console
             window.i18nDebug = i18n
+
+        testLocalStorageEnabled: () =>
+            val = '_test'
+            try
+                localStorage.setItem val, val
+                localStorage.removeItem val
+                return true
+            catch e
+                return false

         _handleLocation: (pos, positionObject) =>
             if pos.coords.accuracy > 10000
@@ -363,7 +372,7 @@
                 @setTransport 'public_transport', true

         _fetch: ->
-            if not localStorage
+            if not @localStorageEnabled
                 return

             str = localStorage.getItem LOCALSTORAGE_KEY
@@ -375,7 +384,7 @@
             @_verifyValidState()

         _save: ->
-            if not localStorage
+            if not @localStorageEnabled
                 return

             data = _.extend @attributes, version: CURRENT_VERSION


refactor

refactor

--- src/prob.coffee
+++ src/prob.coffee
@@ -64,13 +64,15 @@
 ###
 partitionProbability = () ->
   if isArray arguments[0]
-    args = arguments[0]
+    hand = arguments[0]
   else
-    args = Array.prototype.slice.call arguments
+    hand = Array.prototype.slice.call arguments

-  key = args.toString()
+  key = hand.toString()

   throw new Error 'Not a valid partition!' unless validPartitions.hasOwnProperty key
+
+  verifyHandSize hand

   # Don't re-calculate unless we have to
   return validPartitions[key] if validPartitions[key]
@@ -79,7 +81,7 @@

   denominator = bc deckSize, handSize

-  numerator = args.map (e) ->
+  numerator = hand.map (e) ->
     bc handSize, e

   .reduce (a, b) ->


add options to git diff

add options to git diff

--- src/repo.coffee
+++ src/repo.coffee
@@ -128,14 +128,32 @@
   # commitA  - A Commit or String commit id.
   # commitB  - A Commit or String commit id.
   # paths    - A list of String paths to restrict the difference to (optional).
+  # options  - An object of options to pass to git diff (optional)
   # callback - A Function which receives `(err, diffs)`.
   #
-  diff: (commitA, commitB, paths, callback) ->
-    [callback, paths] = [paths, callback] if !callback
-    paths ?= []
+  # Possible forms of the method:
+  #
+  # diff(commitA, commitB, callback)
+  # diff(commitA, commitB, paths, callback)
+  # diff(commitA, commitB, options, callback)
+  # diff(commitA, commitB, paths, options, callback)
+  #
+  diff: (commitA, commitB) ->
+    [paths, options] = [[], {}]
+    if arguments.length is 3
+      callback = arguments[2]
+    else if arguments.length is 4
+      callback = arguments[3]
+      if arguments[2] instanceof Array
+        paths = arguments[2]
+      else if arguments[2] instanceof Object
+        options = arguments[2]
+    else if arguments.length is 5
+      [paths, options, callback] = arguments.slice(2)
+
     commitA = commitA.id if _.isObject(commitA)
     commitB = commitB.id if _.isObject(commitB)
-    @git "diff", {}, _.flatten([commitA, commitB, "--", paths])
+    @git "diff", options, _.flatten([commitA, commitB, "--", paths])
     , (err, stdout, stderr) =>
       return callback err if err
       return callback err, Diff.parse(this, stdout)


Remove beta reference in scraperwiki.coffee

--- shared/code/scraperwiki.coffee
+++ shared/code/scraperwiki.coffee
@@ -2,7 +2,7 @@
 scraperwiki.js 2
 Copyright (c) 2013 ScraperWiki Limited
 ScraperWiki tool client library. See
-https://beta.scraperwiki.com/help
+https://scraperwiki.com/help

 jQuery is required.
 ###


Add missing packagePath variable

Add missing packagePath variable

--- src/test.coffee
+++ src/test.coffee
@@ -31,7 +31,8 @@
     env = process.env

     atomCommand = args.argv.path ? 'atom'
-    testArgs = ['--dev', '--test', "--spec-directory=#{path.join(process.cwd(), 'spec')}"]
+    packagePath = process.cwd()
+    testArgs = ['--dev', '--test', "--spec-directory=#{path.join(packagePath, 'spec')}"]

     if process.platform is 'win32'
       logFile = temp.openSync(suffix: '.log', prefix: path.basename(packagePath))


update script.coffee

update script.coffee

--- dev/coffee/script.coffee
+++ dev/coffee/script.coffee
@@ -1,6 +1,6 @@
 get_random = (min, max) ->
-  min = min ? 0
-  max = max ? 0
+  min = min or 0
+  max = max or 0

   if typeof(min) is 'number' and typeof(max) is 'number'
     random = Math.floor(Math.random() * (max - min + 1) + min)
@@ -243,6 +243,7 @@
           img = data.images[ settings.images.index ]
           $('img[role="top banner"]').attr 'src', ["/img/", img].join("")
           $('img[role="top banner"]').removeClass 'hide'
+        return

       error: (err) ->
         return


dotted keys break when the attribute has a default

I modified a test precondition to expose this problem

--- test/index.coffee
+++ test/index.coffee
@@ -645,7 +645,7 @@
   Embedded = new Document simple_collection,
     attr: 'at'
     embed: Embed 'em',
-      attr: 'at'
+      attr: ['at', 666]

   Deep = new Document simple_collection,
     one: Embed '1',


Added a Triangle method circumCircleRadius() in Delaunay.

--- examples/delaunay.coffee
+++ examples/delaunay.coffee
@@ -102,11 +102,18 @@
     n = @b.lift().minus(@a.lift()).cross @c.lift().minus(@a.lift())
     if n.z <= 0 then n else n.times -1

-  # The function `circumCircleCenter` computes the center of the circum-circle
+  # The method `circumCircleCenter` computes the center of the circum-circle
   # of this triangle.
   memo @, 'circumCircleCenter', ->
     n = @liftedNormal()
     new Point2d(n.x, n.y).times -0.5 / n.z if 1e-6 < Math.abs n.z
+
+  # The method `circumCircleCenter` computes the center of the circum-circle
+  # of this triangle.
+  memo @, 'circumCircleRadius', ->
+    c = @circumCircleCenter()
+    square = (x) -> x * x
+    Math.sqrt square(c.x - @a.x) + square(c.y - @a.y)

   # The function `inclusionInCircumCircle` checks whether a point d is inside,
   # outside or on the circle through this triangle's vertices. A positive


Already refactored what little Delaunay code there was.

--- examples/delaunay.coffee
+++ examples/delaunay.coffee
@@ -15,13 +15,12 @@
 # triangle, specified by three input points.
 circumCircleCenter = (a, b, c) ->

-  # The three given points are first projected onto a paraboloid.
-  [ap, bp, cp] = [a.projection(), b.projection(), c.projection()]
+  # First, the normal to the plane formed by the projections of the
+  # points a, b and c onto a standard parabola is computed.
+  ap = a.projection()
+  n = b.projection().minus(ap).cross c.projection().minus(ap)

-  # The normal to the projected triangle is computed next.
-  n = bp.minus(ap).cross cp.minus(ap)
-
-  # The normal scaled to z=-1/2 and projected back onto the x,y-plane
+  # This normal scaled to z=-1/2 and projected back onto the x,y-plane
   # yields the desired point.
   if Math.abs(n.z) > 1e-6
     p = n.times 1 / (-0.5 * n.z)
@@ -33,16 +32,12 @@
 # inside, zero means on and a negative value means outside.
 inclusionInCircumCircle = (a, b, c, d) ->

-  # The four given points are first projected onto a paraboloid.
-  [ap, bp, cp, dp] =
-    [a.projection(), b.projection(), c.projection(), d.projection()]
+  # First, the normal to the plane formed by the projections of the
+  # points a, b and c onto a standard parabola is computed.
+  ap = a.projection()
+  n = b.projection().minus(ap).cross c.projection().minus(ap)

-  # The normal to the triangle formed by the projection of a, b and c
-  # is computed next.
-  n = bp.minus(ap).cross cp.minus(ap)
-
-  # The following tells us whether the projection of d is on, below or
-  # above the plane of the projected triangle, and thus whether d
-  # itself is on, inside or outside the circum-circle of the original
-  # one.
-  d.minus(a).dot(n) * (if n.z > 0 then -1 else 1)
+  # This dot product tells us whether the projection of d is on, below
+  # or above the plane of the projected triangle, and thus whether d
+  # is on, inside or outside the circum-circle of the original one.
+  d.projection().minus(ap).dot(n) * (if n.z > 0 then -1 else 1)


Remove view

Remove view

--- src/view.coffee
+++ src/view.coffee
@@ -1,27 +0,0 @@
-define ['check', 'jquery', 'handlebars'], (check, $, Handlebars) ->
-
-  class MilkSugar.View
-
-    constructor: (@view) ->
-
-    data: null
-    subviews: []
-    partials: []
-    helpers: {}
-    target: null
-
-    render: (options) ->
-      dataObject = null
-
-      check(@data)
-        .array((data) -> dataObject = $.when @data)
-        .object((data) -> dataObject = $.Deferred((defer) -> defer.resolve([data])).promise())
-        .string((data) -> dataObject = $.ajax data)
-
-      check(@partials)
-
-      check(@subviews)
-
-      $.ajax(@view).done(->
-
-      )


Revert "Reduce spec timeout duration"

Revert "Reduce spec timeout duration"

This reverts commit e03df6e1a48fea12782b25df0b81790e4f4a056c.

--- spec/async-spec-helpers.coffee
+++ spec/async-spec-helpers.coffee
@@ -19,7 +19,9 @@

 waitsForPromise = (fn) ->
   promise = fn()
-  waitsFor 'spec promise to resolve', 30000, (done) ->
+  # This timeout is 3 minutes. We need to bump it back down once we fix backgrounding
+  # of the renderer process on CI. See https://github.com/atom/electron/issues/4317
+  waitsFor 'spec promise to resolve', 3 * 60 * 1000, (done) ->
     promise.then(
       done,
       (error) ->


Re-factored a small bit of code to make the coffee linter happy.

--- spec/barcode_input_spec.coffee
+++ spec/barcode_input_spec.coffee
@@ -43,7 +43,7 @@
 ####
 # Event Spying form https://github.com/jandudulski/jasmine-jquery/blob/master/lib/jasmine-jquery.js

-( (namespace) ->
+addEventSpies = (namespace) ->
   data = {
     spiedEvents: {},
     handlers:    []
@@ -63,7 +63,7 @@
       data.handlers    = []

   }
-)(jasmine)
+addEventSpies(jasmine)

 spyOnEvent = (selector, eventName) -> jasmine.events.spyOn selector, eventName


Flipped a single quote around, because that's how I roll.

--- spec/helpers/SpecHelper.coffee
+++ spec/helpers/SpecHelper.coffee
@@ -35,7 +35,7 @@
         expect(actualOffset).toEqual(expectedOffset)

     if options.expectedHelper
-      it 'should have a helper property that represents a reference to the drag helper‘s DOM element', ->
+      it 'should have a helper property that represents a reference to the drag helper’s DOM element', ->
         expectedHelper = options.expectedHelper.call(this)
         actualHelper = @[options.spyName].mostRecentCall.args[options.argNumber].helper
         expect(actualHelper).toBe(expectedHelper)


Modify specs for use inside Travis-CI.

Modify specs for use inside Travis-CI.

--- spec/linter-opencl-spec.coffee
+++ spec/linter-opencl-spec.coffee
@@ -28,7 +28,7 @@

   beforeEach ->
     waitsForPromise ->
-      atom.config.set('linter-opencl.openCL.platformIndex', 1)
+      atom.config.set('linter-opencl.openCL.platformIndex', 0)
       # atom.config.set('linter-opencl.openCL.platformIndex', 1)
       atom.config.set('linter-opencl.debug', true)
       atom.packages.activatePackage('language-opencl')


Add basic tests for reduceTerm()'s termination and max steps

--- test/tests.coffee
+++ test/tests.coffee
@@ -58,6 +58,18 @@
   it 'should reduce a beta-redex that is formed only after a reduction', ->
     shouldReduce '(λx.x y) (λz.z z)', 'y y'

+  it 'should do at most maxStep reduction steps', ->
+    {steps} = reduceTerm '(λx.x x) (λx.x x)', maxSteps: 42
+    assert steps.length is 42
+
+  it 'indicates when a reduction terminates', ->
+    {terminates} = reduceTerm '(λx.x) y'
+    assert terminates
+
+  it 'indicates when a reduction does not terminate', ->
+    {terminates} = reduceTerm '(λx.x x) (λx.x x)'
+    assert not terminates
+
   describe 'renaming in substitution (λy.T)[x := S]', ->

     it 'should rename when y is free in S and x is free in T', ->


test(utils): add test for `min` function.

--- test/utils.coffee
+++ test/utils.coffee
@@ -14,8 +14,3 @@
     utils.min(['a', 1]).should.be.equal(1)
     utils.min([1, 1]).should.be.equal(1)
     done()
-
-describe 'min', ->
-  it 'should work', (done) ->
-    utils.min([1, 10, 100]).should.be.equal(1)
-    done()


Unfocus spec

Unfocus spec

--- spec/view-registry-spec.coffee
+++ spec/view-registry-spec.coffee
@@ -1,7 +1,7 @@
 ViewRegistry = require '../src/view-registry'
 {View} = require '../src/space-pen-extensions'

-fdescribe "ViewRegistry", ->
+describe "ViewRegistry", ->
   registry = null

   beforeEach ->


messing with travisci

messing with travisci

--- test/cases/controller/paramsTest.coffee
+++ test/cases/controller/paramsTest.coffee
@@ -4,15 +4,16 @@
   beforeEach (done) ->
     # for travisci...
     console.log 'Tower.ControllerParams.beforeEach...'
-    App.Post.all (error, posts) =>
-      console.log 'BEFORE ANY POSTS', _.stringify(posts) #
-      App.Post.create title: 'First Post', rating: 8, =>
-        App.Post.all (error, posts) =>
-          console.log 'After FIRST POST', _.stringify(posts) #
-          App.Post.create title: 'Second Post', rating: 7, =>
-            App.Post.all (error, posts) =>
-              console.log 'After SECOND POST', _.stringify(posts) #
-              done()
+    App.Post.destroy =>
+      App.Post.all (error, posts) =>
+        console.log 'BEFORE ANY POSTS', _.stringify(posts) #
+        App.Post.create title: 'First Post', rating: 8, =>
+          App.Post.all (error, posts) =>
+            console.log 'After FIRST POST', _.stringify(posts) #
+            App.Post.create title: 'Second Post', rating: 7, =>
+              App.Post.all (error, posts) =>
+                console.log 'After SECOND POST', _.stringify(posts) #
+                done()

   beforeEach (done) ->
     Tower.start(done)


remove console log

remove console log

--- lib/analytics.coffee
+++ lib/analytics.coffee
@@ -107,7 +107,6 @@
 maxTrackableMultiIds = 50

 module.exports.encodeMulti = (ids) ->
-  console.log createHash
   if createHash
     ids = _.compact(ids)
     (_.map ids, (id) -> createHash('md5').update(id).digest('hex').substr(0, 8)).join("-")


Remove dependency to Tabsets

Remove dependency to Tabsets

--- app/assets/javascripts/darkswarm/directives/pageset_ctrl.js.coffee
+++ app/assets/javascripts/darkswarm/directives/pageset_ctrl.js.coffee
@@ -1,4 +1,4 @@
-Darkswarm.directive "pagesetCtrl", (Tabsets, $location) ->
+Darkswarm.directive "pagesetCtrl", ($location) ->
   restrict: "C"
   scope:
     id: "@"
@@ -9,7 +9,7 @@
     $scope.selected = path[1..] if path

     this.toggle = (name) ->
-      Tabsets.toggle($scope.id, name, "open")
+      this.select(name)

     this.select = (selection) ->
       $scope.$broadcast("selection:changed", selection)
@@ -23,4 +23,4 @@
     this

   link: (scope, element, attrs, ctrl) ->
-    Tabsets.register(ctrl, scope.id, scope.selected)
+    ctrl.select(scope.selected) if scope.selected?


TAP5-2225: use a check that works if jQuery is not loaded

--- tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
+++ tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
@@ -908,10 +908,10 @@

     if element is null
       element = document.body
-    else if element instanceof jQuery
-      element = element[0];
     else if element instanceof ElementWrapper
       element = element.element;
+    else if element.jquery?
+      element = element[0];

     # Look for event data in itself first, then in the preceding siblings


Support restarting broadcast

Support restarting broadcast

--- lib/broadcast.coffee
+++ lib/broadcast.coffee
@@ -11,9 +11,9 @@
     atom.workspaceView.command "broadcast:stop", => @stop()

   start: ->
-    if server isnt null
-      console.error 'Broadcast has already started'
-      return
+    # If server has already started, then it should stop first
+    if server?
+      @stop()

     filePath = path.join __dirname, '..'
     template = fs.readFileSync path.join(filePath, 'template.html'), {encoding: 'utf8'}
@@ -54,8 +54,7 @@
       for socket in sockets
         socket.destroy()

-    if server isnt null
-      server.close()
-      server = null
+    server?.close()
+    server = null

     console.log 'Broadcast stopped.'


fix(bundle): fix support for express3

fix(bundle): fix support for express3

--- lib/bundle_up.coffee
+++ lib/bundle_up.coffee
@@ -42,12 +42,9 @@

     if(@app.locals)
       # Support for Express 3
-      @app.locals(
-        renderStyles: (namespace=@css.defaultNamespace) =>
-          return @css.render(namespace)
-        renderJs: (namespace=@js.defaultNamespace) =>
-          return @js.render(namespace)
-      )
+      @app.locals.renderStyles= (namespace=@css.defaultNamespace) => return @css.render(namespace)
+      @app.locals.renderJs = (namespace=@js.defaultNamespace) => return @js.render(namespace)
+

     else if(@app.dynamicHelpers)
       # Support for Express 2


Give support dragEnd event for HTML5 DND now.

--- lib/core/view.coffee
+++ lib/core/view.coffee
@@ -48,6 +48,7 @@
     dragenter     : 'dragEnter'
     dragleave     : 'dragLeave'
     dragover      : 'dragOver'
+    dragend       : 'dragEnd'
     paste         : 'paste'
     transitionend : 'transitionEnd'

@@ -635,6 +636,11 @@
     e.stopPropagation()

   dragLeave:(e)->
+
+    e.preventDefault()
+    e.stopPropagation()
+
+  dragEnd:(e)->

     e.preventDefault()
     e.stopPropagation()


:lipstick: Put expandedEntries after entries property

--- lib/directory.coffee
+++ lib/directory.coffee
@@ -11,9 +11,9 @@
     directory: null
     isRoot: false
     isExpanded: false
-    expandedEntries: -> {}
     status: null # Either null, 'added', 'ignored', or 'modified'
     entries: -> {}
+    expandedEntries: -> {}

   @::accessor 'name', -> @directory.getBaseName()
   @::accessor 'path', -> @directory.getPath()


:lipstick: Remove extra space

:lipstick: Remove extra space

--- lib/directory.coffee
+++ lib/directory.coffee
@@ -138,6 +138,6 @@

   serializeExpansionStates: ->
     expandedEntries = {}
-    for name, entry of  @entries when entry.isExpanded
+    for name, entry of @entries when entry.isExpanded
       expandedEntries[name] = entry.serializeExpansionStates()
     expandedEntries


revert changes for ngAnnotate

revert changes for ngAnnotate

--- lib/extractor.coffee
+++ lib/extractor.coffee
@@ -1,7 +1,7 @@
 # Gratefully stolen from https://gist.github.com/pmuellr/5143384
 path = require "path"

-sourceMapCommentRegEx =  /\/\/[@#] sourceMappingURL=data:application\/json;base64,(.*)$/
+sourceMapCommentRegEx =  /\/\/[@#] sourceMappingURL=data:application\/json;base64,(.*)\n/

 translateSources = (sources, grunt) ->
   newSources = []


update encoding to adhere to rfc3986 (from MDN)

--- lib/hmac-sha1.coffee
+++ lib/hmac-sha1.coffee
@@ -10,7 +10,7 @@
 #
 # Returns the encoded string
 special_encode = (string) ->
-  encodeURIComponent(string).replace(/'/g,"%27").replace(/\!/g, "%21")
+  encodeURIComponent(string).replace(/[!'()]/g, escape).replace(/\*/g, "%2A")

 # Cleaning invloves:
@@ -61,4 +61,4 @@
     #hashed[0..hashed.length-2]  <- python oauth does this to remove '=' but i dont think we need to

-exports = module.exports = HMAC_SHA1+exports = module.exports = HMAC_SHA1


Remove old code comment

Remove old code comment

--- src/browser/MenuManager.coffee
+++ src/browser/MenuManager.coffee
@@ -1,14 +1,3 @@
-# _           = require "lodash"
-# season      = require "season"
-#
-# Menu        = require "menu"
-#
-# module.exports = class AppMenu
-#     constructor         : ->
-#         @template = season.readFileSync season.resolve(__dirname, "./menubar/#{process.platform}.cson")
-#
-#         @menu = Menu.buildFromTemplate @template, _.cloneDeep @template.menu
-#         Menu.setApplicationMenu @menu
 Menu            = require "menu"
 path            = require "path"


[i18n] fixed bug in embedded documents

[i18n] fixed bug in embedded documents

--- src/coffee/content/i18n.coffee
+++ src/coffee/content/i18n.coffee
@@ -11,7 +11,8 @@
     # after reloading the page
     messages = null

-    locale = $ 'html'
+    locale = $ window.top.document
+        .find 'html'
         .attr 'lang'

     exports.init = (callback) ->


Update to a better CoffeeScript syntax

Update to a better CoffeeScript syntax

Fixes #4
Fixes #6

--- lib/shuss-cli.coffee
+++ lib/shuss-cli.coffee
@@ -1,32 +1,32 @@
 argv = require('yargs')
-      .options('d', {
-        alias: 'dir',
-        default: '.',
+      .options('d',
+        alias: 'dir'
+        default: '.'
         describe: 'Served files directory'
-      })
-      .options('p', {
-        alias: 'port',
-        default: '1234',
+      )
+      .options('p',
+        alias: 'port'
+        default: '1234'
         describe: 'Runs Shuss on the specified port'
-      })
-      .options('verbose', {
-        boolean: true,
+      )
+      .options('verbose',
+        boolean: true
         describe: 'Speak to me'
-      })
-      .options('l', {
+      )
+      .options('l',
         alias: 'livereload'
-        boolean: true,
+        boolean: true
         describe: 'Enables LiveReload'
-      })
-      .options('f', {
-        alias: 'file',
+      )
+      .options('f',
+        alias: 'file'
         describe: 'Config file path'
-      })
-      .options('v', {
+      )
+      .options('v',
         alias: 'version'
-        boolean: true,
+        boolean: true
         describe: 'Return actual Shuss version'
-      })
+      )
       .argv
 ShussServer = require './shuss-server'


check if result object exits

check if result object exits

--- src/Actions.coffee
+++ src/Actions.coffee
@@ -27,7 +27,7 @@
           payload : err or res.visible
           error   : err?

-        if (Array.isArray (ids = res.visible)) and ids.length > 0
+        if (Array.isArray (ids = res?.visible)) and ids.length > 0
           { entries } = getState()
           fetch_ids = (id for id in ids when not entries[id]?)
           dispatch Actions.getEntries fetch_ids if fetch_ids.length > 0


Add HighlightComponent::shouldComponentUpdate

--- src/highlight-component.coffee
+++ src/highlight-component.coffee
@@ -1,5 +1,6 @@
 React = require 'react-atom-fork'
 {div} = require 'reactionary-atom-fork'
+{isEqualForProperties} = require 'underscore-plus'

 module.exports =
 HighlightComponent = React.createClass
@@ -61,3 +62,6 @@
     )

     regions
+
+  shouldComponentUpdate: (newProps) ->
+    not isEqualForProperties(newProps, @props, 'startPixelPosition', 'endPixelPosition', 'lineHeightInPixels')


Properly indicate if an association is loaded

--- src/interfaces/json_api.coffee
+++ src/interfaces/json_api.coffee
@@ -317,7 +317,16 @@
     resource.klass().reflectOnAllAssociations().each (reflection) ->
       association = resource.association(reflection.name)
       association.__links = data['relationships']?[s.underscored(reflection.name)]?['links']
-      association.loaded(true) if _.has(attributes, reflection.name)
+
+      relationshipEmpty =
+        if _.isObject(relationship = data['relationships']?[s.underscored(reflection.name)]?['data'])
+          _.keys(relationship).length == 0
+        else if relationship?
+          relationship.length == 0
+        else
+          true
+
+      association.loaded(true) if _.has(attributes, reflection.name) || relationshipEmpty

     resource


Hang registers off of workspace instead of vimState

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -14,13 +14,14 @@
   opStack: null
   mode: null
   submode: null
-  registers: null

   constructor: (@editorView) ->
     @editor = @editorView.editor
     @opStack = []
     @history = []
-    @registers = {}
+    atom.workspace ||= {}
+    atom.workspace.vimState ||= {}
+    atom.workspace.vimState.registers ||= {}
     @mode = 'command'

     @setupCommandMode()
@@ -212,7 +213,7 @@
       type = utils.copyType(text)
       {text, type}
     else
-      @registers[name]
+      atom.workspace.vimState.registers[name]

   # Private: Sets the value of a given register.
   #
@@ -224,7 +225,7 @@
     if name == '*'
       atom.clipboard.write(value.text)
     else
-      @registers[name] = value
+      atom.workspace.vimState.registers[name] = value

   ##############################################################################
   # Commands


Remove unused instance variable in VimState

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -17,7 +17,6 @@
   opStack: null
   mode: null
   submode: null
-  initialSelectedRange: null

   constructor: (@editorElement, @statusBarManager, @globalVimState) ->
     @emitter = new Emitter
@@ -390,7 +389,6 @@

     if @submode == 'linewise'
       @editor.selectLinesContainingCursors()
-      @initialSelectedRange = @editor.getLastSelection().getBufferRange()

     @updateStatusBar()


fix(spellchecker): broken array check logic for en_US default

--- src/nylas-spellchecker.coffee
+++ src/nylas-spellchecker.coffee
@@ -76,7 +76,7 @@
   getAvailableDictionaries: ->
     if process.platform is 'linux'
       arr = spellchecker.getAvailableDictionaries()
-      if not "en_US" in arr
+      if "en_US" not in arr
         arr.push('en_US') # Installed by default in node-spellchecker's vendor directory
       arr
     else


account: initial resize call

account: initial resize call

--- client/app/Applications/Account.kdapplication/AppController.coffee
+++ client/app/Applications/Account.kdapplication/AppController.coffee
@@ -79,6 +79,8 @@

     @_windowDidResize()
     @getSingleton("windowController").registerWindowResizeListener @
+
+    @utils.wait => @split._windowDidResize()

   contentScrolled:(pubInst,event)->
     @__lastScrollTop or= 0


Use path.join

Use path.join

--- views/env.coffee
+++ views/env.coffee
@@ -19,7 +19,7 @@
 fs.ensureDirSync path.join window.PLUGIN_PATH, 'node_modules'

 # Shortcuts and Components
-(window.dbg = require ROOT + '/lib/debug').init()
+(window.dbg = require path.join(ROOT, 'lib', 'debug')).init()
 window._ = require 'underscore'
 window.$ = (param) -> document.querySelector(param)
 window.$$ = (param) -> document.querySelectorAll(param)


our binding is setup too

our binding is setup too

--- test/hooks.coffee
+++ test/hooks.coffee
@@ -7,17 +7,18 @@
 db = new Mongolian("localhost/LiveDocumentTestDB")

-class Thing extends LiveDocument
-
-  @socket = new EventEmitter
-
-  @key "title", { length: [3...24] }
-  @key "description", { max: 140, required: true }
-
+Thing = null
 liveDocumentMongo = new LiveDocumentMongo(new EventEmitter, db)

 describe "LiveDocument", ->
   beforeEach (done) ->
+    class Thing extends LiveDocument
+
+      @socket = new EventEmitter
+
+      @key "title", { length: [3...24] }
+      @key "description", { max: 140, required: true }
+
     # clean out all of the old listeners from previous tests
     socket = new EventEmitter
     Thing.socket = socket
@@ -43,4 +44,10 @@
       thing.save ->
         done("This shouldn't happen")

-    it "should pass the thing in and also bind to this"
+    it "should pass the thing in and also bind to this", (done) ->
+      thing = new Thing {title: "w00t"}
+      Thing.beforeSave (ok, t) ->
+        @.should.equal(t).and.equal(thing)
+        ok()
+      thing.save ->
+        done()


tests wip

tests wip

--- test/index.coffee
+++ test/index.coffee
@@ -1,5 +1,11 @@
 {expect} = require 'chai'
 hubot = require 'actuator'
+
+# todo
+#
+# make passes at using hubot.robot
+# to mock state in the application
+# for each spec

 beforeEach (done) ->
   hubot.initiate(script: '../scripts/tflobby.coffee', done)
@@ -90,7 +96,13 @@
     it 'should create a new pickup with the given map', (done) ->
       hubot.on('hubot sg cp_badlands')
         .spread (response) ->
+          lobby = robot.brain.get('lobby')
           expect(response).to.equal '|| cp_badlands | 0/12 | [  ] ||'
+          expect(lobby).to.have.property('map')
+          expect(lobby).to.have.property('participants')
+          expect(lobby).to.have.property('finalising')
+          expect(lobby).to.have.property('principal')
+          expect(lobby).to.have.property('server')
         .done(done.bind(@, null), done)

     it 'should filter and select a single map if a partial name is given', (done) ->
@@ -109,14 +121,14 @@

   describe 'add me|username', ->

-    it 'should add a given user to a lobby', (done) ->
+    it 'should add a nickname to a lobby', (done) ->
       hubot.on('hubot cg')
       hubot.on('hubot add abcd')
         .spread (response) ->
           expect(response).to.contain '| 1/12 | [ abcd ] ||'
         .done(done.bind(@, null), done)

-    it 'should respond with an error if the given user is already added', (done) ->
+    it 'should respond with an error if the given nickname is already added', (done) ->
       hubot.on('hubot cg')
       hubot.on('hubot add abcd')
       hubot.on('hubot add abcd')
@@ -124,19 +136,25 @@
           expect(response).to.contain 'already added...'
         .done(done.bind(@, null), done)

-    it 'should responsd with an error if the pickup is full', (done) ->
-      hubot.on('hubot add 1')
-      hubot.on('hubot add 2')
-      hubot.on('hubot add 3')
-      hubot.on('hubot add 4')
-      hubot.on('hubot add 5')
-      hubot.on('hubot add 6')
-      hubot.on('hubot add 7')
-      hubot.on('hubot add 8')
-      hubot.on('hubot add 9')
-      hubot.on('hubot add 10')
-      hubot.on('hubot add 11')
-      hubot.on('hubot add 12')
+    it 'should responsd with an error if the lobby is full', (done) ->
+
+      lobby =
+        participants:
+          1: 0
+          2: 0
+          3: 0
+          4: 0
+          5: 0
+          6: 0
+          7: 0
+          8: 0
+          9: 0
+          10: 0
+          11: 0
+          12: 0
+
+      hubot.robot.set 'lobby', lobby
+
       hubot.on('hubot add 13')
         .spread (response) ->
           expect(response).to.contain 'the pickup is already full...'
@@ -145,20 +163,33 @@
   describe 'rem me|username', ->

     it 'should respond with an error if no lobby is filling', (done) ->
+
+      hubot.robot.lobby.set 'lobby', null
+
       hubot.on('hubot rem me')
         .spread (response) ->
           expect(response).to.contain 'no pickup filling...'
         .done(done.bind(@, null), done)

     it 'should remove a given user from a lobby', (done) ->
-      hubot.on('hubot add asdf')
+      lobby =
+        participants:
+          asdf: 'asdf'
+
+      hubot.robot.set 'lobby', lobby
+
       hubot.on('hubot rem asdf')
         .spread (response) ->
           expect(response).to.contain '| 0/12 | [  ] ||'
         .done(done.bind(@, null), done)

     it 'should respond with an error if the given user is not listed in the lobby', (done) ->
-      hubot.on('hubot sg lkajsdf')
+      lobby =
+        participants:
+          lkajsdf: 'lkajsdf'
+
+      hubot.robot.set 'lobby', lobby
+
       hubot.on('hubot rem lkjasdf')
         .spread (response) ->
           expect(response).to.contain 'added to the pickup...'
@@ -167,13 +198,23 @@
   describe 'map mapname', ->

     it 'should respond with an error if no lobby is filling', (done) ->
+
+      lobby =
+        map: ''
+
+      hubot.robot.set 'lobby', lobby
+
       hubot.on('hubot map lkjasfd')
         .spread (response) ->
           expect(response).to.contain 'no pickup filling...'
         .done(done.bind(@, null), done)

     it 'should change the map to the given mapname', (done) ->
-      hubot.on('hubot add lkajsdf')
+      lobby =
+        map: 'cp_snakewater_final1'
+
+      hubot.robot.set 'lobby', lobby
+
       hubot.on('hubot map badl')
         .spread (response) ->
           expect(response).to.contain 'changing map to cp_badlands...'


Fix typo

Fix typo

--- virtual-file-system/message-strategies/change.coffee
+++ virtual-file-system/message-strategies/change.coffee
@@ -33,7 +33,7 @@
     node

   moved_to: (path, virtualFileSystem, virtualFile) ->
-    changeStrategies.create(path, virtualFileSystem, virtualFiledata)
+    changeStrategies.create(path, virtualFileSystem, virtualFile)

   close_write: (path, virtualFileSystem, virtualFile) ->
     node = virtualFileSystem.projectNode.update(virtualFile)


Propper assert for float values

Propper assert for float values

--- test/suite.coffee
+++ test/suite.coffee
@@ -24,6 +24,8 @@
         [0, 3]
         [0, 1]
       ]]
+    for pair in query.geojson.$geoWithin.$geometry.coordinates[0]
+      assert.equal typeof val, 'number' for val in pair

 describe 'customNear()', ->
   it 'should not genearate $near query for invalid point', ->
@@ -36,6 +38,7 @@
     assert.deepEqual query, geojson: $near: $geometry:
       type: 'Point'
       coordinates: [0, 1]
+    assert.equal typeof val, 'number' for val in query.geojson.$near.$geometry.coordinates

 describe 'customAfter()', ->
   it 'should not generate after query for invalid date', ->


providing an example multiline style

providing an example multiline style

--- community/server/src/main/coffeescript/neo4j/webadmin/modules/databrowser/visualization/models/style.coffee
+++ community/server/src/main/coffeescript/neo4j/webadmin/modules/databrowser/visualization/models/style.coffee
@@ -36,7 +36,7 @@
           labelColor : new forms.ColorField("Label color")
         })
         label : new forms.FieldSet({
-          labelPattern : new forms.TextField("Label", {tooltip:'You can use placeholders here, {id} for node id, {prop.PROPERTYNAME} for properties. Use ";" to create multiline labels.'})
+          labelPattern : new forms.TextField("Label", {tooltip:'You can use placeholders here, {id} for node id, {prop.PROPERTYNAME} for properties. Use ";" to create multiline labels. Example: "id: {id};name: {prop.name}"'})
         })


Updates the call to dashboard poller in this jasmine test

--- dashboard_spec.coffee
+++ dashboard_spec.coffee
@@ -10,7 +10,7 @@
     it "should return the dashboard data", ->
       that = this

-      @dashboard.getData 'lesson_leaders', {}, (data) ->
+      @dashboard.getData { type: 'lesson_leaders' }, (data) ->
         that.data = data

       request = mostRecentAjaxRequest()


activate/deactivate histogram selection area with double tap on mobile

Former-commit-id: f67921afce89274bd250048eefb8ec5ccd06bf77 [formerly 904beee2b457b7b40195aca087825485872f2c85] [formerly 281ccf4a6c2371e0bf0da12688982f990d24fdb9 [formerly 5a4ab4fd69335a8e57f6546845abc29a092ce33d]] [formerly cff18205655fd00b6b1224b312c9699866066273 [formerly f9545afa3fce03e4f78713d2065e750897ffe666] [formerly b8b2d4ab986ae865237547a0b8057d0a7068261c [formerly b8b2d4ab986ae865237547a0b8057d0a7068261c [formerly 24b44f0ccc7225c43d43544891b4c21c2e0414ed]]]]
Former-commit-id: 5956b232389c804c0268773d259ba0f8404bb639 [formerly 11d63763d2ee447b11c22587bd43f2d89b1c2e79] [formerly 99595b3a1f2fc5c7998c23493e88de9d960a422d [formerly b6382cb0608231cc351ab76f6c5d883a97fed591]]
Former-commit-id: 29e9d5621d39c4a15f2884e46295b19bfc8eaeab [formerly c1fc64c5481b0ff2ee8e396c56f21ad61dac7f0b]
Former-commit-id: f310ceafb16189560e0f4f0bf3824d667a126e17
Former-commit-id: 1fff38a312ebda9f32b6db2abeeccd6f59924ac3

--- @client/histogram.coffee
+++ @client/histogram.coffee
@@ -185,12 +185,28 @@
         _.extend histogram_props,

           onTouchStart: (ev) =>
-            ev.preventDefault()
-            @local.touched = true
-            save @local
-            @onClick(ev)
+            curr_time = new Date().getTime()
+            # activation by double tap
+            if @local.last_tapped_at && curr_time - @local.last_tapped_at < 300
+              ev.preventDefault()
+              @local.touched = true
+              save @local
+              @onClick(ev)
+            else
+              @local.last_tapped_at = curr_time
+              save @local
+
           onTouchMove: (ev) => ev.preventDefault(); @onMouseMove(ev)
-          onTouchEnd: (ev) => ev.preventDefault(); @onMouseUp(ev)
+          onTouchEnd: (ev) =>
+            curr_time = new Date().getTime()
+            # activation by double tap
+            if @local.last_tapped_at && curr_time - @local.last_tapped_at < 300
+              ev.preventDefault()
+              @onMouseUp(ev)
+            else
+              @local.last_tapped_at = curr_time
+              save @local
+
           onTouchCancel: (ev) => ev.preventDefault(); @onMouseUp(ev)

     DIV histogram_props,


The props already overlap without needing to cast

--- resources/assets/coffee/react/beatmap-discussions/header.coffee
+++ resources/assets/coffee/react/beatmap-discussions/header.coffee
@@ -19,8 +19,6 @@
 import { showVisual } from 'utils/beatmapset-helper'
 import Chart from 'beatmap-discussions/chart'
 el = React.createElement
-
-deletedUserJson = deletedUser.toJson()

 export class Header extends React.PureComponent
   render: =>
@@ -128,7 +126,7 @@
                 span null,
                   el StringWithComponent,
                     mappings:
-                      ':user': el(UserLink, key: 'user', user: @props.users[@props.currentBeatmap.user_id] ? deletedUserJson)
+                      ':user': el(UserLink, key: 'user', user: @props.users[@props.currentBeatmap.user_id] ? deletedUser)
                     pattern: osu.trans('beatmaps.discussions.guest')
             el BeatmapBasicStats, beatmap: @props.currentBeatmap


Added jsdocs and better logging. Passed back promise for on(). Allowed providing dependency value synchronously. Added bindMeteor.

--- src/Depends.coffee
+++ src/Depends.coffee
@@ -12,28 +12,33 @@
   _getDeferred: (name) ->
     @_deps[name] ?= Q.defer()

-  # @type {String} name - The name of the resource to add as a dependency.
-  # @type {Array.<String>} [deps] - The names of the dependencies the resource depends on.
-  # @type {Function} callback - A callback which defines the named dependency. This may optionally
-  #     return a result which is passed to the callback of {@link #on}. This may optionally return
-  #     a deferred promise and resolve the dependency in the future.
+  # @type {String} name - The name of the resource to define as a dependency.
+  # @type {Array.<String>|String} [deps] - The names of the dependencies the resource depends on.
+  # @type {Function|*} value - A value which defines the named dependency. This may
+  #     optionally be a callback which returns a result, or one which returns a deferred promise.
+  #     If the value of this argument is not a function, it is resolved as the result of the
+  #     dependency.
   # @returns {Q.Promise} A promise which is resolved once the named dependency is ready.
-  add: (name, deps, callback) ->
-    if Types.isFunction(deps)
-      callback = deps
+  define: (name, deps, value) ->
+    unless Types.isString(deps) || Types.isArray(deps)
+      value = deps
       deps = []
+    isCallback = Types.isFunction(value)
+    if isCallback
+      value = bindMeteor(value)
     df = @_getDeferred(name)
-    log('Added dependency', name, deps)
+    log('Defined dependency', name, deps)
     @on(deps).then(
-      ->
-        Q.when(callback()).then(
-          (result) ->
-            log('Resolved dependency', name)
-            df.resolve(result)
+      bindMeteor (depsResult) ->
+        value = if isCallback then value.apply(null, depsResult) else value
+        Q.when(value).then(
+          bindMeteor (valueResult) ->
+            log('Resolved dependency', name, valueResult)
+            df.resolve(valueResult)
           df.reject
-        )
+        ).done()
       df.reject
-    )
+    ).done()
     df.promise

   # Rejects the promise for delivering the named dependency and cancels any requests for it with
@@ -44,7 +49,7 @@
     if df
       df.reject('Removed dependency: ' + name)

-  # @type {Array.<String>} deps - An array of dependency names.
+  # @type {Array.<String>|String} deps - An array of dependency names.
   # @type {Function} [callback] - If provided, this is used as the success callback once all
   #     dependencies are resolved.
   # @returns {Q.Promise} A promise which is resolved once all dependencies are resolved or rejected
@@ -54,11 +59,16 @@
       throw new Error('No dependencies provided')
     unless Types.isArray(deps)
       deps = [deps]
+    if callback
+      callback = bindMeteor(callback)
     promises = _.map deps, (name) => @_getDeferred(name).promise
     log('Waiting for dependencies', deps)
-    Q.all(promises).then (results) ->
-      log('Dependencies resolved', deps)
+    promise = Q.all(promises)
+    promise.then bindMeteor (results) ->
+      log('Dependencies resolved', deps, results)
       callback?(results)
-      results
+      promise
+    promise

 log = -> console.log.apply(console, arguments) if Depends.debug
+bindMeteor = -> Meteor.bindEnvironment.apply(Meteor, arguments)


Handled Object.defineProperty in flattenProperties.

--- src/Objects.coffee
+++ src/Objects.coffee
@@ -25,7 +25,9 @@

   flattenProperties: (obj) ->
     flattened = {}
-    _.each obj, (value, key) =>
+    # Include properties defined with Object.defineProperty.
+    _.each Object.getOwnPropertyNames(obj), (key) =>
+      value = obj[key]
       if Types.isObjectLiteral(value)
         _.each @flattenProperties(value), (flatValue, flatKey) ->
           flattened[key + '.' + flatKey] = flatValue


Commit fix in progressbar

Commit fix in progressbar

--- client.coffee
+++ client.coffee
@@ -160,6 +160,7 @@
 					border: 0
 					boxShadow: "0 3px 10px 0 rgba(0, 0, 0, 1)"
 					marginBottom: '-25px'
+					overflowX: "hidden"
 				Dom.div !->
 					Dom.style
 						height: "25px"
@@ -180,7 +181,7 @@
 					Dom._get().style.transition = "width " + time + "ms linear"
 					window.progressElement = Dom._get()
 					timer = () -> window.progressElement.style.width = nextPercentage + "%"
-					window.setTimeout(timer, 10)
+					window.setTimeout(timer, 100)
 				Dom.div !->
 					Dom.text barText
 					Dom.style


Add ellipsis to long titles

Add ellipsis to long titles

--- modules/player/queueManager.coffee
+++ modules/player/queueManager.coffee
@@ -79,11 +79,13 @@
       currentNick = Core.bot.User.memberOf(guild).nick
       newNick = null
       if instance.nowPlaying
+        title = instance.nowPlaying.title.substr(0, 28)
+        title = title.substr(0, 29) + '...' if instance.nowPlaying.title.length > 28
         switch instance.nowPlaying.status
           when 'playing'
-            newNick = "▶ | " + instance.nowPlaying.title.substr(0, 28)
+            newNick = "▶ | " + title
           when 'paused', 'suspended'
-            newNick = "⏸ | " + instance.nowPlaying.title.substr(0, 28)
+            newNick = "⏸ | " + title
       if currentNick isnt newNick
         Core.bot.User.memberOf(guild).setNickname(newNick)
     # Event Messages


namespaced Movable

namespaced Movable

--- src/ageable.coffee
+++ src/ageable.coffee
@@ -13,13 +13,7 @@

 player.update(1)

-player.I.rotation
-# => 0.04908738521234052 # Math.PI / 64

-player.update(1)
-
-player.I.rotation
-# => 0.09817477042468103 # 2 * (Math.PI / 64)
 </pre></code>

 @name Ageable


Allow accessToken in Hull.init

Allow accessToken in Hull.init

--- src/api/xdm.coffee
+++ src/api/xdm.coffee
@@ -6,7 +6,8 @@
     remoteUrl = "#{config.orgUrl}/api/v1/#{config.appId}/remote.html?v=#{version}"
     remoteUrl += "&js=#{config.jsUrl}"  if config.jsUrl
     remoteUrl += "&uid=#{config.uid}"   if config.uid
-    remoteUrl += "&access_token=#{config.appSecret}" if config.appSecret
+    accessToken = config.accessToken || config.appSecret
+    remoteUrl += "&access_token=#{accessToken}" if accessToken?
     remoteUrl += "&user_hash=#{config.userHash}" if config.userHash != undefined
     remoteUrl += "&r=#{encodeURIComponent(document.referrer)}"
     remoteUrl


Don't use deepStrictEqual because travis is finding https://www.npmjs.com/package/assert instead, which doesn't have deepStrictEqual

--- test/mustdo-manager.coffee
+++ test/mustdo-manager.coffee
@@ -13,20 +13,20 @@

   it 'is initialized with empty task list', ->
-    assert.deepStrictEqual @manager.full_task_list, {},
+    assert.deepEqual @manager.full_task_list, {},
       'task list for all days is empty object'

-    assert.deepStrictEqual @manager.task_list(), [],
+    assert.deepEqual @manager.task_list(), [],
       'task list for today is empty list'

   it 'can be initialized with a task list', ->
     @manager = new MustDoManager(
       { 20151010: [ {description: 'walk the house'} ] }
     )
-    assert.deepStrictEqual @manager.full_task_list,
+    assert.deepEqual @manager.full_task_list,
       { 20151010: [ {description: 'walk the house'} ] }

-    assert.deepStrictEqual @manager.task_list('20151010'),
+    assert.deepEqual @manager.task_list('20151010'),
       [ {description: 'walk the house'} ]

   it 'adds simple tasks to the default task list', ->


update spec

update spec

--- spec/lib/interval-tree.coffee
+++ spec/lib/interval-tree.coffee
@@ -1,20 +1,7 @@

 IntervalTree = require '../../src/lib/interval-tree'
 Interval     = require '../../src/lib/interval'
-
-createRandomInterval = (unit, id) ->
-
-    p1 = Math.floor(Math.random() * unit)
-    p2 = Math.floor(Math.random() * unit)
-
-    if p1 is p2
-        if p1 > 0
-            p1--
-        else
-            p2++
-
-    return new Interval(Math.min(p1, p2), Math.max(p1, p2), id)
-
+Node         = require '../../src/lib/node'

 describe 'IntervalTree', ->
@@ -23,51 +10,131 @@

         @iTree = new IntervalTree(500)

-        @intervals = (createRandomInterval(1000, i) for i in [0...100])

-        for interval in @intervals
+    it 'throws an error when null is passed to constructor', ->

-            @iTree.add interval.start, interval.end, interval.id
+        expect(-> new IntervalTree(null)).to.throw 'IntervalTree: center is required.'
+
+
+
+    describe 'add', ->
+
+        it 'throws an error when non-number value is given to "start"', ->
+            expect(-> @iTree.add('123', 39)).to.throw Error
+
+
+        it 'throws an error when non-number value is given to "end"', ->
+            expect(-> @iTree.add(123, '39')).to.throw Error
+
+
+        it 'throws an error when duplicated id is given', ->
+            @iTree.add(123, 345, 'foo')
+            expect(-> @iTree.add(1234, 3457, 'foo')).to.throw Error
+
+
+        it 'adds data with automatically-inserted id', ->
+
+            interval = @iTree.add(12, 39)
+
+            expect(interval).to.be.instanceof Interval
+            expect(interval).to.have.property('id')
+
+            id = interval.id
+
+            expect(@iTree.intervalsById[id]).to.equal interval
+            expect(@iTree.nodesById[id]).to.be.instanceof Node
+
+
+        it 'adds data with custom id', ->
+
+            interval = @iTree.add(-100, 10000, 'foo')
+
+            expect(interval).to.be.instanceof Interval
+            expect(interval).to.have.property('id', 'foo')
+
+            expect(@iTree.intervalsById.foo).to.equal interval
+            expect(@iTree.nodesById.foo).to.be.instanceof Node
+

     describe 'search', ->

-        it 'runs point search when one argument is given', ->
+        it 'throws an error when 1st argument is not a number', ->
+
+            expect(-> @iTree.search('123')).to.throw Error
+
+
+        it 'runs point search when one argument is given', (done) ->
+
+            @iTree.pointSearch = (val) ->
+                expect(val).to.equal 100
+                done()
+
+            @iTree.search(100)
+
+        it 'throws an error when 2nd argument is given and not a number', ->
+
+            expect(-> @iTree.search(70, '123')).to.throw Error
+
+
+        it 'runs range search when two arguments are given', (done) ->
+
+            @iTree.rangeSearch = (val1, val2) ->
+                expect(val1).to.equal 100
+                expect(val2).to.equal 200
+                done()
+
+            @iTree.search(100, 200)
+

     describe 'pointSearch', ->

-        it 'searches intervals by point', ->
+        it 'returns overlapping intervals ', ->

-            results = @iTree.search(500)
+            @iTree.add 499, 500, '499-500'
+            @iTree.add 499, 501, '499-501'
+            @iTree.add 500, 501, '500-501'
+            @iTree.add 501, 502, '501-502'
+            @iTree.add -31, 502, '-31-502'

-            resultIds = (result.id for result in results)
+            results = @iTree.pointSearch(500)

-            for interval in @intervals
+            expect(results).to.be.instanceof Array
+            expect(results[0]).to.be.instanceof Interval
+            expect(results).to.have.length 4

-                { start, end, id } = interval
+            for interval in results
+                expect(interval.start).to.be.below 501
+                expect(interval.end).to.be.above 499

-                if id in resultIds
-
-                    expect(start).to.be.below 501
-                    expect(end).to.be.above 499
-
-                else if start < 500
-                    expect(end).to.be.below 500
-
-                else
-                    expect(start).to.be.above 500

     describe 'rangeSearch', ->

         it 'searches intervals by range', ->

-            results = @iTree.search(500, 700)
+            @iTree.add 498, 499, '498-499' # x
+            @iTree.add 499, 500, '499-500' # o
+            @iTree.add 499, 501, '499-501' # o
+            @iTree.add 500, 501, '500-501' # o
+            @iTree.add 501, 502, '500-502' # o
+            @iTree.add 509, 510, '509-510' # o
+            @iTree.add 509, 511, '509-511' # o
+            @iTree.add 510, 511, '510-511' # o
+            @iTree.add 511, 512, '511-512' # x
+            @iTree.add -31, 999, '-31-999' # o
+
+            results = @iTree.rangeSearch(500, 510)

             resultIds = (result.id for result in results)

-            for interval in @intervals
+            expect(results).to.be.instanceof Array
+            expect(results[0]).to.be.instanceof Interval
+            expect(results).to.have.length 8
+
+
+            for id, interval of @iTree.intervalsById

                 { start, end, id } = interval

@@ -76,16 +143,15 @@
                     if start < 500
                         expect(end).to.be.above 499

-                    else if end > 700
-                        expect(start).to.be.below 701
+                    else if end > 510
+                        expect(start).to.be.below 511

                     else
-                        expect(start).within 500, 700
-                        expect(end).within 500, 700
-
+                        expect(start).within 500, 510
+                        expect(end).within 500, 510

                 else
-                    expect(start > 700 or end < 500).to.be.true
+                    expect(start > 510 or end < 500).to.be.true

@@ -93,14 +159,16 @@

         it 'removes an interval by id', ->

-            id = 59
+            @iTree.add 498, 499, 'foo'
+            @iTree.add 498, 499, 'bar'
+
+            id = 'foo'
+
             interval = @iTree.intervalsById[id]
             node = @iTree.nodesById[id]
             count = node.count()

-
             @iTree.remove id
-

             expect(@iTree.intervalsById[id]).to.not.exist
             expect(@iTree.nodesById[id]).to.not.exist


Construct test instance of MenuManager in spec

--- spec/menu-manager-spec.coffee
+++ spec/menu-manager-spec.coffee
@@ -1,43 +1,48 @@
+MenuManager = require '../src/menu-manager'
+
 describe "MenuManager", ->
+  menu = null
+
+  beforeEach ->
+    menu = new MenuManager(resourcePath: atom.getLoadSettings().resourcePath)
+
   describe "::add(items)", ->
     it "can add new menus that can be removed with the returned disposable", ->
-      originalItemCount = atom.menu.template.length
-      disposable = atom.menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
-      expect(atom.menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]}
+      disposable = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
+      expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}]
       disposable.dispose()
-      expect(atom.menu.template.length).toBe originalItemCount
+      expect(menu.template).toEqual []

     it "can add submenu items to existing menus that can be removed with the returned disposable", ->
-      originalItemCount = atom.menu.template.length
-      disposable1 = atom.menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
-      disposable2 = atom.menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "D", command: 'd'}]}]}]
-      disposable3 = atom.menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "E", command: 'e'}]}]}]
+      disposable1 = menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
+      disposable2 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "D", command: 'd'}]}]}]
+      disposable3 = menu.add [{label: "A", submenu: [{label: "C", submenu: [{label: "E", command: 'e'}]}]}]

-      expect(atom.menu.template[originalItemCount]).toEqual {
+      expect(menu.template).toEqual [{
         label: "A",
         submenu: [
           {label: "B", command: "b"},
           {label: "C", submenu: [{label: 'D', command: 'd'}, {label: 'E', command: 'e'}]}
         ]
-      }
+      }]

       disposable3.dispose()
-      expect(atom.menu.template[originalItemCount]).toEqual {
+      expect(menu.template).toEqual [{
         label: "A",
         submenu: [
           {label: "B", command: "b"},
           {label: "C", submenu: [{label: 'D', command: 'd'}]}
         ]
-      }
+      }]

       disposable2.dispose()
-      expect(atom.menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]}
+      expect(menu.template).toEqual [{label: "A", submenu: [{label: "B", command: "b"}]}]

       disposable1.dispose()
-      expect(atom.menu.template.length).toBe originalItemCount
+      expect(menu.template).toEqual []

     it "does not add duplicate labels to the same menu", ->
-      originalItemCount = atom.menu.template.length
-      atom.menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
-      atom.menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
-      expect(atom.menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]}
+      originalItemCount = menu.template.length
+      menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
+      menu.add [{label: "A", submenu: [{label: "B", command: "b"}]}]
+      expect(menu.template[originalItemCount]).toEqual {label: "A", submenu: [{label: "B", command: "b"}]}


Fix destroy ship

Fix destroy ship

--- views/env.coffee
+++ views/env.coffee
@@ -139,6 +139,10 @@
         window._slotitems.push body.api_slot_item if body.api_create_flag == 1
       when '/kcsapi/api_req_kousyou/destroyship'
         idx = _.sortedIndex window._ships, {api_id: parseInt(postBody.api_ship_id)}, 'api_id'
+        for itemId in window._ships[idx].api_slot
+          continue if itemId == -1
+          itemIdx = _.sortedIndex window._slotitems, {api_id: itemId}, 'api_id'
+          window._slotitems.splice itemIdx, 1
         window._ships.splice idx, 1
       when '/kcsapi/api_req_kousyou/destroyitem2'
         for itemId in postBody.api_slotitem_ids.split(',')


Replace 'keys' with 'docs' for shard graph ('documents' is too long)

--- admin/static/coffee/namespaces/shards.coffee
+++ admin/static/coffee/namespaces/shards.coffee
@@ -373,7 +373,7 @@
                 axe_legend.push
                     x: margin_width
                     y: Math.floor(margin_height/2)
-                    string: 'Keys'
+                    string: 'Docs'
                     anchor: 'middle'
                 axe_legend.push
                     x: Math.floor(svg_width/2)


Add closing tag to turbolinks loading message.

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -8,7 +8,7 @@

 # Have a loading screen when turbolinks is working it's magic
 document.addEventListener 'page:fetch', ->
-  html = "

"
+  html = "

"
   $('body').prepend(html)

 document.addEventListener 'page:receive', ->


Added events_sort theory

Added events_sort theory

--- server/materials/data/topics/events_sort.coffee
+++ server/materials/data/topics/events_sort.coffee
@@ -8,7 +8,7 @@
 export default events_sort = () ->
     return {
         topic: topic("Сортировка событий", "Задачи на сортировку событий", [
-            label("Теории тут пока нет, прослушайте на занятии (попросите меня рассказать)."),
+            label("См. видеозаписи лекций ЛКШ параллели B', раздел «Отрезки на прямой»
"),
             problem(112542),
             problem(1755),
             problem(3721),
@@ -18,4 +18,4 @@
         advancedProblems: [
             problem(1622)
         ]
-    }+    }


force jsonp for geocoding requests, makes ie9 usable #40

--- app/assets/transit/lib/models/plan.js.coffee
+++ app/assets/transit/lib/models/plan.js.coffee
@@ -43,11 +43,15 @@
       callback(@geocode_storage[query])
     else
       bounds = Transit.map.leaflet?.getBounds()
-      $.get 'http://open.mapquestapi.com/nominatim/v1/search'
-        format: 'json'
-        countrycodes: 'US'
-        viewbox: bounds?.toBBoxString()
-        q: query
+      $.ajax
+        type: 'GET'
+        dataType: 'jsonp'
+        url: 'http://open.mapquestapi.com/nominatim/v1/search?json_callback=?'
+        data:
+          format: 'json'
+          countrycodes: 'US'
+          viewbox: bounds?.toBBoxString()
+          q: query
       .success (response) =>
         # save the first result in the local storage
         @geocode_storage[query] = response[0]


Improve button rendering logic

Improve button rendering logic

--- SingularityUI/app/views/ExpandableTableSubview.coffee
+++ SingularityUI/app/views/ExpandableTableSubview.coffee
@@ -32,12 +32,15 @@
             @collection.currentPage -= 1
             return

+        # For after the render
+        haveButtons = @$('.table-subview-buttons').length
+
         @$el.html @template
             synced:  @collection.synced
             data:    _.pluck @collection.models, 'attributes'

         # Stop right here if we don't need to append the expand links and the buttons
-        return if @collection.length isnt @collection.atATime and not @$('.table-subview-buttons').length
+        return if @collection.length isnt @collection.atATime and not haveButtons

         # Append expand / shrink link
         $header = @$('.page-header h1')


呼び出しをわけない

呼び出しをわけない

--- backbone/app/routers/sample_router.js.coffee
+++ backbone/app/routers/sample_router.js.coffee
@@ -6,12 +6,9 @@
     "spa/timers/:type": "timer"
     ".*": "timer"

-  before: ()->
+  timer:(type)->
     @view.remove() if @view
     @view = null
-
-  timer:(type)->
-    @before()
     type ||= "current"
     @view = new Spa.TimerView(collection: @timers,type: type)
     $("#container").html(@view.render().el)


Added rows to show in text area.

Added rows to show in text area.

--- app/assets/javascripts/app/models/signature.js.coffee
+++ app/assets/javascripts/app/models/signature.js.coffee
@@ -5,7 +5,7 @@

   @configure_attributes = [
     { name: 'name',                 display: 'Name',              tag: 'input',    type: 'text', limit: 100, 'null': false, 'class': 'span4' },
-    { name: 'body',                 display: 'Text',              tag: 'textarea',               limit: 250, 'null': true, 'class': 'span4' },
+    { name: 'body',                 display: 'Text',              tag: 'textarea',               limit: 250, 'null': true, 'class': 'span4', rows: 10 },
     { name: 'note',                 display: 'Note',              tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, 'null': true, 'class': 'span4' },
     { name: 'updated_at',           display: 'Updated',           type: 'time',    readonly: 1 },
     { name: 'active',               display: 'Active',            tag: 'boolean',  type: 'boolean', 'default': true, 'null': false, 'class': 'span4' },


more refactor

more refactor

--- app/assets/javascripts/bookings/application.js.coffee
+++ app/assets/javascripts/bookings/application.js.coffee
@@ -59,31 +59,42 @@
     $('#template_form').css('display', 'block')
     event

+  updateForm: (event)->
+    $('#template_form').css('display', 'none')
+    $('#template_form form').attr('action', $('#template_form form').attr('action') + "/#{event.id}")
+    $('#template_form form').attr('method', 'patch')
+    $('#template_form form').submit()
+
+  showUpdatForm: (event)->
+    FormHandler.showForm(event)
+    $('#template_form form').attr('action', $('#template_form form').attr('action') + "/#{event.id}")
+    $('#template_form form').attr('method', 'patch')
+
   showForm: (event)->
-      $('#template_form').html(templateSlotForm)
-      FormHandler.setFormFieldsValue(event)
+    $('#template_form').html(templateSlotForm)
+    FormHandler.setFormFieldsValue(event)

-      $('#template_form form').on 'submit', (e) ->
-        e.preventDefault()
-        url =$(@).attr('action') + '.json'
-        data = $(@).serialize()
-        if $('#template_form form').attr('method') == 'patch'
-          data['_method'] = 'patch'
-          type = 'patch'
-        else
-          type = 'POST'
+    $('#template_form form').on 'submit', (e) ->
+      e.preventDefault()
+      url =$(@).attr('action') + '.json'
+      data = $(@).serialize()
+      if $('#template_form form').attr('method') == 'patch'
+        data['_method'] = 'patch'
+        type = 'patch'
+      else
+        type = 'POST'

-        $.ajax
-          type: type
-          url: url
-          data: data
-          dataType: 'json'
+      $.ajax
+        type: type
+        url: url
+        data: data
+        dataType: 'json'

-          success: (data)->
-            FormHandler.successHandler event, data
-            console.log event
-          error: (xhr, textStatus, errorThrown) ->
-            FormHandler.displayErros xhr.responseJSON.errors
+        success: (data)->
+          FormHandler.successHandler event, data
+          console.log event
+        error: (xhr, textStatus, errorThrown) ->
+          FormHandler.displayErros xhr.responseJSON.errors

@@ -93,11 +104,10 @@
   m = date.getMonth()
   y = date.getFullYear()

-  window.templateSlotCalendar = $("#calendar").fullCalendar(
+  window.templateSlotCalendar = $("#calendar").fullCalendar
     eventClick: (event, element) ->
-      FormHandler.showForm(event)
-      $('#template_form form').attr('action', $('#template_form form').attr('action') + "/#{event.id}")
-      $('#template_form form').attr('method', 'patch')
+      FormHandler.showUpdatForm(event)
+

     theme: false
     slotMinutes: 15
@@ -136,17 +146,10 @@

     eventResize: (event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view)->
       FormHandler.showForm(event)
-      $('#template_form').css('display', 'none')
-      $('#template_form form').attr('action', $('#template_form form').attr('action') + "/#{event.id}")
-      $('#template_form form').attr('method', 'patch')
-      $('#template_form form').submit()
+      FormHandler.updateForm(event)
+

     eventDrop: (event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, viw)->
       FormHandler.showForm(event)
-      $('#template_form').css('display', 'none')
-      $('#template_form form').attr('action', $('#template_form form').attr('action') + "/#{event.id}")
-      $('#template_form form').attr('method', 'patch')
-      $('#template_form form').submit()
-
-
-  )+      FormHandler.updateForm(event)
+


fix bug in regtest

fix bug in regtest

--- test/files/decode_pgp.iced
+++ test/files/decode_pgp.iced
@@ -22,7 +22,7 @@
   n = 0
   for p,i in packets when p.is_key_material()
     n++
-    await p.open { passphrase }, defer err
+    await p.unlock { passphrase }, defer err
     T.no_error err
     err = p.key.sanity_check()
     T.waypoint "opened key #{i}"


Group similar subscribes together

Group similar subscribes together

--- lib/grammar-status-view.coffee
+++ lib/grammar-status-view.coffee
@@ -8,12 +8,11 @@

   initialize: (@statusBar) ->
     @subscribe @statusBar, 'active-buffer-changed', @updateGrammarText
+    @subscribe atom.workspaceView, 'editor:grammar-changed', @updateGrammarText

     @subscribe this, 'click', =>
       atom.workspaceView.getActiveView().trigger('grammar-selector:show')
       false
-
-    @subscribe atom.workspaceView, 'editor:grammar-changed', @updateGrammarText

   attach: ->
     @statusBar.appendLeft(this)


[♻] Cleaned up (“formy”).

[♻] Cleaned up (“formy”).

--- vendor/assets/javascripts/jquery/plugins/formify/formy.js.coffee
+++ vendor/assets/javascripts/jquery/plugins/formify/formy.js.coffee
@@ -34,7 +34,7 @@

     return

-  hideFieldsets: =>
+  hideFieldsets: ->
     @fieldsets.velocity @options.hideFieldsets.effect,
       delay: @options.hideFieldsets.delay
       duration: @options.hideFieldsets.duration


comment log for domain

comment log for domain

--- vendor/assets/javascripts/pullentity-backbone/app/site.js.coffee
+++ vendor/assets/javascripts/pullentity-backbone/app/site.js.coffee
@@ -12,7 +12,7 @@
     info: ->

-console.log window.pullentity_domain
+#console.log window.pullentity_domain
 if _.isUndefined( window.pullentity_domain) or window.pullentity_domain == "http://"
   alert("Please configure the domain name in pullentity.yml file \n Or run > pullentity setup your@email.com. in console")
   false


FAILS: Implement transaction-per-test for some tests in game.coffee.

--- tests/game.coffee
+++ tests/game.coffee
@@ -23,6 +23,7 @@
 transaction = require 'any-db-transaction'
 queryUtils = require '../lib/query_utils'
 sugar = require 'sugar'
+_conn = null
 conn = null
 query = null

@@ -36,27 +37,16 @@

 exports.setUp = (->
-	unless conn?
-		try
-			conn = anyDB.createConnection(config.DATABASE_URL_TEST)
-			queryf = conn.query
-			conn.query = () ->
-				args = (i for i in arguments)
-				cb = args[args.length-1]
-				if cb instanceof Function
-					stack = new Error().stack
-					args[args.length-1] = (err,res) ->
-						if err instanceof Error
-							err.stack = stack
-						cb(err, res)
-				queryf.apply this, args
-			query = queryUtils.getFor conn
-			mg.migrate.sync mg, conn
-		catch e
-			console.error e
-).async() # the entrance to the Fieber land
-
-#exports.tearDown = (->).async()
+	unless _conn?
+		_conn = anyDB.createConnection(config.DATABASE_URL_TEST)
+		mg.migrate.sync mg, _conn
+	conn = transaction(_conn)
+	query = queryUtils.getFor conn
+).async()
+
+exports.tearDown = (->
+	conn.rollback.sync(conn)
+).async()

 exports.getInitialLocation =
@@ -204,10 +194,9 @@
 exports.createBattleBetween = (test) ->
 	clearTables 'battles', 'battle_participants'

-	tx = transaction conn
 	locid = 123

-	game._createBattleBetween tx, locid, [
+	game._createBattleBetween conn, locid, [
 			{id: 1, initiative:  5}
 			{id: 2, initiative: 15}
 			{id: 5, initiative: 30}
@@ -230,7 +219,6 @@
 		{id: 1, index: 4, side: 0}
 	], 'should involve all users and monsters of both sides in correct order'

-	tx.commit.sync tx
 	test.done()

@@ -241,9 +229,7 @@
 	insert 'battle_participants', battle: 1, character_id: 1
 	insert 'battle_participants', battle: 1, character_id: 2

-	tx = transaction conn
-	game._stopBattle(tx, 1)
-	tx.commit.sync tx
+	game._stopBattle(conn, 1)

 	test.strictEqual +query.val("SELECT count(*) FROM battles"), 0, 'should remove battle'
 	test.strictEqual +query.val("SELECT count(*) FROM battle_participants"), 0, 'should remove participants'
@@ -265,9 +251,7 @@
 	insert 'battle_participants', battle: 2, character_id: 5, side: 1, index: 1

-	tx = transaction conn
-
-	res = game._leaveBattle(tx, 1, 1)
+	res = game._leaveBattle(conn, 1, 1)
 	test.strictEqual res.battleEnded, false, "should return false if wasn't ended"

 	test.strictEqual query.val("SELECT autoinvolved_fm FROM characters WHERE id=1"), false,
@@ -281,7 +265,7 @@
 		], "should update indexes if participant has gone"

-	res = game._leaveBattle(tx, 1, 3, 'user')
+	res = game._leaveBattle(conn, 1, 3, 'user')
 	test.strictEqual res.battleEnded, true, 'should return true if battle was ended'

 	test.strictEqual query.val("SELECT autoinvolved_fm FROM characters WHERE id=2"), false,
@@ -297,12 +281,11 @@
 		'should not affect other participants'

 	test.throws(
-		-> game._leaveBattle(tx, 1, 123)
+		-> game._leaveBattle(conn, 1, 123)
 		Error
 		'should throw error if unable to find anyone to leave'
 	)

-	tx.commit.sync tx
 	test.done()

@@ -499,16 +482,16 @@
 	item = query.row 'SELECT id, strength FROM items'
 	power = 80

-	queryUtils.doInTransaction conn, (tx) ->
-		delta = game._hitItem(tx, power, item)
-		item = query.row 'SELECT id, strength FROM items'
-		test.strictEqual delta, 80, "should reduce all attacker's power if item is strong"
-		test.strictEqual item.strength, 20, "should reduce item's strength"
-
-		delta = game._hitItem(tx, power, item)
-		item = query.row 'SELECT id, strength FROM items'
-		test.strictEqual delta, 20, "should reduce part of attacker's power if item was broken"
-		test.strictEqual item.strength, 0, "should reduce item's strength"
+	delta = game._hitItem(conn, power, item)
+	item = query.row 'SELECT id, strength FROM items'
+	test.strictEqual delta, 80, "should reduce all attacker's power if item is strong"
+	test.strictEqual item.strength, 20, "should reduce item's strength"
+
+	delta = game._hitItem(conn, power, item)
+	item = query.row 'SELECT id, strength FROM items'
+	test.strictEqual delta, 20, "should reduce part of attacker's power if item was broken"
+	test.strictEqual item.strength, 0, "should reduce item's strength"
+
 	test.done()

@@ -525,13 +508,11 @@
 		maxDmg = (power - 50) / 2 * 1.2
 		victim_id = 1

-		tx = transaction(conn)
-
 		damages = {}
 		prevHP = 1000

 		for i in [0..100]
-			hp = game._hitAndGetHealth tx, victim_id, power
+			hp = game._hitAndGetHealth conn, victim_id, power
 			hpActual = query.val "SELECT health FROM characters WHERE id=$1", [victim_id]
 			test.strictEqual hp, hpActual, "should return current characters's health"

@@ -548,11 +529,10 @@
 		query "UPDATE characters SET defense = 9001"

 		hpBefore = prevHP
-		hpAfter = game._hitAndGetHealth tx, victim_id, power
+		hpAfter = game._hitAndGetHealth conn, victim_id, power
 		test.strictEqual hpBefore, hpAfter,
 			"should not change health if defense is greater than damage"

-		tx.rollback.sync(tx)
 		test.done()

 	'with armor': (test) ->
@@ -560,21 +540,21 @@
 		damages = null

 		userHP = -> query.val 'SELECT health FROM characters WHERE id=1'
-		totalStringth = -> query.val 'SELECT SUM(strength) FROM items'
+		totalStr = -> query.val 'SELECT SUM(strength) FROM items'

 		performSomeAttacks = ->
 			damages = {}
 			tx = transaction(conn)
 			for i in [0..20]
 				prevHP = userHP()
-				prevSt = totalStringth()
+				prevSt = totalStr()

 				hp = game._hitAndGetHealth tx, 1, power
 				dmg = prevHP - hp
 				damages[dmg] = true

 				if dmg is 0
-					test.ok prevSt > totalStringth(), 'should reduce armor strength if damage was blocked'
+					test.ok prevSt > totalStr(), 'should reduce armor strength if damage was blocked'
 			tx.rollback.sync(tx)


tweaks log output format

tweaks log output format

--- lib/minimap-editor-view.coffee
+++ lib/minimap-editor-view.coffee
@@ -24,7 +24,7 @@
       }))
     @lines.html(html.join(''))
     html = displayBuffer = screenLines = null
-    console.log('Update MinimapEditorView load time ', Date.now() - start, 'ms')
+    console.log('Update MinimapEditorView response time:', (Date.now() - start) + 'ms')

   getClientRect: ->
     sv = @scrollView[0]


:bug: Add log to catch undefined current line in range clearing

--- lib/minimap-editor-view.coffee
+++ lib/minimap-editor-view.coffee
@@ -228,6 +228,9 @@
       domPosition = 0
       for intactRange in intactRanges
         while intactRange.domStart > domPosition
+          unless currentLine?
+            console.warn "Unexpected undefined line at dom position #{domPosition} with range starting at position #{intactRange.domStart} (#{intactRange.start}..#{intactRange.end})"
+            return
           currentLine = @clearLine(currentLine)
           domPosition++


making a little progress -- don't want to loose it.

--- salvus/page/worksheet1.coffee
+++ salvus/page/worksheet1.coffee
@@ -56,15 +56,23 @@
                         #range.selectNode(e[0])
                         sel = rangy.getSelection()
                         range = sel.getRangeAt(0)
-                        newNode = $("
 ")[0]   # need to figure out how to get rid of this space (?)
+                        newNode = $("

")[0]   # need to figure out how to get rid of this space (?)
                         range.insertNode(newNode)
+
                         r2 = rangy.createRange()
-                        #r2.selectNode(newNode)
                         r2.setStart(newNode,1)
                         r2.setEnd(newNode,1)
                         if sel.rangeCount > 0
                             sel.removeAllRanges()
-                        rangy.getSelection().addRange(r2)
+                        sel.addRange(r2)
+
+                        sel.removeAllRanges()
+
+                        r2 = rangy.createRange()
+                        r2.selectNodeContents(newNode)
+                        r2.moveStart("character", 1)
+                        sel.setSingleRange(r2)
+                        sel.deleteFromDocument(r2)
                         return false

             when 40 # down arrow


Fix api_member_lv, api_level type

Fix api_member_lv, api_level type

--- views/env.coffee
+++ views/env.coffee
@@ -189,6 +189,9 @@
     postBody = Object.remoteClone postBody
     # Delete api_token
     delete postBody.api_token if postBody?.api_token?
+    # Fix api
+    body.api_level = parseInt body.api_level if body?.api_level?
+    body.api_member_lv = parseInt body.api_member_lv if body?.api_member_lv?
     switch path
       # Game datas prefixed by $
       when '/kcsapi/api_start2'


Fix #125

Fix #125

--- lib/utils/serial-helper.coffee
+++ lib/utils/serial-helper.coffee
@@ -14,10 +14,11 @@

     cores = []
     serialport.list (err, ports) ->
-      for port in ports
-        if (port.manufacturer && port.manufacturer.indexOf("Spark") >= 0) ||
-            (port.pnpId && port.pnpId.indexOf("Spark_Core") >= 0)
-          cores.push port
+      if ports
+        for port in ports
+          if (port.manufacturer && port.manufacturer.indexOf("Spark") >= 0) ||
+              (port.pnpId && port.pnpId.indexOf("Spark_Core") >= 0)
+            cores.push port

       if !cores.length
         for port in ports


Fix search result lmo href

Fix search result lmo href

--- angular/core/components/thread_page/previous_proposals_card/previous_proposals_card.coffee
+++ angular/core/components/thread_page/previous_proposals_card/previous_proposals_card.coffee
@@ -1,4 +1,4 @@
-angular.module('loomioApp').directive 'previousProposalsCard', ($routeParams) ->
+angular.module('loomioApp').directive 'previousProposalsCard', ->
   scope: {discussion: '='}
   restrict: 'E'
   templateUrl: 'generated/components/thread_page/previous_proposals_card/previous_proposals_card.html'


add api shortcuts for common methods

add api shortcuts for common methods

--- modules/http/lib/Router.coffee
+++ modules/http/lib/Router.coffee
@@ -12,6 +12,13 @@
         constructor: (@ID)->

             @_routes = []
+            for m in ['get', 'head', 'post', 'put', 'delete', 'trace', 'connect']
+                do (m)=>
+                    @[m] = (route, handler)=>
+                        @add route, (req, res, next)=>
+                            if req.method is m.toUpperCase()
+                                handler req, res, next
+                            else next()

         ##


Removed unnecessary focusout directive

Removed unnecessary focusout directive

--- src/ng-quick-datepicker.coffee
+++ src/ng-quick-datepicker.coffee
@@ -277,11 +277,3 @@
           fn scope,
             $event: event
   ]
-  app.directive "ngFocusout", ["$parse", ($parse) ->
-    (scope, element, attr) ->
-      fn = $parse(attr["ngFocusOut"])
-      element.bind "focusout", (event) ->
-        scope.$apply ->
-          fn scope,
-            $event: event
-  ]


Minor formatting fix

Minor formatting fix

--- library/gearing/service.coffee
+++ library/gearing/service.coffee
@@ -106,7 +106,7 @@
     unregister: ->
         noKernel = "No kernel reference found"
         noRouter = "Could not access the router"
-        unreg = "Unregistering the %s service"
+        unreg = "Unregistering the %s service".yellow
         throw new Error(noKernel) unless @kernel?
         registry = @kernel.router?.registry
         throw new Error(noRouter) unless registry?


fix a minor oversight

fix a minor oversight

--- library/membrane/duplex.coffee
+++ library/membrane/duplex.coffee
@@ -281,7 +281,7 @@
     # that intercept specific events and log the output to a console.
     # Can be overriden to provide more meaningful feedback handlers.
     socketFeedback: external ->
-        c = "an error raised during socket connection: %s"
+        c = "an error raised during socket connection:"
         p = "an exception happend at the server provider:"
         connected = "established connection at #{@location}"
         reconnect = "attempting to reconnect at #{@location}"


Fix misnomer

Fix misnomer

--- library/membrane/visual.coffee
+++ library/membrane/visual.coffee
@@ -232,7 +232,7 @@
         noPrelude = "no prelude method detected"
         assert _.isFunction(@prelude), noPrelude
         assert _.isObject context = stock or {}
-        @extendContext.call this, context, symbol
+        @energizeContext.call @, context, symbol
         prelude = @upstreamAsync "prelude", =>
             assert @deployContext context, symbol
             assert @inlineAutocalls context, symbol
@@ -247,7 +247,7 @@
     # with all the commodities that should be present on contexts.
     # This includes utilitiy methods and member definitions that all
     # of the internal and external codebase depends and relies on.
-    extendContext: (context, symbol) ->
+    energizeContext: (context, symbol) ->
         append = -> _.extend context, arguments...
         append styles: [], sheets: [], changes: []
         append externals: [], invokes: [], sources: []


don't use the $-style ctor vars

don't use the $-style ctor vars

--- library/nucleus/restful.coffee
+++ library/nucleus/restful.coffee
@@ -67,7 +67,7 @@
     # Especially useful for service with the same resource but with
     # different conditions, such as mobile only and desktop only.
     @condition: (synopsis, limitation) ->
-        return @$condition if arguments.length is 0
+        return @conditions if arguments.length is 0
         limitation = _.find arguments, _.isFunction
         generic = "service condition: #{limitation}"
         synopsis = generic unless _.isString synopsis
@@ -76,8 +76,8 @@
         assert _.isString(synopsis), "got no synopsis"
         assert _.isFunction(limitation), noLimitation
         assert limitation.length >= 3, wrongSignature
-        assert _.isArray inherited = @$condition or []
-        return @$condition = inherited.concat
+        assert _.isArray inherited = @conditions or []
+        return @conditions = inherited.concat
             limitation: limitation
             synopsis: synopsis