Moved duplicate options to helper method

--- core/app/backbone/views/evidence/vote_up_down_view.coffee
+++ core/app/backbone/views/evidence/vote_up_down_view.coffee
@@ -61,16 +61,20 @@
   on_down_vote: ->
     @open_vote_down_popup()

+  default_popover_options: ->
+    side: 'right'
+    align: 'top'
+
   open_vote_up_popup: ->
     return if @_up_is_opened

     @close_vote_down_popup() if @_down_is_opened
     @_up_is_opened = true

-    @popoverAdd '.supporting',
-      side: 'right'
-      align: 'top'
-      contentView: @fact_relation_vote_up_view()
+    popover_options = _.extend {}, @default_popover_options(),
+                               contentView: @fact_relation_vote_up_view()
+
+    @popoverAdd '.supporting', popover_options

   fact_relation_vote_up_view: ->
     view = new FactRelationVoteUpView model: @model
@@ -85,10 +89,10 @@
     @close_vote_up_popup() if @_up_is_opened
     @_down_is_opened = true

-    @popoverAdd '.weakening',
-      side: 'right'
-      align: 'top'
-      contentView: @fact_relation_vote_down_view()
+    popover_options = _.extend {}, @default_popover_options(),
+                               contentView: @fact_relation_vote_down_view()
+
+    @popoverAdd '.weakening', popover_options

   fact_relation_vote_down_view: ->
     view = new FactRelationVoteDownView model: @model


Add assertion for truncated search results.

--- spec/javascripts/lib/mobile/autocomplete_mobile_spec.js.coffee
+++ spec/javascripts/lib/mobile/autocomplete_mobile_spec.js.coffee
@@ -227,6 +227,7 @@
           expect(list.tagName).toBe('UL')
           expect(list.className).toBe('autocomplete__results')
           expect(list.childNodes.length).toBe(1)
+          expect(listItem.textContent).toBe(SEARCH_RESULTS[0].title)

         it 'should create an unordered list no items when the results list is empty', ->
           list = @myAutoComplete._createList EMPTY_RESULTS


asserted the confirmation msg in test

asserted the confirmation msg in test

--- spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
+++ spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
@@ -822,6 +822,7 @@
       $scope.dirtyProducts = {}
       $httpBackend.expectDELETE("/api/v0/products/13").respond 200, "data"
       $scope.deleteProduct $scope.products[1]
+      expect(window.confirm).toHaveBeenCalledWith "Are you sure?"
       $httpBackend.flush()

     it "removes the specified product from both $scope.products and $scope.dirtyProducts (if it exists there)", ->


Fixed guidance in client

Fixed guidance in client

'false' seems to be truthy in javascript.

--- core/app/backbone/controllers/client_controller.coffee
+++ core/app/backbone/controllers/client_controller.coffee
@@ -7,7 +7,7 @@
   newFact: (params={}) => #(layout, fact_text, title, url, site_id) =>
     csrf_token = $('meta[name=csrf-token]').attr('content')

-    FactlinkApp.guided = params.guided
+    FactlinkApp.guided = params.guided == 'true'

     factsNewView = new FactsNewView
       layout: 'client'


fix unit tests

fix unit tests

--- test/unit/coffee/RedisManager/RedisManagerTests.coffee
+++ test/unit/coffee/RedisManager/RedisManagerTests.coffee
@@ -551,7 +551,7 @@
 	describe "removeDocFromMemory", ->
 		beforeEach (done) ->
 			@rclient.del = sinon.stub()
-			@rclient.srem = sinon.stub().yields()
+			@rclient.srem = sinon.stub()
 			@rclient.exec.yields()
 			@RedisManager.removeDocFromMemory @project_id, @doc_id, done


fix(keybase): Minor linter errors

fix(keybase): Minor linter errors


Removed debugging information

Removed debugging information

--- public/scripts/backbone-schedule/models/section.coffee
+++ public/scripts/backbone-schedule/models/section.coffee
@@ -20,7 +20,6 @@
         for prop, val of res
           @set(prop, val) if prop isnt 'id'
         @trigger 'seatsUpdated'
-        console.log 'updated seats from socket'

     __rnd: (seed = Date.now()) ->
       ((seed*9301+49297) % 263212) / (263212.0)


Parsed arguments to query

Parsed arguments to query

--- source/Commander.coffee
+++ source/Commander.coffee
@@ -5,3 +5,6 @@

 # Fetch arguments
 components = require('minimist')(process.argv.slice(2))
+
+# Combine arguments to single string
+specs = components['_'].join(' ')


removed logging

removed logging

--- coffee/src/shells/videolink.shell.coffee
+++ coffee/src/shells/videolink.shell.coffee
@@ -305,7 +305,6 @@
     if seekOffset?
       seekOffset = Math.min(seekOffset, @model.timeEnd() - 2)
       seekOffset = Math.max(@model.timeStart(), seekOffset)
-      console.log 'seekOffset: ' + seekOffset
       @mediaView.seek seekOffset

     @eventhub.trigger 'change:shell', @model, @


videoLinkShell: play on input change unless paused

in remixView, play video whenever an input changes unless video has been
explicitly paused by the user. when player is in state 'end', for
instance, play should start upon changing an input

--- coffee/src/shells/videolink.shell.coffee
+++ coffee/src/shells/videolink.shell.coffee
@@ -349,6 +349,10 @@

     @model.set changes

+    # unless user paused the video, make sure it is playing
+    unless @_playerView.isInState 'pause'
+      @_playerView.play()
+
     # when playing, rewind a bit to see the "end"
     if seekOffset is @model.timeEnd() and @_playerView.isPlaying()
       seekOffset = Math.max(seekOffset - 2, @model.timeStart())


remove workaround for parseHelp()

remove workaround for parseHelp()

--- test/scripts/hello.coffee
+++ test/scripts/hello.coffee
@@ -12,7 +12,7 @@
     @robot = new Robot(path.resolve(__dirname, '..'), 'shell', false, 'hubot')
     @robot.adapter.on 'connected', =>
       @robot.load path.resolve(__dirname, '../../src/scripts')
-      setTimeout done, 10 # wait for parseHelp()
+      done()
     @robot.run()

   afterEach (done) ->


ACE -> ACE3

ACE -> ACE3

--- snippets/language-sqf.cson
+++ snippets/language-sqf.cson
@@ -164,7 +164,7 @@
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#3-1-function-definitions'

   # ACE3 Event system
-  'ACE addEventHandler':
+  'ACE3 addEventHandler':
     'prefix': 'addEventHandler_ace'
     'body': """
       ["${1:Event name}", ${2:code}] call EFUNC(common,addEventhandler);
@@ -172,7 +172,7 @@
     'description': 'adds an event handler with the event name and returns the event handler id'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE removeEventHandler':
+  'ACE3 removeEventHandler':
     'prefix': 'removeEventHandler_ace'
     'body': """
       ["${1:Event name}", ${2:eventId}] call EFUNC(common,removeEventHandler);
@@ -180,7 +180,7 @@
     'description': 'Remove a specific event handler of the event name, using the ID returned from addEventhandler'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE removeAllEventHandlers':
+  'ACE3 removeAllEventHandlers':
     'prefix': 'removeAllEventHandlers_ace'
     'body': """
       ["${1:Event name}"] call EFUNC(common,removeAllEventHandlers);
@@ -188,7 +188,7 @@
     'description': 'Removes all Eventhandler for given type of event'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE Local Event':
+  'ACE3 Local Event':
     'prefix': 'localEvent_ace'
     'body': """
       ["${1:Event name}", [${2:Parameters}]] call EFUNC(common,localEvent);
@@ -196,7 +196,7 @@
     'description': 'Calls an event just on the local machine, useful for inter-module events'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE Server Event':
+  'ACE3 Server Event':
     'prefix': 'serverEvent_ace'
     'body': """
       ["${1:Event name}", [${2:Parameters}]] call EFUNC(common,serverEvent);
@@ -204,7 +204,7 @@
     'description': 'Calls an event just on the server computer (dedicated or self-hosted)'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE Global Event':
+  'ACE3 Global Event':
     'prefix': 'globalEvent_ace'
     'body': """
       ["${1:Event name}", [${2:Parameters}]] call EFUNC(common,globalEvent);
@@ -212,7 +212,7 @@
     'description': 'Calls an event with the listed args on all machines, the local machine, and the server'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE Target Event':
+  'ACE3 Target Event':
     'prefix': 'targetEvent_ace'
     'body': """
       ["${1:Event name}", ${2:Target(s)}, [${3:Parameters}]] call EFUNC(common,targetEvent);
@@ -220,7 +220,7 @@
     'description': 'Calls an event just on the targeted object or list of objects'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html'

-  'ACE addSyncedEventHandler':
+  'ACE3 addSyncedEventHandler':
     'prefix': 'addSyncedEventHandler_ace'
     'body': """
       ["${1:Event name}", ${2:code}, ${2:ttlNumberOrCodeBlock}] call EFUNC(common,addSyncedEventHandler);
@@ -228,7 +228,7 @@
     'description': 'Adds a globally synchronized event handler which will expire events after the provided TTL, or the code returns true.'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html#1-1-synchronized-events'

-  'ACE removeSyncedEventHandler':
+  'ACE3 removeSyncedEventHandler':
     'prefix': 'removeSyncedEventHandler_ace'
     'body': """
       ["${1:Event name}", ${2:eventId}] call EFUNC(common,removeSyncedEventHandler);
@@ -236,7 +236,7 @@
     'description': 'will remove a specific event handler of the event name, using the ID returned from addSyncedEventHandler'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/ace3-events-system.html#1-1-synchronized-events'

-  'ACE syncedEvent':
+  'ACE3 syncedEvent':
     'prefix': 'syncedEvent_ace'
     'body': """
       ["${1:Event name}", [${2:args}], ${3:ttlNumberOrCodeBlock}] call EFUNC(common,syncedEvent);


Use .explicit when deciding whether or not to add location data.

--- rewriter.coffee
+++ rewriter.coffee
@@ -195,12 +195,7 @@
   addLocationDataToGeneratedTokens: ->
     @scanTokens (token, i, tokens) ->
       tag = token[0]
-      # Some generated indentation isn't '.generated'.  We want to treet these and generated
-      # anyways, since everything needs a location data.  We don't want to just blindly add
-      # location data, though, since we want to find bugs.  :)
-      generated = token.generated or (token.explicit and (tag is 'INDENT' or tag is 'OUTDENT'))
-
-      if generated and not token.locationData
+      if (token.generated or token.explicit) and not token.locationData
         if i > 0
           prevToken = tokens[i-1]
           token.locationData =
@@ -221,7 +216,6 @@
   # blocks, so it doesn't need to. ')' can close a single-line block,
   # but we need to make sure it's balanced.
   addImplicitIndentation: ->
-
     starter = indent = outdent = null

     condition = (token, i) ->


fixed the while-loop-condition-with-implicit-function-call bug

--- rewriter.coffee
+++ rewriter.coffee
@@ -20,7 +20,8 @@

 # Tokens pairs that, in immediate succession, indicate an implicit call.
 IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END']
-IMPLICIT_END:  ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'OUTDENT']
+IMPLICIT_BLOCK:['->', '=>', '{', '[', ',']
+IMPLICIT_END:  ['IF', 'UNLESS', 'FOR', 'WHILE', 'TERMINATOR', 'INDENT', 'OUTDENT']
 IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',
                  'TRY', 'DELETE', 'TYPEOF', 'SWITCH',
                  'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT',
@@ -140,18 +141,22 @@
 re::add_implicit_parentheses: ->
   stack: [0]
   @scan_tokens (prev, token, post, i) =>
-    stack.push(0) if token[0] is 'INDENT'
-    if token[0] is 'OUTDENT'
+    tag: token[0]
+    stack.push(0) if tag is 'INDENT'
+    if tag is 'OUTDENT'
       last: stack.pop()
       stack[stack.length - 1] += last
-    if stack[stack.length - 1] > 0 and (IMPLICIT_END.indexOf(token[0]) >= 0 or !post?)
-      idx: if token[0] is 'OUTDENT' then i + 1 else i
-      for tmp in [0...stack[stack.length - 1]]
-        @tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
-      size: stack[stack.length - 1] + 1
-      stack[stack.length - 1]: 0
-      return size
-    return 1 unless prev and IMPLICIT_FUNC.indexOf(prev[0]) >= 0 and IMPLICIT_CALL.indexOf(token[0]) >= 0
+    if IMPLICIT_END.indexOf(tag) >= 0 or !post?
+      return 1 if tag is 'INDENT' and prev and IMPLICIT_BLOCK.indexOf(prev[0]) >= 0
+      if stack[stack.length - 1] > 0 or tag is 'INDENT'
+        idx: if tag is 'OUTDENT' then i + 1 else i
+        stack_pointer: if tag is 'INDENT' then 2 else 1
+        for tmp in [0...stack[stack.length - stack_pointer]]
+          @tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
+        size: stack[stack.length - stack_pointer] + 1
+        stack[stack.length - stack_pointer]: 0
+        return size
+    return 1 unless prev and IMPLICIT_FUNC.indexOf(prev[0]) >= 0 and IMPLICIT_CALL.indexOf(tag) >= 0
     @tokens.splice(i, 0, ['CALL_START', '(', token[2]])
     stack[stack.length - 1] += 1
     return 2
@@ -196,7 +201,7 @@
       throw "too many " + token[1] if levels[open] < 0
     return 1
   unclosed: key for key, value of levels when value > 0
-  throw "unclosed " + unclosed[0] if unclosed.length
+  throw new Error("unclosed " + unclosed[0]) if unclosed.length

 # We'd like to support syntax like this:
 #    el.click((event) ->


be more flexible about trailing commas in implicit object literals.

--- rewriter.coffee
+++ rewriter.coffee
@@ -133,9 +133,9 @@
       after  = @tokens[i + 2]
       open   = stack[len] > 0
       if (tag is 'TERMINATOR' and not ((after and after[0] is ':') or (post and post[0] is '@' and @tokens[i + 3] and @tokens[i + 3][0] is ':'))) or
-          (running and tag is ',' and post and (post[0] not in ['IDENTIFIER', 'STRING', '@']))
+          (running and tag is ',' and post and (post[0] not in ['IDENTIFIER', 'STRING', '@', 'TERMINATOR']))
         running = no
-        return closeBrackets(i)
+        return closeBrackets(if post and post[0] is 'OUTDENT' then i + 1 else i)
       else if include EXPRESSION_START, tag
         stack.push(if tag is '{' then 1 else 0)
         return 2 if tag is '{' and post and post[0] is 'INDENT'


refactor to simplify scanTokens method in Rewriter.

--- rewriter.coffee
+++ rewriter.coffee
@@ -50,7 +50,7 @@
     i = 0
     loop
       break unless @tokens[i]
-      move = block @tokens[i - 1], @tokens[i], @tokens[i + 1], i
+      move = block @tokens[i], i
       i += move
     true

@@ -68,9 +68,9 @@
   # Massage newlines and indentations so that comments don't have to be
   # correctly indented, or appear on a line of their own.
   adjustComments: ->
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
       return 1 unless token[0] is 'HERECOMMENT'
-      [before, after] = [@tokens[i - 2], @tokens[i + 2]]
+      [before, prev, post, after] = [@tokens[i - 2], @tokens[i - 1], @tokens[i + 1], @tokens[i + 2]]
       if after and after[0] is 'INDENT'
         @tokens.splice i + 2, 1
         if before and before[0] is 'OUTDENT' and post and prev[0] is post[0] is 'TERMINATOR'
@@ -95,15 +95,15 @@
   # Some blocks occur in the middle of expressions -- when we're expecting
   # this, remove their trailing newlines.
   removeMidExpressionNewlines: ->
-    @scanTokens (prev, token, post, i) =>
-      return 1 unless post and include(EXPRESSION_CLOSE, post[0]) and token[0] is 'TERMINATOR'
+    @scanTokens (token, i) =>
+      return 1 unless include(EXPRESSION_CLOSE, @tag(i + 1)) and token[0] is 'TERMINATOR'
       @tokens.splice i, 1
       return 0

   # The lexer has tagged the opening parenthesis of a method call. Match it with
   # its paired close.
   closeOpenCalls: ->
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
       if token[0] is 'CALL_START'
         condition = (token, i) -> token[0] in [')', 'CALL_END']
         action    = (token, i) -> token[0] = 'CALL_END'
@@ -113,7 +113,7 @@
   # The lexer has tagged the opening parenthesis of an indexing operation call.
   # Match it with its paired close.
   closeOpenIndexes: ->
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
       if token[0] is 'INDEX_START'
         condition = (token, i) -> token[0] in [']', 'INDEX_END']
         action    = (token, i) -> token[0] = 'INDEX_END'
@@ -124,16 +124,15 @@
   # Insert the missing braces here, so that the parser doesn't have to.
   addImplicitBraces: ->
     stack = []
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
       if include EXPRESSION_START, token[0]
-        stack.push(if (token[0] is 'INDENT' and (prev and prev[0] is '{')) then '{' else token[0])
+        stack.push(if (token[0] is 'INDENT' and (@tag(i - 1) is '{')) then '{' else token[0])
       if include EXPRESSION_END, token[0]
         stack.pop()
       last = stack[stack.length - 1]
-      before = @tokens[i - 2]
       if token[0] is ':' and (not last or last[0] isnt '{')
         stack.push '{'
-        idx = if before and before[0] is '@' then i - 2 else i - 1
+        idx = if @tag(i - 2) is '@' then i - 2 else i - 1
         @tokens.splice idx, 0, ['{', '{', token[2]]
         condition = (token, i) ->
           [one, two, three] = @tokens.slice(i + 1, i + 4)
@@ -150,15 +149,15 @@
   # Insert the implicit parentheses here, so that the parser doesn't have to
   # deal with them.
   addImplicitParentheses: ->
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
+      prev = @tokens[i - 1]
       if prev and prev.spaced and include(IMPLICIT_FUNC, prev[0]) and include(IMPLICIT_CALL, token[0]) and
-          not (token[0] is '!' and (post[0] in ['IN', 'OF']))
+          not (token[0] is '!' and (@tag(i + 1) in ['IN', 'OF']))
         @tokens.splice i, 0, ['CALL_START', '(', token[2]]
         condition = (token, i) ->
-          [before, prev] = @tokens.slice(i - 2, i + 1)
           (not token.generated and @tokens[i - 1][0] isnt ',' and include(IMPLICIT_END, token[0]) and
-            not (token[0] is 'INDENT' and (include(IMPLICIT_BLOCK, prev[0]) or before[0] is 'CLASS'))) or
-            token[0] is 'PROPERTY_ACCESS' and prev[0] is 'OUTDENT'
+            not (token[0] is 'INDENT' and (include(IMPLICIT_BLOCK, @tag(i - 1)) or @tag(i - 2) is 'CLASS'))) or
+            token[0] is 'PROPERTY_ACCESS' and @tag(i - 1) is 'OUTDENT'
         action = (token, i) ->
           idx = if token[0] is 'OUTDENT' then i + 1 else i
           @tokens.splice idx, 0, ['CALL_END', ')', token[2]]
@@ -171,16 +170,16 @@
   # blocks, so it doesn't need to. ')' can close a single-line block,
   # but we need to make sure it's balanced.
   addImplicitIndentation: ->
-    @scanTokens (prev, token, post, i) =>
-      if token[0] is 'ELSE' and prev[0] isnt 'OUTDENT'
+    @scanTokens (token, i) =>
+      if token[0] is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
         @tokens.splice i, 0, @indentation(token)...
         return 2
       if token[0] is 'CATCH' and
           (@tokens[i + 2][0] is 'TERMINATOR' or @tokens[i + 2][0] is 'FINALLY')
         @tokens.splice i + 2, 0, @indentation(token)...
         return 4
-      if include(SINGLE_LINERS, token[0]) and post[0] isnt 'INDENT' and
-          not (token[0] is 'ELSE' and post[0] is 'IF')
+      if include(SINGLE_LINERS, token[0]) and @tag(i + 1) isnt 'INDENT' and
+          not (token[0] is 'ELSE' and @tag(i + 1) is 'IF')
         starter = token[0]
         [indent, outdent] = @indentation token
         indent.generated = outdent.generated = true
@@ -201,7 +200,7 @@
   ensureBalance: (pairs) ->
     levels   = {}
     openLine = {}
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
       for pair in pairs
         [open, close] = pair
         levels[open] or= 0
@@ -237,7 +236,7 @@
     stack = []
     debt  = {}
     (debt[key] = 0) for key, val of INVERSES
-    @scanTokens (prev, token, post, i) =>
+    @scanTokens (token, i) =>
       tag = token[0]
       inv = INVERSES[token[0]]
       if include EXPRESSION_START, tag
@@ -268,6 +267,10 @@
   indentation: (token) ->
     [['INDENT', 2, token[2]], ['OUTDENT', 2, token[2]]]

+  # Look up a tag by token index.
+  tag: (i) ->
+    @tokens[i] and @tokens[i][0]
+
 # Constants
 # ---------


fixing again

fixing again

--- app/coffee/metamenu.coffee
+++ app/coffee/metamenu.coffee
@@ -146,10 +146,10 @@

           if $('#entry_view_preference_attributes_image_id').attr('name')?
             $('#entry_view_preference_attributes_image_id').val($(event.currentTarget).data('id'))
+          else if $('#show_entry_mode').attr('name')?
+            @updateEntryBedsheet($('#showEntry').data('id'),$(event.currentTarget).data('id'))
           else
             @updateUserBedsheet($(event.currentTarget).data('id'))
-          if $('#show_entry_mode').attr('name')?
-            @updateEntryBedsheet($('#showEntry').data('id'),$(event.currentTarget).data('id'))
         )

   updateUserBedsheet: (@bedsheet_id)->


Order args.

Order args.

--- app/client/js/routes/store.coffee
+++ app/client/js/routes/store.coffee
@@ -7,17 +7,17 @@

   ###*
     @param {app.Actions} actions
-    @param {este.Dispatcher} dispatcher
     @param {app.Routes} routes
     @param {app.Storage} storage
-    @param {este.Router} router
     @param {app.songs.Store} songsStore
     @param {app.users.Store} usersStore
+    @param {este.Dispatcher} dispatcher
+    @param {este.Router} router
     @constructor
     @extends {este.Store}
   ###
-  constructor: (@actions, @dispatcher, @routes, @storage, @router,
-      @songsStore, @usersStore) ->
+  constructor: (@actions, @routes, @storage, @songsStore, @usersStore,
+      @dispatcher, @router) ->

     @dispatcher.register (action, payload) =>
       switch action


reject empty talk comments

reject empty talk comments

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -29,7 +29,7 @@
     '#tutorial'                         : 'tutorialButton'
     'numbers-container'                 : 'numbersContainer'
     '#classify-summary'                 : 'classifySummary'
-    '#comments'                         : 'comments'
+    '#comments'                         : 'commentsContainer'
     '#planet-num'                       : 'planetNum'
     '#alt-comments'                     : 'altComments'
     'button[name="no-transits-button"]' : 'noTransitsButton'
@@ -732,22 +732,6 @@
     $(".guest_obs .guest_obs_desc").html(cont.description)
     $(".guest_obs .guest_obs_img").attr("src",cont.example)

-  onClickJoinConvo: ->
-    @joinConvoBtn.hide().siblings().show()
-
-  onClickSubmitTalk: ->
-    console.log "SEND THIS TO MAIN TALK DISCUSSION", @talkComment.val()
-    @appendComment(@talkComment, @comments)
-
-  appendComment: (comment, container) ->
-    container.append("""
-

-
#{comment.val()}

-
by #{'currentUser'} 0 minutes ago

-

-    """).animate({ scrollTop: container[0].scrollHeight}, 1000)
-    @resetTalkComment comment
-
   onChangeScaleSlider: ->
     @canvasGraph.sliderValue = +@el.find("#ui-slider").val()
     @canvasGraph.plotPoints( @canvasGraph.sliderValue, @canvasGraph.sliderValue + @canvasGraph.zoomRanges[@canvasGraph.zoomLevel] )
@@ -811,18 +795,37 @@
   showZoomMessage: (message) =>
     @el.find('#zoom-notification').html(message).fadeIn(100).delay(1000).fadeOut()

+
+  #
+  # BEGIN TALK COMMENT METHODS
+  #
+
+  onClickJoinConvo: ->
+    @joinConvoBtn.hide().siblings().show()
+
+  onClickSubmitTalk: ->
+    return if @talkComment.val() is "" # reject empty comments
+    @appendComment(@talkComment, @commentsContainer)
+    @talkComment.val('')
+
+  appendComment: (comment, container) ->
+    container.append("""
+

+
#{comment.val()}

+
by You

+

+    """).animate({ scrollTop: container[0].scrollHeight}, 1000)
+
   onCommentsFetch: ({discussion}) =>
     @comments = discussion.comments

-    commentsContainer = @el.find '#comments'
     for comment in @comments
-      commentsContainer.append """
-

-
#{comment.body}

-
by #{comment.user_name} #{comment.created_at}

-

-
-      """
+      @commentsContainer.append("""
+

+
#{comment.body}

+
by #{comment.user_name} #{comment.created_at}

+

+      """).animate({ scrollTop: container[0].scrollHeight}, 1000)

     #   comment.timeago = $.timeago comment.updated_at
     #   comment.date = DateWidget.formatDate 'd MM yy', new Date comment.updated_at
@@ -842,4 +845,8 @@
       @fetchComments()
     , @refresh * 1000 if @refresh?

+  #
+  # END TALK COMMENT METHODS
+  #
+
 module.exports = Classifier


clean up code

clean up code

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -613,13 +613,9 @@
         Subject.current?.destroy()
         subjects[0].select()
         Subject.group = MAIN_SUBJECT_GROUP
-        # @onSubjectSelect(null, subjects[0])
-
     else
       Subject.group = MAIN_SUBJECT_GROUP
       @Subject.next()
-
-

     @noTransitsButton.show()


fix: mark bounds not recorded (oops!)

fix: mark bounds not recorded (oops!)

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -299,10 +299,10 @@
     console.log 'YOU\'VE MARKED ', @course.count, ' LIGHT CURVES!'
     for mark, i in [@canvasGraph.marks.all...]
       @classification.annotations[i] =
-        xMinRelative: mark.dataXMin
-        xMaxRelative: mark.dataXMax
-        xMinGlobal: mark.dataMin + Math.round(@canvasGraph.originalMin)
-        xMaxGlobal: mark.dataMax + Math.round(@canvasGraph.originalMin)
+        xMinRelative: mark.dataXMinRel
+        xMaxRelative: mark.dataXMaxRel
+        xMinGlobal: mark.dataXMinGlobal
+        xMaxGlobal: mark.dataXMaxGlobal
     console.log JSON.stringify( @classification )
     @classification.send()
     @showSummary()


Remove FIRST_DATA_COLUMN

Remove FIRST_DATA_COLUMN

Not really sure why that's even a thing, doesn't seem like we should
offset the lookup.  The data comes in the order of columns

--- tutor/src/components/scores/student-data-sorter.coffee
+++ tutor/src/components/scores/student-data-sorter.coffee
@@ -1,16 +1,14 @@
 _ = require 'underscore'

-FIRST_DATA_COLUMN = 2

 percent = (num, total) ->
   Math.round((num / total) * 100) or 0

-getSortValue = (student, key, dataType, displayAs) ->
+getSortValue = (student, index, dataType, displayAs) ->

-  return (student.last_name or student.name).toLowerCase() unless _.isNumber(key)
+  return (student.last_name or student.name).toLowerCase() unless _.isNumber(index)

-  index = key - FIRST_DATA_COLUMN
   record = student.data[index]
   return -1 unless record


Move bolus arrival bar into chart callback. Move style to stylesheet.

--- app/javascripts/directives.coffee
+++ app/javascripts/directives.coffee
@@ -25,39 +25,6 @@
         scope.spinner.spin(element[0])
       else if scope.spinner
         scope.spinner.stop()
-
-
-# Places a bolus arrival bar on the current graph element.
-directives.directive 'qiBolusArrival', () ->
-  restrict: 'E'
-  link: (scope, element, attrs) ->
-    # The intensity graph.
-    chart = element.parent().find('nvd3-line-chart.qi-intensity-chart')[0]
-    # Wait for the session detail to be fetched.
-    scope.deferred_session.then (sess) ->
-      # The chart axis tick marks start after the axis legend.
-      # Therefore, the plot width is the chart width minus the y-axis
-      # legend width and the plot height is the chart height minus the
-      # data series legend and the x-axis legend.
-      bar_width = element[0].clientWidth
-      # The chart is positioned based on the parent CSS margin.
-      chart_left = parseFloat(element.parent().css('marginLeft'))
-      # The plot offset relative to the parent chart element.
-      plot_offset = {left: 65, top: 29, bottom: 48, right: 35}
-      plot =
-        offset: plot_offset
-        width: chart.clientWidth - plot_offset.left - plot_offset.right
-        height: chart.clientHeight - plot_offset.top - plot_offset.bottom
-      delta = plot.width / (sess.scan.intensity.intensities.length - 1)
-      # The amount to shift the bar to the right from the origin.
-      shift = sess.bolus_arrival_index * delta
-      # Position the bar.
-      element.offset(
-        top: chart.offsetTop + plot.offset.top
-        left: chart_left + plot.offset.left - (bar_width / 2) + shift
-      )
-      # The bar runs along the plot y axis.
-      element.height(plot.height)

 # Displays a modeling chart.
@@ -110,7 +77,7 @@
     hrefs =
       scope.href(obj) for obj in data

-    Helpers.d3Hyperlink(top, hrefs, fill: 'Peru')
+    Helpers.d3Hyperlink(top, hrefs)

   # Make the directive.
   restrict: 'E'


minor obsolete comment

minor obsolete comment

--- fizzylogo_populateMethods.coffee
+++ fizzylogo_populateMethods.coffee
@@ -185,7 +185,6 @@
     commonPropertyAccessFunction

-  # TODO I think method body should NOT be quoted
   classToAddThemTo.addMethod \
     (flTokenize "answer: ( ' signature ) by ( methodBody )"),
     (context) ->


Move success handler to a new function

Move success handler to a new function

--- vendor/assets/javascripts/brainstem/data-loader.coffee
+++ vendor/assets/javascripts/brainstem/data-loader.coffee
@@ -49,33 +49,7 @@
       data: {}
       parse: true
       error: @loadOptions.error
-      success: (resp, status, xhr) =>
-        # The server response should look something like this:
-        #  {
-        #    count: 200,
-        #    results: [{ key: "tasks", id: 10 }, { key: "tasks", id: 11 }],
-        #    time_entries: [{ id: 2, title: "te1", project_id: 6, task_id: [10, 11] }]
-        #    projects: [{id: 6, title: "some project", time_entry_ids: [2] }]
-        #    tasks: [{id: 10, title: "some task" }, {id: 11, title: "some other task" }]
-        #  }
-        # Loop over all returned data types and update our local storage to represent any new data.
-
-        results = resp['results']
-        keys = _.reject(_.keys(resp), (key) -> key == 'count' || key == 'results')
-        unless _.isEmpty(results)
-          keys.splice(keys.indexOf(@loadOptions.name), 1) if keys.indexOf(@loadOptions.name) != -1
-          keys.push(@loadOptions.name)
-
-        for underscoredModelName in keys
-          @storageManager.storage(underscoredModelName).update _(resp[underscoredModelName]).values()
-
-        unless @loadOptions.cache == false || @loadOptions.only?
-          @storageManager.getCollectionDetails(@loadOptions.name).cache[@loadOptions.cacheKey] = results
-
-        if @loadOptions.only?
-          @_success @loadOptions, @collection, _.map(@loadOptions.only, (id) => @cachedCollection.get(id))
-        else
-          @_success @loadOptions, @collection, _(results).map (result) -> base.data.storage(result.key).get(result.id)
+      success: @onLoadSuccess

     syncOptions.data.include = @loadOptions.include.join(",") if @loadOptions.include.length
     syncOptions.data.only = _.difference(@loadOptions.only, @alreadyLoadedIds).join(",") if @loadOptions.only?
@@ -101,6 +75,34 @@
       @loadOptions.returnValues.jqXhr = jqXhr

     @collection
+
+  onLoadSuccess: (resp, status, xhr) =>
+    # The server response should look something like this:
+    #  {
+    #    count: 200,
+    #    results: [{ key: "tasks", id: 10 }, { key: "tasks", id: 11 }],
+    #    time_entries: [{ id: 2, title: "te1", project_id: 6, task_id: [10, 11] }]
+    #    projects: [{id: 6, title: "some project", time_entry_ids: [2] }]
+    #    tasks: [{id: 10, title: "some task" }, {id: 11, title: "some other task" }]
+    #  }
+    # Loop over all returned data types and update our local storage to represent any new data.
+
+    results = resp['results']
+    keys = _.reject(_.keys(resp), (key) -> key == 'count' || key == 'results')
+    unless _.isEmpty(results)
+      keys.splice(keys.indexOf(@loadOptions.name), 1) if keys.indexOf(@loadOptions.name) != -1
+      keys.push(@loadOptions.name)
+
+    for underscoredModelName in keys
+      @storageManager.storage(underscoredModelName).update _(resp[underscoredModelName]).values()
+
+    unless @loadOptions.cache == false || @loadOptions.only?
+      @storageManager.getCollectionDetails(@loadOptions.name).cache[@loadOptions.cacheKey] = results
+
+    if @loadOptions.only?
+      @_success @loadOptions, @collection, _.map(@loadOptions.only, (id) => @cachedCollection.get(id))
+    else
+      @_success @loadOptions, @collection, _(results).map (result) -> base.data.storage(result.key).get(result.id)

 class Brainstem.DataLoader
   constructor: (options = {}) ->


Scroll to top of thread when clicking lintel thread title

--- lineman/app/components/thread_lintel/thread_lintel.coffee
+++ lineman/app/components/thread_lintel/thread_lintel.coffee
@@ -2,12 +2,18 @@
   restrict: 'E'
   templateUrl: 'generated/components/thread_lintel/thread_lintel.html'
   replace: true
-  controller: ($scope, Records, ModalService, ProposalForm) ->
+  controller: ($scope, Records, ModalService, ProposalForm, CurrentUser, ScrollService) ->
     $scope.show = ->
       $scope.scrolled && $scope.currentComponent == 'threadPage'

+    $scope.scrollToThread = ->
+      ScrollService.scrollTo 'h1:first'
+
+    $scope.scrollToProposal = ->
+      ScrollService.scrollTo 'section.current-proposal-card'
+
     $scope.canStartProposal = ->
-      true
+      $scope.discussion && !$scope.discussion.hasActiveProposal() and CurrentUser.canStartProposals($scope.discussion)

     $scope.startProposal = ->
       ModalService.open ProposalForm, proposal: -> Records.proposals.initialize(discussion_id: $scope.discussion.id)


Emit event when op is acknowledged

Emit event when op is acknowledged

--- services/web/public/coffee/ide/editor/Document.coffee
+++ services/web/public/coffee/ide/editor/Document.coffee
@@ -309,6 +309,9 @@
 				@ide.pushEvent "op:acknowledged",
 					doc_id: @doc_id
 					op: op
+				@ide.$scope.$emit "ide:opAcknowledged",
+					doc_id: @doc_id
+					op: op
 				@trigger "op:acknowledged"
 			@doc.on "op:timeout", (op) =>
 				@ide.pushEvent "op:timeout",


Wrap bindingprovider and reload page on binding error

--- source/coffee/index.coffee
+++ source/coffee/index.coffee
@@ -232,5 +232,23 @@
         animation: false
       $(el).tooltip opts

+  # Custom binding provider with error handling
+  ErrorHandlingBindingProvider = ->
+    original = new ko.bindingProvider()
+
+    # Determine if an element has any bindings
+    @nodeHasBindings = original.nodeHasBindings
+
+    # Return the bindings given a node and the bindingContext
+    @getBindings = (node, bindingContext) ->
+      try
+        original.getBindings node, bindingContext
+      catch e
+        console.log "Error in binding: " + e.message, node
+        window.location = "/" # Reload page for now
+    @
+
+  ko.bindingProvider.instance = new ErrorHandlingBindingProvider()
+
   dashboard.indexModel = new IndexModel()
   ko.applyBindings dashboard.indexModel


Delay creating the filter bar until the translations are set up

The filter bar uses the translations, so we need to wait for them.

--- evesrp/static/js/main.coffee
+++ evesrp/static/js/main.coffee
@@ -19,13 +19,14 @@

 unless (jQuery '#mocha').length != 0
     ui.setupEvents()
-    ui.setupTranslations()
+    i18nPromise = ui.setupTranslations()
     if (jQuery '.entity-typeahead').length != 0
         division.setupEvents()
     if (jQuery '#actionMenu').length != 0
         request.setupEvents()
     if (jQuery '.filter-tokenfield').length != 0
-        filter.createFilterBar '.filter-tokenfield'
+        i18nPromise.done () ->
+            filter.createFilterBar '.filter-tokenfield'
     if (jQuery 'table#requests').length != 0
         requestList.setupEvents()
     if (jQuery 'div#requests').length != 0


ENHANCE: Load teaching periods in root controller

--- src/app/config/root-controller/root-controller.coffee
+++ src/app/config/root-controller/root-controller.coffee
@@ -3,7 +3,7 @@
 #
 # The Doubtfire root application controller
 #
-.controller("AppCtrl", ($rootScope, $state, $document, $filter, ExternalName) ->
+.controller("AppCtrl", ($rootScope, $state, $document, $filter, ExternalName, TeachingPeriod) ->

   # Automatically localise page titles
   # TODO: (@alexcu) consider putting this in a directive?
@@ -18,4 +18,7 @@
   # Get the confugurable, external name of Doubtfire
   $rootScope.externalName = ExternalName

+  # Ensure that teaching periods are loaded
+  TeachingPeriod.query()
+
 )


Bump to v3.0.0-beta2

Bump to v3.0.0-beta2

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -1,5 +1,5 @@
-POI_VERSION = '2.2.0'
-ELECTRON_VERSION = '0.28.2'
+POI_VERSION = '3.0.0-beta2'
+ELECTRON_VERSION = '0.29.2'
 SYSTEM_BIT =
   win32: 'ia32'
   linux: 'x64'


Add outFile option

Add outFile option

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -34,6 +34,7 @@
       debugDirectory: 'debug'
     .pipe mocha()
     .pipe cover.report
+      outFile: 'coverage.html'
       reporter: 'html'

 gulp.task 'coveralls', (done) ->


add css:clean to build task

add css:clean to build task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -33,12 +33,13 @@
 # high level tasks
 # =================================================================
 gulp.task "build", (cb)->
-  return runSequence  ['build:clean', 'css:clean', 'js:clean'],
+  return runSequence  ['build:clean', 'js:clean'],
                       ['css:build','js:build'],
                       'build_wintersmith',
                       ['css:rev','js:rev'],
                       'ref:all',
                       'rev:clean',
+                      'css:clean',
                        cb

 gulp.task "preview", (cb)->
@@ -296,7 +297,7 @@
 # experiments
 # =================================================================

-gulp.task "css_clean", ->
+gulp.task "css:clean", ->
   return gulp.src('build/css/*.css')
     .pipe(uncss(
       html: ['build/*/*.html', 'build/index.html', "!build/blog"]


Updated gulpfile

Updated gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -151,7 +151,6 @@
       host: null
       port: "#{port}"
       root: "#{output}"
-      #livereload: true

@@ -282,7 +281,7 @@
    "stylus"
    "bower"
    "concat"
-   #"test"
+   "test"
    "connect"
    "watch"
 ]


chore(build): fix overwriting of scripts and styles constants

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -175,8 +175,8 @@
 			p.replace regex, '/'

 	includify = ->
-		scripts = []
-		styles = []
+		js = []
+		css = []

 		bufferContents = (file) ->
 			return if file.isNull()
@@ -185,14 +185,15 @@
 			p = unixifyPath(path.join('/', path.relative(file.cwd, file.path)))

 			return if ext is '.js'
-				scripts.push p
+				js.push p

 			return if ext is '.css'
-				styles.push p
+				css.push p

 		endStream = ->
-			@emit 'data', {scripts, styles}
-			@emit 'end', {scripts, styles}
+			payload = {scripts: js, styles: css}
+			@emit 'data', payload
+			@emit 'end', payload

 		es.through bufferContents, endStream

@@ -260,6 +261,4 @@
 		.watch "#{srcDirectory}**", ['dist']

 gulp.task 'dist', ['build'], ->
-	gulp
-		.src "#{distDirectory}**"
-		.pipe connect.reload()+	connect.reload()


Library urls were wrong

Library urls were wrong

--- app/js/search/index.coffee
+++ app/js/search/index.coffee
@@ -59,7 +59,7 @@
       $scope.lib = res

     $scope.file_url = ->
-      "//cdn.jsdelivr.net/#{@lib.selected_version}/#{@file}"
+      "//cdn.jsdelivr.net/#{@lib.name}/#{@lib.selected_version}/#{@file}"

   .controller 'SearchCtrl', ($scope, $location, Library) ->


all + 48h

all + 48h

--- modules/userFactory.coffee
+++ modules/userFactory.coffee
@@ -2,8 +2,8 @@
 config = require 'cnf'
 mongoose = require 'mongoose'

-humanBaseTimeH = 24
-zombieBaseTimeH = 24
+humanBaseTimeH = 24 + 48
+zombieBaseTimeH = 24 + 48

 userFactory = (user) ->
 	moment


FIX: misspelled 'throw' - still would have thrown an error, just not the right one

--- source/Art/Engine/Core/Drawing/ElementDrawMixin.coffee
+++ source/Art/Engine/Core/Drawing/ElementDrawMixin.coffee
@@ -714,7 +714,7 @@
       @_drawCacheToElementMatrix = d2eMatrix
       @_elementToDrawCacheMatrix = @_drawCacheToElementMatrix.inv

-      thrwo new Error "why no elementToTargetMatrix?" unless elementToTargetMatrix
+      throw new Error "why no elementToTargetMatrix?" unless elementToTargetMatrix
       clippedElementSpaceDrawArea = elementToTargetMatrix.inv.transformBoundingRect(targetSpaceDrawArea).roundOut(snapTo, colorPrecision).intersection elementSpaceDrawArea

       remainingDirtyAreas = null


Make keyCode undefined when 0

Make keyCode undefined when 0

0 is the default but it should really be undefined since the null key
is invalid.

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -30,6 +30,8 @@
   dispatchKeyboardEvent = (target, eventArgs...) ->
     e = document.createEvent('KeyboardEvent')
     e.initKeyboardEvent eventArgs...
+    # 0 is the default, and it's valid ASCII, but it's wrong.
+    Object.defineProperty(e, 'keyCode', get: -> undefined) if e.keyCode is 0
     target.dispatchEvent e

   dispatchTextEvent = (target, eventArgs...) ->


Require wrapper lib in spec

Require wrapper lib in spec

--- spec/writer_spec.coffee
+++ spec/writer_spec.coffee
@@ -1,4 +1,4 @@
-genx = require '../build/default/genx'
+genx = require '../lib/genx'

 describe 'genx', ->


resurrection activity: change limit option to 20

--- workers/social/lib/social/models/graph/activity.coffee
+++ workers/social/lib/social/models/graph/activity.coffee
@@ -171,12 +171,14 @@
   @fetchFolloweeContentsForNewKoding = (options={}, callback)->
     @getExemptUsersClauseIfNeeded options, (err, exemptClause)=>
       @getCurrentGroup options.client, (err, currentGroup)=>
-        {limit, skip, userId} = options
+        {limit, skip, client} = options
+        {connection:{delegate}} = client
+
         queryOptions =
-          limitCount : limit or 10
+          limitCount : limit or 20
           skipCount  : skip or 0
           groupName  : currentGroup.slug or "koding"
-          userId     : userId
+          userId     : delegate.getId()

         query = QueryRegistry.activity.followingnew exemptClause
         @fetch query, queryOptions, (err, results) =>


Simplify getting text from a paragraph, document IE limitation

--- js-library/app/js/jail_iframe/classes/icon_buttons.coffee
+++ js-library/app/js/jail_iframe/classes/icon_buttons.coffee
@@ -126,16 +126,11 @@

 textFromElement = (element) ->
   selection = document.getSelection()
+  selection.selectAllChildren(element)
+  text = selection.toString()
+  # note: IE11's toString includes invisible text content such as display:none stuff. no idea how to fix this bug
+
   selection.removeAllRanges()
-
-  range = document.createRange()
-  range.setStart element, 0
-  range.setEndAfter element
-
-  selection.addRange(range)
-  text = selection.toString()
-  selection.removeAllRanges()
-
   text.trim()


Added copy imgs task

Added copy imgs task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -14,7 +14,7 @@
 templates       = require 'gulp-angular-templatecache'
 uglify          = require "gulp-uglify"

-gulp.task "compile", ["clean", "compile-styles", "compile-scripts", "compile-views"]
+gulp.task "compile", ["clean", "compile-styles", "compile-scripts", "compile-views", "copy-imgs"]

 gulp.task "clean", ->
   gulp.src(["./dist/*.js", "./dist/*.css"],
@@ -25,6 +25,10 @@
 gulp.task "compile-styles", ->
   gulp.src("./app/**/*.css")
       .pipe gulp.dest("./dist/")
+
+gulp.task "copy-imgs", ->
+  gulp.src("./app/img/*.*" )
+  .pipe(gulp.dest("./dist/img"))

 gulp.task "compile-scripts", ->
   gulp.src([


Makes the release task depend on pack:all

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -123,7 +123,7 @@
   shelljs.exec 'open ./build/Messenger/osx64/Messenger.app'

 # Upload release to GitHub
-gulp.task 'release', (callback) ->
+gulp.task 'release', ['pack:all'], (callback) ->
   gulp.src './dist/*'
     .pipe $.githubRelease
       draft: true


refactor

refactor

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -26,12 +26,10 @@
   marked = require 'marked'
   site = myjekyll src, {}
   site.entries().map (entry) ->
-    date = moment entry.pubdate
-    dir = date.format 'YYYY/MM/DD'
     titleKey = entry.file.match(/^\d+-\d+-\d+-(.+)$/, '$1')[1]
-    entry:
+    entry =
       content: marked entry.content
-      date: date.format 'YYYY-MM-DD'
+      date: moment(entry.pubdate).format 'YYYY-MM-DD'
       description: entry.content.substring(0, 100)
       file: entry.file
       minutes: entry.minutes
@@ -39,11 +37,18 @@
       tags: entry.tags
       title: entry.title
       titleKey: titleKey
-    paths: [
-      dir + '/' + titleKey + '/index.html'
-      if titleKey is 'diary' then null else dir + '/diary/index.html'
-      dir + '/index.html'
-    ].filter (i) -> i
+    entry
+
+prerenderEntry = (entry) ->
+  dir = moment(entry.pubdate).format 'YYYY/MM/DD'
+  titleKey = entry.titleKey
+  paths = [
+    dir + '/' + titleKey + '/index.html'
+    if titleKey is 'diary' then null else dir + '/diary/index.html'
+    dir + '/index.html'
+  ].filter (i) -> i
+  paths.forEach (path) ->
+    prerender(baseDir + path, entry)

 ignoreError = (stream) ->
   stream.on 'error', (e) ->
@@ -77,16 +82,14 @@

 gulp.task 'build-html', ->
   baseDir = './dist/'
-  loadEntriesV3('./data/**/*.md').forEach ({ paths, entry }) ->
-    paths.forEach (path) ->
-      prerender(baseDir + path, entry)
+  loadEntriesV3('./data/**/*.md').forEach (entry) ->
+    prerenderEntry(baseDir, entry)
   prerender(baseDir + 'index.html', null)

 gulp.task 'build-html-dev', ->
   baseDir = './dist/'
-  loadEntriesV3('./data/nofile.md').forEach ({ paths, entry }) ->
-    paths.forEach (path) ->
-      prerender(baseDir + path, entry)
+  loadEntriesV3('./data/nofile.md').forEach (entry) ->
+    prerenderEntry(baseDir, entry)
   prerender(baseDir + 'index.html', null)

 gulp.task 'build-images', ->


updated settings

updated settings

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -35,7 +35,7 @@
 gulp.task 'browserify', ->
   browserify
       extensions: ['.coffee', '.js']
-    .transform coffeeify
+    .transform coffeeify, global: true
     .require(src.main, { expose: module.shortcut})
     .ignore('coffee-script')
     .bundle()


clean by default when running gulp

clean by default when running gulp

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -13,8 +13,8 @@
 testFiles   = jsFiles
 buildFiles  = ['lib', 'coverage']

-gulp.task 'clean', (cb) ->
-  del buildFiles, cb
+gulp.task 'clean', ->
+  del.sync buildFiles

 gulp.task 'lint', ->
   gulp.src coffeeFiles
@@ -40,4 +40,4 @@
         .pipe mocha reporter: 'nyan'
         .pipe istanbul.writeReports() # Creating the reports after tests run

-gulp.task 'default', ['test']
+gulp.task 'default', ['clean', 'test']


Increased timeout

Increased timeout

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -44,7 +44,12 @@
     linter.reporter("coffeelint-stylish")
   ).pipe(
     linter.reporter("failOnWarning")
-  ).pipe(mocha("reporter": "dot"))
+  ).pipe(
+    mocha(
+      "reporter": "dot"
+      "timeout": 5000
+    )
+  )

 g.task "it.server", (done) ->
   karma = require "./src/plugin"


Build: fixed accidentally overwritten buildDir

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -236,7 +236,6 @@
 gulp.task 'webserver', ['compile'], ->
   express = require 'express'
   app     = express()
-  buildDir = '/docs'

   app.use express.static "#{__dirname}/#{buildDir}"


resimplify test

resimplify test

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -80,14 +80,14 @@
         assert.notOk nav.children.length, 'Nav should have no children.'
         assert.end()
       test "Root-#{label}", (assert) ->
-        assert.plan 5     # don't know why, but otherwise tests exit w/o ending
         assert.is nav.root.title, 'Home', titleMsg
         assert.is nav.root.href, '..', hrefMsg
         assert.is nav.root.href, nav.root.root.href, hrefMsg
         assert.ok nav.root.hasActiveDescendant, activeDescendant
         assert.notOk nav.root.active, notActiveMsg
+        assert.end()
       test "No-Index", (assert) ->
-        assert.plan 1
         for uncle in nav.parent.siblings
           if uncle.title is 'Greek'
             assert.notOk uncle.href?, "Nav without index shouldn't have href"
+        assert.end()


small gulpfile update

small gulpfile update

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -31,10 +31,15 @@
 helpers = require('app/javascripts/shared/helpers')
 log = _.bind(helpers.log, logPrefix: '[gulp]')

+bundler = null # for watchify to avoid memory leaks
+lastBrowserified = 0
+

 #=========================================================================================
 # Settings
 #=========================================================================================
+RELOAD_TRIGGERS = ['rs', 'regulp']
+
 ASSETS_LOCATION = './public/assets'
 PUBLIC_LOCATION = './public'
 CORE_LOCATION = './app'
@@ -42,6 +47,8 @@
 JS_TRANSFORMS = ['coffeeify', 'jadeify', 'browserify-shim']
 MINIFIED_NAME = suffix: '.min'

+BROWSERIFY_RATELIMIT = 1000
+

 #=========================================================================================
 # Reporters
@@ -64,6 +71,7 @@
 # Compilers
 #=========================================================================================
 compileJavascripts = (src, options)->
+  bundler.close?() if bundler
   args = [src, extensions: ['.coffee', '.jade']]
   bundler = if options.watch then watchify(args...) else browserify(args...)

@@ -72,6 +80,10 @@

   compile = (files)->
     startTime = Date.now()
+
+    return if startTime - lastBrowserified < BROWSERIFY_RATELIMIT
+    lastBrowserified = startTime
+
     watchReporter(path: file, type: 'changed') for file in files if files

     bundler.bundle(debug: config.source_maps)
@@ -192,6 +204,16 @@

   processJavascripts(watch: true)
   processStylesheets()
+  processStatic()
+
+  # FIXME: This reload method is really slow
+  templates = [
+    "#{APP_LOCATION}/templates/**/*.jade"
+    "!#{APP_LOCATION}/templates/static/**/*.jade"
+  ]
+  gulp.watch(templates).on 'change', (event)->
+    watchReporter(event)
+    processJavascripts(watch: true)

   stylesheets = [
     "#{CORE_LOCATION}/stylesheets/**/*.styl"
@@ -211,5 +233,12 @@
     watchReporter(event)
     processStatic()

+  process.stdin.on 'data', (chunk)->
+    if chunk.toString().replace(/[\r\n]/g, '') in RELOAD_TRIGGERS
+      log('Triggered manual reload', 'red')
+      processJavascripts(watch: true)
+      processStylesheets()
+      processStatic()
+
 gulp.task('default', ['browserify', 'stylus', 'static'])
 gulp.task('build', ['compress'])


Change watch task to default

Change watch task to default

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -39,4 +39,4 @@
   .pipe(gulp.dest('dist'));

 gulp.task 'watch', ->
-  gulp.watch ['**/*.coffee'], ['scripts']+  gulp.watch ['**/*.coffee'], ['default']


add PORT option in watch task

add PORT option in watch task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -153,6 +153,7 @@
     paths.appDir + '/index.html'
   ], ['test-and-build']
   browserSync
+    port: parseInt(process.env.PORT ? '5000')
     server:
       baseDir: './dist'


Remove test from build task until _stream_duplex issue is fixed

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -55,7 +55,13 @@
 		.pipe(coffeelint.reporter())

 gulp.task 'build', (callback) ->
-	runSequence([ 'lint', 'test' ], [ 'json', 'coffee' ], callback)
+	runSequence([
+		'lint'
+
+		# Disable test on build until _stream_duplex issue is fixed:
+		# https://github.com/iojs/readable-stream/issues/119
+		# 'test'
+	], [ 'json', 'coffee' ], callback)

 gulp.task 'watch', [ 'build' ], ->
 	gulp.watch([ OPTIONS.files.coffee, OPTIONS.files.json, 'README.md' ], [ 'build' ])


chore: fix gulpfile

chore: fix gulpfile

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -29,6 +29,7 @@
 cached = require 'gulp-cached'
 tslint = require 'gulp-tslint'
 mkdir = require 'mkdirp'
+debug = require 'gulp-debug'

 ###
 TASK SUMMARY


remove json task

remove json task

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -5,7 +5,6 @@
 gulpsync     = $.sync gulp
 path         = require 'path'
 htmlincluder = require 'gulp-htmlincluder'
-mdtojson     = require 'gulp-markdown-to-json'

 gulp.task 'clean', ->
   del config.prod_path, force: true
@@ -19,7 +18,6 @@
   gulp.src path.join config.dev_path_coffee, '*.coffee'
     .pipe $.coffee bare: true
     .pipe gulp.dest config.prod_path_js
-    .pipe $.livereload()

 gulp.task 'gen_css', ->
   gulp.src path.join config.dev_path_sass, '*.sass'
@@ -58,7 +56,6 @@
       ]
       cascade: true
     .pipe gulp.dest config.prod_path_css
-    .pipe $.livereload()

 gulp.task 'gen_markdown', ->
   gulp.src path.join config.database_path, '*.md'
@@ -74,13 +71,6 @@
 gulp.task 'gen_html_live', ->
   gulp.src path.join config.dev_path, '*.html'
     .pipe htmlincluder()
-    .pipe gulp.dest config.prod_path
-    .pipe $.livereload()
-  return
-
-gulp.task 'gen_json', ->
-  gulp.src path.join config.database_path, '*.md'
-    .pipe mdtojson()
     .pipe gulp.dest config.prod_path
   return

@@ -119,12 +109,8 @@
 gulp.task 'deploy', [], $.shell.task [ 'surge ' + config.prod_path ]

 gulp.task 'watcher', ->
-  $.livereload.listen port: process.env.LL or 35729
   gulp.watch path.join(config.dev_path_coffee, '*.coffee'), ['gen_js_live']
   gulp.watch path.join(config.dev_path_sass, '*.sass'), ['gen_css_live']
   gulp.watch path.join(config.dev_path, '*.html'), ['gen_html_live']
   return

-gulp.task 'json', gulpsync.sync [
-  'gen_json'
-]


betterer fingering selection

betterer fingering selection

--- lib/fretboard_logic.coffee
+++ lib/fretboard_logic.coffee
@@ -131,21 +131,21 @@

   # Construct the filter set

-  filters = [
-    {name: 'four fingers or fewer', filter: four_fingers_or_fewer}
-  ]
+  filters = []
+  filters.push name: 'has all chord notes', select: has_all_notes

   if options.filter
-    filters.push name: 'has all chord notes', filter: has_all_notes
+    filters.push name: 'four fingers or fewer', select: four_fingers_or_fewer

   unless options.fingerpicking
-    filters.push name: 'no muted medial strings', filter: cmp(muted_medial_strings)
-    filters.push name: 'no muted treble strings', filter: cmp(muted_treble_strings)
+    filters.push name: 'no muted medial strings', reject: muted_medial_strings
+    filters.push name: 'no muted treble strings', reject: muted_treble_strings

   # filter by all the filters in the list, except ignore those that wouldn't pass anything
   filter_fingerings = (fingerings) ->
-    for {name, filter} in filters
-      filtered = (fingering for fingering in fingerings when filter(fingering))
+    for {name, select, reject} in filters
+      select ||= cmp(reject)
+      filtered = (fingering for fingering in fingerings when select fingering)
       unless filtered.length
         console.warn "#{chord_name}: no fingerings pass filter \"#{name}\"" if warn
         filtered = fingerings
@@ -157,19 +157,26 @@
   # Sort
   #

-  high_note_count = (fingering) -> -fingering.positions.length
+  # FIXME count pitch classes, not sounded strings
+  high_note_count = (fingering) ->
+   fingering.positions.length

   is_root_position = (fingering) ->
     _(fingering.positions).sortBy((pos) -> pos.string)[0].degree_index == 0

-  sorts = [
-    {name: 'low finger count', key: (fingering) -> -fingering.positions.length}
+  reverse_sort_key = (fn) -> (a) -> -fn(a)
+
+  # ordered list of preferences, from most to least important
+  preferences = [
+    {name: 'root position', key: is_root_position}
     {name: 'high note count', key: high_note_count}
-    {name: 'root position', key: cmp(is_root_position)}
+    {name: 'avoid barres', key: reverse_sort_key((fingering) -> fingering.barres.length)}
+    {name: 'low finger count', key: reverse_sort_key(finger_count)}
   ]

   sort_fingerings = (fingerings) ->
-    fingerings = _(fingerings).sortBy(key) for {key} in sorts
+    fingerings = _(fingerings).sortBy(key) for {key} in preferences.slice(0).reverse()
+    fingerings.reverse()
     return fingerings


Use observeTextEditors instead of eachEditor

--- lib/haskell-ghc-mod.coffee
+++ lib/haskell-ghc-mod.coffee
@@ -26,7 +26,7 @@
       'haskell-ghc-mod:check': ->
         @getModel().haskellGhcModController?.doCheck()

-    @subscriptions.add atom.workspace.eachEditor (editor) =>
+    @subscriptions.add atom.workspace.observeTextEditors (editor) =>
       return unless editor.getGrammar().scopeName=="source.haskell"
       @numInstances += 1
       console.log(@numInstances)


Fix last date getting.

Fix last date getting.

--- scripts/chat-logger.coffee
+++ scripts/chat-logger.coffee
@@ -219,7 +219,7 @@
     catch e
       throw e if e != "break"

-    last_day = _.last(_.last(result)).date
+    last_day = _.first(_.last(result)).date
     new_logs = {}
     for i in [0...10]
       d = new Date(last_day - 1000 * 60 * 60 * 24 * i)


Include parent/container in before/after add/remove has_many events

--- app/assets/javascripts/active_admin/lib/has_many.js.coffee
+++ app/assets/javascripts/active_admin/lib/has_many.js.coffee
@@ -2,8 +2,14 @@
   # Provides a before-removal hook:
   # $ ->
   #   # This is a good place to tear down JS plugins to prevent memory leaks.
-  #   $(document).on 'has_many_remove:before', '.has_many_container', (e, fieldset)->
+  #   $(document).on 'has_many_remove:before', '.has_many_container', (e, fieldset, container)->
   #     fieldset.find('.select2').select2 'destroy'
+  #
+  #   # If you need to do anything after removing the items you can use the
+  #   has_many_remove:after hook
+  #   $(document).on 'has_many_remove:after', '.has_many_container', (e, fieldset, container)->
+  #     list_item_count = container.find('.has_many_fields').length
+  #     alert("There are now #{list_item_count} items in the list")
   #
   $(document).on 'click', 'a.button.has_many_remove', (e)->
     e.preventDefault()
@@ -11,26 +17,26 @@
     to_remove = $(@).closest 'fieldset'
     recompute_positions parent

-    parent.trigger 'has_many_remove:before', [to_remove]
+    parent.trigger 'has_many_remove:before', [to_remove, parent]
     to_remove.remove()
-    parent.trigger 'has_many_remove:after', [ to_remove ]
+    parent.trigger 'has_many_remove:after', [to_remove, parent]

   # Provides before and after creation hooks:
   # $ ->
   #   # The before hook allows you to prevent the creation of new records.
-  #   $(document).on 'has_many_add:before', '.has_many_container', (e)->
+  #   $(document).on 'has_many_add:before', '.has_many_container', (e, container)->
   #     if $(@).children('fieldset').length >= 3
   #       alert "you've reached the maximum number of items"
   #       e.preventDefault()
   #
   #   # The after hook is a good place to initialize JS plugins and the like.
-  #   $(document).on 'has_many_add:after', '.has_many_container', (e, fieldset)->
+  #   $(document).on 'has_many_add:after', '.has_many_container', (e, fieldset, container)->
   #     fieldset.find('select').chosen()
   #
   $(document).on 'click', 'a.button.has_many_add', (e)->
     e.preventDefault()
     parent = $(@).closest '.has_many_container'
-    parent.trigger before_add = $.Event 'has_many_add:before'
+    parent.trigger before_add = $.Event('has_many_add:before'), [parent]

     unless before_add.isDefaultPrevented()
       index = parent.data('has_many_index') || parent.children('fieldset').length - 1
@@ -41,7 +47,7 @@

       fieldset = $(html).insertBefore(@)
       recompute_positions parent
-      parent.trigger 'has_many_add:after', [fieldset]
+      parent.trigger 'has_many_add:after', [fieldset, parent]

   $(document).on 'change','.has_many_container[data-sortable] :input[name$="[_destroy]"]', ->
     recompute_positions $(@).closest '.has_many'


Hourly supply chart: fix annual view series order

Closes #2900

--- app/assets/javascripts/d3/merit_order_hourly_supply.coffee
+++ app/assets/javascripts/d3/merit_order_hourly_supply.coffee
@@ -30,7 +30,7 @@
       weekNum = this.dateSelect && this.dateSelect.val() || 0

       _.sortBy @model.non_target_series(), (serie) =>
-        values = MeritTransformator.sliceValues(serie.future_value(), weekNum)
+        values = MeritTransformator.transform(serie.future_value(), weekNum)

         min = max = sum = 0


Atom notifications provide no serialization, discard them.

--- lib/language-ledger.coffee
+++ lib/language-ledger.coffee
@@ -90,8 +90,7 @@
   deactivate: ->
     console.log "deactivate"
     @subscriptions?.dispose()
-    @output?.detach()
+    @output?.clear()

   serialize: ->
     console.log "serialize"
-    ledgerViewState: @output?.serialize()


r/w updates

r/w updates

--- grovepi.coffee
+++ grovepi.coffee
@@ -29,12 +29,11 @@

-	send = ( cmd, args... ) ->
+	send = ( data, args... ) ->
 		writeArgs = []
 		if args[1]
 			data = args[0]
 			callback = args[1]
-			writeArgs.push cmd
 			writeArgs.push data
 			writeCmd = 'writeBytes'
 		else
@@ -45,7 +44,7 @@

 		writeArgs.push (error) ->
 			callback()
-			debug.log "Send", cmd
+			debug.log "Send", data
 			debug.log "ERROR:", error if error

 		wire[writeCmd] writeArgs...
@@ -83,7 +82,7 @@
 			wire.writeByte CMD.mode, 1, -> # Switch to output

 	ranger: ( port, callback ) ->
-		send CMD.ranger, port, [0,0], ->
+		send CMD.ranger, [port,0,0], ->
 			receive port, 3, (data) ->
 				callback data[2] + data[1]


Fixes #593

Fixes #593

--- lib/models/git-show.coffee
+++ lib/models/git-show.coffee
@@ -31,8 +31,8 @@
 showFile = (objectHash) ->
   filePath = showCommitFilePath(objectHash)
   disposables = new CompositeDisposable
-  editorForDiffs = atom.workspace.getPaneItems().filter((item) -> item.getURI().includes('.diff'))[0]
-  if editorForDiffs
+  editorForDiffs = atom.workspace.getPaneItems().filter((item) -> item.getURI()?.includes('.diff'))[0]
+  if editorForDiffs?
     editorForDiffs.setText fs.readFileSync(filePath, encoding: 'utf-8')
   else
     if atom.config.get('git-plus.general.openInPane')


use debug and comment out

use debug and comment out

--- lib/operation-stack.coffee
+++ lib/operation-stack.coffee
@@ -63,8 +63,7 @@
       top = @peekTop()

       if top.isComplete()
-        if settings.get('debug')
-          console.log  [top.getName(), top.target?.getName()]
+        # debug  [top.getName(), top.target?.getName()]
         @execute(@stack.pop())
       else
         if @vimState.isMode('normal') and top.isOperator()


update the margin size of pdfng

update the margin size of pdfng

--- services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee
@@ -38,7 +38,7 @@
 			scale = {} if not scale?
 			if scale.scaleMode == 'scale_mode_fit_width'
 				# TODO make this dynamic
-				numScale = (containerWidth - 15) / ($scope.pdfPageSize[1])
+				numScale = (containerWidth - 40) / ($scope.pdfPageSize[1])
 			else if scale.scaleMode == 'scale_mode_fit_height'
 				# TODO magic numbers for jquery ui layout
 				numScale = (containerHeight) / ($scope.pdfPageSize[0])


Check for abort

Check for abort

--- varify/static/scripts/coffeescript/ui/workflows/results.coffee
+++ varify/static/scripts/coffeescript/ui/workflows/results.coffee
@@ -555,10 +555,12 @@

         hidePhenotypes: =>
             @phenotypeXhr.abort() if @phenotypeXhr
+            @phenotypeXhr = undefined
             @ui.viewPhenotype.find(".content").empty()
             @ui.viewPhenotype.find(".loading").show()

         phenotypesError: (model, response) =>
+            return if response.statusText is "abort"
             @ui.viewPhenotype.find(".loading").hide()
             @ui.viewPhenotype.find(".content").html("
An error was encountered. " +
                 "Unable to retrieve phenotypes for sample #{ model.attributes.sample_id }.
")


Fix #105 "New FB: hovering over section template grid asks to add labels/hints"

--- src/resources/forms/orbeon/builder/resources/grid/events.coffee
+++ src/resources/forms/orbeon/builder/resources/grid/events.coffee
@@ -61,11 +61,13 @@
         Event.addListener document, "mouseover", (event) ->
             target = Event.getTarget event
             gridThTd =
+                # Give up we we're not in an editable grid, e.g. section template
+                if not $(target).closest('.fr-grid').is('.fr-editable') then null
                 # Target is the grid td, we're good
-                if $(target).is('.fr-grid-th, .fr-grid-td') then target
+                else if $(target).is('.fr-grid-th, .fr-grid-td') then target
                 # Try finding a grid td parent of the target
                 else $(target).closest('.fr-grid-th, .fr-grid-td')[0]
-            if gridThTd
+            if gridThTd?
                 if currentMouseOverGridThTd
                     if gridThTd isnt currentMouseOverGridThTd
                         # From one gridTd to another gridTd


Always submit form using fill

Always submit form using fill

--- tests/javascript/browser/means_test.coffee
+++ tests/javascript/browser/means_test.coffee
@@ -4,12 +4,11 @@
   casper.start casper.base_url + "your_problem/", ->
     test.assertSelectorHasText "h1", "Your problem", "page has correct title"

-
   casper.thenEvaluate ->
       $("input[name=your_problem-category]:first").click()
-      $("button[type='submit']").click()

   casper.then ->
+    @fill 'form', {}, true
     @waitForUrl /.*your_details/

   casper.thenEvaluate ->
@@ -17,7 +16,6 @@
     $("#id_your_details-has_partner_0").click()

   casper.then ->
-    @fill 'form', {}, true
     @waitForUrl /.*your_capital/

   casper.thenEvaluate ->


Cleanup.

Cleanup.

--- src/ProjectUtils.coffee
+++ src/ProjectUtils.coffee
@@ -65,10 +65,6 @@
             SchemaUtils.setParameterValue(model, 'access.public', false)
             user = AccountsUtil.resolveUser(args.userId)
             if user? then model[AccountsUtil.AUTHOR_FIELD] = user._id
-
-          # if collection == Ranks
-          #   console.log('rank model', model)
-
           # Ensure collection hooks run for the project since there are far fewer docs.
           method = collection.direct.insert if args.useDirect
           method ?= collection.insert
@@ -93,17 +89,11 @@
         newModelIds = _.values(idMap)
         newModels = collection.find(_id: $in: newModelIds).fetch()
         newModelsMap = {}
-
-        # if name == 'ranks'
-        #   console.log('idMap', idMap)
-
         _.each newModels, (model) -> newModelsMap[model._id] = model
         _.each idMap, (newId, oldId) ->
           runner.add ->
             newModel = newModelsMap[newId]
             modifier = SchemaUtils.getRefModifier(newModel, collection, idMaps)
-            # if name == 'ranks'
-            #   console.log('modifier', modifier)
             unless _.isEmpty(modifier.$set)
               refDf = Q.defer()
               refDfs.push(refDf.promise)


Properly escape multiple \'s in the same string

--- lib/snippet-manager.coffee
+++ lib/snippet-manager.coffee
@@ -26,7 +26,7 @@
     te = atom.workspace.getActiveTextEditor()
     range = te.getSelectedBufferRange()
     text = te.getTextInBufferRange(range)
-    text = text.replace("\\", "\\\\")
+    text = text.replace(/\\/g, "\\\\")

     te.transact =>
       te.setTextInBufferRange(range, "")


fix to accounts for text and html token email

--- server/api/accounts.coffee
+++ server/api/accounts.coffee
@@ -86,7 +86,7 @@
   _hash = Random.hexString 40
   tok.hash = API.accounts.hash _hash
   tok.url ?= settings.url # TODO is it worth checking validity of incoming urls?
-  tok.url += '#' + tok.hash if tok.url?
+  tok.url += '#' + _hash if tok.url?
   tok.timeout = Date.now() + (tok.timeout ? settings.timeout) * 60 * 1000 # convert to ms from now
   Tokens.insert tok
   tok.hash = _hash
@@ -104,8 +104,8 @@
       re = new RegExp '\{\{LOGINCODE\}\}', 'g'
       ure = new RegExp '\{\{LOGINURL\}\}', 'g'
       tre = new RegExp '\{\{TIMEOUT\}\}', 'g'
-      snd.text = snd.text.replace(re, tok.token).replace(ure,tok.url).replace(tre,settings.timeout) if snd.text
-      snd.html = snd.html.replace(re, tok.token).replace(ure,tok.url).replace(tre,settings.timeout) if snd.html
+      snd.text = snd.text.replace(re, _token).replace(ure,tok.url).replace(tre,settings.timeout) if snd.text
+      snd.html = snd.html.replace(re, _token).replace(ure,tok.url).replace(tre,settings.timeout) if snd.html
       if settings.timeout >= 60 and snd.text and snd.text.indexOf(settings.timeout + ' minutes') isnt -1
         rp = settings.timeout / 60
         rp += if rp > 1 then ' hours' else ' hour'


Remove unnecessary codes

Remove unnecessary codes

--- server/publications.coffee
+++ server/publications.coffee
@@ -11,18 +11,6 @@
   Flowers.find()

 Meteor.publish "friends", ->
-  currentUserQuery = Meteor.users.find(id: @userId)
-  console.log 'currentUserId: ', @userId
-  currentUserQuery.observe ->
-    added: (doc) ->
-      console.log 'added doc', doc
-      console.log 'friendList: ', friendList = Meteor.users.findOne(@userId).profile.friendList
-      # if friendList
-      #   friendsCursor = Meteor.users.find({_id: {$in: friendList}}, {fields: {services: 0}})
-
-    removed: (oldDoc) ->
-      console.log 'removed doc', oldDoc
-
   if @userId
     friendList = Meteor.users.findOne(@userId).profile.friendList
     if friendList


Only one search promise now

Only one search promise now

--- lib/todo-collection.coffee
+++ lib/todo-collection.coffee
@@ -165,14 +165,12 @@
       atom.config.get('todo-show.findTheseTodos')
     )

-    # TODO: Rewrite to only use one regex search and not .all
-    promise = switch @scope
+    @searchPromise = switch @scope
       when 'open' then @fetchOpenRegexItem(regexp, regex, false)
       when 'active' then @fetchOpenRegexItem(regexp, regex, true)
       else @fetchRegexItem(regexp, regex)
-    @searchPromises.push(promise)

-    Promise.all(@searchPromises).then () =>
+    @searchPromise.then () =>
       @searching = false
       @emitter.emit 'did-finish-search'
     .catch (err) =>
@@ -192,6 +190,4 @@
     todosMarkdown.markdown @getTodos()

   cancelSearch: ->
-    @searchPromises ?= []
-    for promise in @searchPromises
-      promise.cancel?() if promise
+    @searchPromise?.cancel?()


more consistent rpc

more consistent rpc

--- lib/connection/client.coffee
+++ lib/connection/client.coffee
@@ -9,15 +9,17 @@
   queue: []
   id: 0

-  input: ([type, data]) ->
+  input: ([type, args...]) ->
+    if type.constructor == Object
+      {type, callback} = type
     if @handlers.hasOwnProperty type
-      if data.callback?
-        @msg data.callback, @handlers[type] data.args...
+      if callback
+        @msg callback, @handlers[type] args...
       else
-        @handlers[type] data
+        @handlers[type] args...
     else if @callbacks.hasOwnProperty type
       try
-        @callbacks[type] data
+        @callbacks[type] args...
       finally
         delete @callbacks[type]
         @loading.done()


add fallback color for bad themes (issue #4) and remove depreciated 'load daemons from file'

--- lib/daemon-management.coffee
+++ lib/daemon-management.coffee
@@ -1,42 +0,0 @@
-
-
-DaemonItem = require "./daemon-item"
-packageName = require('../package.json').name
-
-{Directory,File,CompositeDisposable} = require 'atom'
-
-
-# Will be deleted in next version!
-module.exports =
-class DaemonManagement
-  constructor: ->
-    @subscriptions = new CompositeDisposable
-    @regEventBus()
-
-    #will be deletet in next version
-    @rootPackageDir = atom.packages.loadedPackages[packageName].path
-    @transportJsonToStateIfExist()
-
-  regEventBus: ->
-    @eb = eb.SmartDaemonControl
-    # @eventBus.on "destroy", @destroy
-
-  #Test:
-  # {"1":{"name":"mysql","cmdRun":"launchctl load /usr/local/opt/mysql/homebrew.mxcl.mysql.plist","cmdStop":"launchctl unload /usr/local/opt/mysql/homebrew.mxcl.mysql.plist","cmdCheck":"launchctl list","strCheck":"homebrew.mxcl.mysql","autorun":true,"id":2}}
-
-  # will be deletet in next version
-  transportJsonToStateIfExist: ->
-    daemonsFile = new File "#{@rootPackageDir}/daemons.json"
-    # Check if there is an daemon.json from prev. version
-    if daemonsFile.existsSync()
-      # console.log  "Transform JSON to State"
-      daemons = require '../daemons.json'
-      # pipe it to state
-      for k,item of daemons
-        @eb.daemonItemCollection.add item
-        # @eventBus.emit "daemon-item-collection:add", item
-      # and set file to an emtpy object
-      daemonsFile.writeSync "{}"
-
-  destroy: =>
-    @subscriptions.dispose()


video opacity

video opacity

--- lib/editor-background.coffee
+++ lib/editor-background.coffee
@@ -146,6 +146,12 @@
           default:75
           description:"animation speed in ms (original is 50),
           LOWER VALUE = HIGHER CPU USAGE"
+        opacity:
+          type:"integer"
+          default:75
+          minimum:0
+          maximum:100
+          description:"video opacity"
         startTime:
           type:"string"
           default:'0s'
@@ -1038,6 +1044,10 @@
         inline @elements.resizer,'background:transparent !important;'
         inline @elements.leftPanel,'background:transparent !important;'

+      videoOpacity = (conf.video.opacity/100).toFixed(2)
+      if @animation?.canvas?
+          inline @animation.canvas,"opacity:#{videoOpacity};";
+


Call focusFilterEditor()

Call focusFilterEditor()

--- lib/grammar-list-view.coffee
+++ lib/grammar-list-view.coffee
@@ -39,7 +39,7 @@
   attach: ->
     @storeFocusedElement()
     atom.workspaceView.append(this)
-    @focusEditor()
+    @focusFilterEditor()

   getGrammars: ->
     grammars = atom.syntax.getGrammars().filter (grammar) ->


Fix jPlayer

Fix jPlayer

--- app/assets/javascripts/rglossa/speech/components/centre/results/jplayer.jsx.coffee
+++ app/assets/javascripts/rglossa/speech/components/centre/results/jplayer.jsx.coffee
@@ -27,20 +27,22 @@

     console.log(mediaObj)

-    $node.find(".jp-jplayer").jPlayer
+    $playerNode = $node.find(".jp-jplayer")
+    $playerNode.jPlayer
       solution: "flash, html"
       ready: ->
-        $node.jPlayer "setMedia",
+        $playerNode.jPlayer "setMedia",
           rtmpv: path + mov
           m4v: path+mov
           poster: "assets/rglossa/speech/_6.6-%27T%27_ligo.skev.graa.jpg"
-        $node.jPlayer( "play", start)
+        $playerNode.jPlayer( "play", start)

       timeupdate: (event) =>
         ct = event.jPlayer.status.currentTime
         if ct > stop
-          @$(".jp-jplayer").jPlayer("play", start)
-          @$(".jp-jplayer").jPlayer( "pause" )
+          $playerNode = $node.find(".jp-jplayer")
+          $playerNode.jPlayer("play", start)
+          $playerNode.jPlayer( "pause" )
         else if ct > @textBox.currentEndTime
           @textBox.update(ct)

@@ -69,11 +71,11 @@
           start = parseFloat($("#jp-"+first).data("start_timecode"))
           stop = parseFloat($("#jp-"+last).data("end_timecode"))

-          @$(".js-jplayer").jPlayer("play", start)
+          $node.find(".js-jplayer").jPlayer("play", start)

   componentWillUnmount: ->
-    @$(".jp-jplayer").jPlayer('destroy')
+    $(@getDOMNode()).find(".jp-jplayer").jPlayer('destroy')

   createTextBox: =>
@@ -194,7 +196,7 @@

   render: ->
-    `
+    `

@@ -238,4 +240,4 @@

-    `
+
`


work with looks urls that have a query string

--- lib/schedule_receiver.coffee
+++ lib/schedule_receiver.coffee
@@ -13,7 +13,7 @@

       if req.body.scheduled_plan
         if req.body.scheduled_plan.type == "Look"
-          if matches = req.body.scheduled_plan.url.match(/\/looks\/([0-9]+)$/)
+          if matches = req.body.scheduled_plan.url.match(/\/looks\/([0-9]+)/)
             lookId = matches[1]

             channelName = req.params.channel_name


enhance

enhance

--- lib/selection-wrapper.coffee
+++ lib/selection-wrapper.coffee
@@ -38,6 +38,10 @@
       when 'end' then @getEndBufferPosition()
       when 'head' then @getHeadBufferPosition()
       when 'tail' then @getTailBufferPosition()
+
+  setBufferPositionTo: (which) ->
+    point = @getBufferPositionFor(which)
+    @selection.cursor.setBufferPosition(point)

   reverse: ->
     @setReversedState(not @selection.isReversed())


Fix go-spec Specs

Fix go-spec Specs

--- lib/util/pathexpander.coffee
+++ lib/util/pathexpander.coffee
@@ -7,6 +7,16 @@
   constructor: (@env) ->

   expand: (p, gopath) ->
+    return '' unless p? and p.trim() isnt ''
+    return @expandItem(p, gopath) if p.indexOf(':') is -1
+    paths = p.split(':')
+    result = ''
+    for pathItem in paths
+      pathItem = @expandItem(pathItem, gopath)
+      result = if result is '' then pathItem else result + ':' + pathItem
+    return result
+
+  expandItem: (p, gopath) ->
     return '' unless p? and p.trim() isnt ''
     p = @replaceGoPathToken(p, gopath)
     switch os.platform()


accidentally removed the insert function

--- app/assets/javascripts/mercury/regions/static.js.coffee
+++ app/assets/javascripts/mercury/regions/static.js.coffee
@@ -63,6 +63,10 @@

     redo: -> @content(@history.redo())

+    insertSnippet: (options) ->
+      snippet = options.value
+      snippet.getStaticHTML(@element, => @pushHistory())
+
     editSnippet: ->
       return unless @snippet
       snippet = Mercury.Snippet.find(@snippet.data('snippet'))


URLs should be generated with appropriate schema part

--- library/nucleus/tools.coffee
+++ library/nucleus/tools.coffee
@@ -46,8 +46,10 @@
     secure = nconf.get "secure:port"
     port = if ssl then secure else server
     hostname = nconf.get "server:hostname"
-    hostname = "#{hostname}:#{port}"
-    hostname += "/#{parts}" if parts?
-    hostname += "?#{params}" if params?
-    hostname += "##{segment}" if segment?
-    hostname.toString().replace "//", "/"
+    scheme = if ssl then "https" else "http"
+    dedup = (string) -> string.replace("//", "/")
+    url = "#{scheme}://#{hostname}:#{port}"
+    url += dedup("/#{parts}") if parts?
+    url += "?#{params}" if params?
+    url += "##{segment}" if segment?
+    _.escape url.toString()


documentation

documentation

--- src/List.coffee
+++ src/List.coffee
@@ -1,5 +1,5 @@
 ###*
-  @fileoverview Contains the implementation of the List data structure.
+  @fileoverview Contains the implementation of the List abstract data type.
   @author Mads Hartmann Jensen (mads379@gmail.com)
 ###
 if require?
@@ -8,17 +8,29 @@
   None     = Option.None

 ###*
-
List provides the implementation of the abstract data type 'List' based on a Singly-Linked list

+  List provides the implementation of the abstract data type List based on a Singly-Linked list. The
+  list contains the following operations:

-  The operations specific to the List abstract data type
-
-  append( element )             O(n)
-  prepend( element )            O(1)
-  update( index, element )      O(n)
-  get( index )                  O(n)
-  remove( index )               O(n)
+  --------------------------------------------------------
+  Core operations of the List ADT
+  --------------------------------------------------------
+  append( element )                                   O(n)
+  prepend( element )                                  O(1)
+  update( index, element )                            O(n)
+  get( index )                                        O(n)
+  remove( index )                                     O(n)
+  --------------------------------------------------------
+  Methods that all containers have to implement
+  --------------------------------------------------------
+  map( f )                                            O(n)    TODO
+  flatMap( f )                                        O(n)    TODO
+  filter( f )                                         O(n)    TODO
+  forEach( f )                                        O(n)    TODO
+  foldLeft( f )                                       O(n)
+  isEmpty()                                           O(1)
+  --------------------------------------------------------

-  @class List provides the implementation of the abstract data type 'List' based on a Singly-Linked list

+  @class List provides the implementation of the abstract data type List based on a Singly-Linked list
   @public
 ###
 List = (elements...) ->


Pump: code cleanup

Pump: code cleanup

--- src/Pump.coffee
+++ src/Pump.coffee
@@ -52,8 +52,7 @@
   start: ->
     throw new Error 'Source is not configured' if !@_from
     @_state = Pump.STARTED if @_state == Pump.STOPPED
-    if !@_errorBuffer?
-      @_errorBuffer = new Buffer
+    @_errorBuffer = new Buffer if !@_errorBuffer?
     do @_pump
     @


Don't display window in spec mode

Don't display window in spec mode

--- src/atom.coffee
+++ src/atom.coffee
@@ -223,7 +223,7 @@
     @disposables?.dispose()
     @disposables = new CompositeDisposable

-    @displayWindow()
+    @displayWindow() unless @inSpecMode()

     @setBodyPlatformClass()


Update cart.

Update cart.

--- src/cart.coffee
+++ src/cart.coffee
@@ -30,28 +30,29 @@
 m = require './mediator'
 Events = require './events'

-m.on Events.SetData, (@data)->
+m.on Events.SetData, (@data) ->
   calculateInvoice.call @

-m.on Events.UpdateItems, ()->
+m.on Events.UpdateItems, ->
   calculateInvoice.call @

 m.on Events.ChangeSuccess, (key, value)->
   if key.indexOf('quantity') >= 0 || key.indexOf('city') >= 0 || key.indexOf('state') >= 0 || key.indexOf('country') >= 0
     calculateInvoice.call @

-calculateInvoice = ()->
-  items = @data.get 'order.items'
-  subtotal = -@data.get 'order.discount'  || 0
+calculateInvoice = ->
+  items    =   @data.get 'order.items'
+  subtotal = -(@data.get 'order.discount') ? 0
+
   for item in items
     subtotal += item.price * item.quantity

   @data.set 'order.subtotal', subtotal

-  taxRate = @data.get 'order.shippingRate' || 0
-  shippingRate = @data.get 'order.shippingRate' || 0
+  taxRate      = (@data.get 'order.taxRate')      ? 0
+  shippingRate = (@data.get 'order.shippingRate') ? 0

-  tax = Math.ceil (taxRate || 0) * subtotal
+  tax = Math.ceil (taxRate ? 0) * subtotal
   shipping = shippingRate

   @data.set 'order.shipping', shipping


Hiding Shop Preferences in enterprise form

--- app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
+++ app/assets/javascripts/admin/enterprises/controllers/enterprise_controller.js.coffee
@@ -56,6 +56,7 @@
       if newValue == "none"
         $scope.menu.hide_item_by_name('Shipping Methods')
         $scope.menu.hide_item_by_name('Payment Methods')
+        $scope.menu.hide_item_by_name('Shop Preferences')
         if $scope.Enterprise.is_primary_producer
           $scope.menu.show_item_by_name('Enterprise Fees')
         else
@@ -63,4 +64,5 @@
       else
         $scope.menu.show_item_by_name('Shipping Methods')
         $scope.menu.show_item_by_name('Payment Methods')
+        $scope.menu.show_item_by_name('Shop Preferences')
         $scope.menu.show_item_by_name('Enterprise Fees')


Adding more snippets

Adding more snippets

--- snippets/dispatch.cson
+++ snippets/dispatch.cson
@@ -2,115 +2,115 @@

   'dispatch1':
     'prefix': 'dispatch a key up event on the element found by "identifier"'
-    'body': 'dispatch a key up event on the element found by "$1"'
+    'body': 'dispatch a "keyup" event on the element found by "$1"'
   'dispatch2':
     'prefix': 'dispatch a key up event on the element found by alias "identifier"'
-    'body': 'dispatch a key up event on the element found by alias "$1"'
+    'body': 'dispatch a "keyup" event on the element found by alias "$1"'
   'dispatch3':
     'prefix': 'dispatch a key down event on the element found by "identifier"'
-    'body': 'dispatch a key down event on the element found by "$1"'
+    'body': 'dispatch a "keydown" event on the element found by "$1"'
   'dispatch4':
     'prefix': 'dispatch a key down event on the element found by alias "identifier"'
-    'body': 'dispatch a key down event on the element found by alias "$1"'
+    'body': 'dispatch a "keydown" event on the element found by alias "$1"'
   'dispatch5':
     'prefix': 'dispatch a key press event on the element found by "identifier"'
-    'body': 'dispatch a key press event on the element found by "$1"'
+    'body': 'dispatch a "keypress" event on the element found by "$1"'
   'dispatch6':
     'prefix': 'dispatch a key press event on the element found by alias "identifier"'
-    'body': 'dispatch a key press event on the element found by alias "$1"'
+    'body': 'dispatch a "keypress" event on the element found by alias "$1"'

   'dispatch7':
     'prefix': 'dispatch a key up event on the element with the ID of "identifier"'
-    'body': 'dispatch a key up event on the element with the ID of "$1"'
+    'body': 'dispatch a "keyup" event on the element with the ID of "$1"'
   'dispatch8':
     'prefix': 'dispatch a key up event on the element with the ID of alias "identifier"'
-    'body': 'dispatch a key up event on the element with the ID of alias "$1"'
+    'body': 'dispatch a "keyup" event on the element with the ID of alias "$1"'
   'dispatch9':
     'prefix': 'dispatch a key up event on the element with the class of "identifier"'
-    'body': 'dispatch a key up event on the element with the class of "$1"'
+    'body': 'dispatch a "keyup" event on the element with the class of "$1"'
   'dispatch10':
     'prefix': 'dispatch a key up event on the element with the class of alias "identifier"'
-    'body': 'dispatch a key up event on the element with the class of alias "$1"'
+    'body': 'dispatch a "keyup" event on the element with the class of alias "$1"'
   'dispatch11':
     'prefix': 'dispatch a key up event on the element with the xpath of "identifier"'
-    'body': 'dispatch a key up event on the element with the xpath of "$1"'
+    'body': 'dispatch a "keyup" event on the element with the xpath of "$1"'
   'dispatch12':
     'prefix': 'dispatch a key up event on the element with the xpath of alias "identifier"'
-    'body': 'dispatch a key up event on the element with the xpath of alias "$1"'
+    'body': 'dispatch a "keyup" event on the element with the xpath of alias "$1"'
   'dispatch13':
     'prefix': 'dispatch a key up event on the element with the name of "identifier"'
-    'body': 'dispatch a key up event on the element with the name of "$1"'
+    'body': 'dispatch a "keyup" event on the element with the name of "$1"'
   'dispatch14':
     'prefix': 'dispatch a key up event on the element with the name of alias "identifier"'
-    'body': 'dispatch a key up event on the element with the name of alias "$1"'
+    'body': 'dispatch a "keyup" event on the element with the name of alias "$1"'
   'dispatch15':
     'prefix': 'dispatch a key up event on the element with the css selector of "identifier"'
-    'body': 'dispatch a key up event on the element with the css selector of "$1"'
+    'body': 'dispatch a "keyup" event on the element with the css selector of "$1"'
   'dispatch16':
     'prefix': 'dispatch a key up event on the element with the css selector of alias "identifier"'
-    'body': 'dispatch a key up event on the element with the css selector of alias "$1"'
+    'body': 'dispatch a "keyup" event on the element with the css selector of alias "$1"'

   'dispatch17':
     'prefix': 'dispatch a key down event on the element with the ID of "identifier"'
-    'body': 'dispatch a key down event on the element with the ID of "$1"'
+    'body': 'dispatch a "keydown" event on the element with the ID of "$1"'
   'dispatch18':
     'prefix': 'dispatch a key down event on the element with the ID of alias "identifier"'
-    'body': 'dispatch a key down event on the element with the ID of alias "$1"'
+    'body': 'dispatch a "keydown" event on the element with the ID of alias "$1"'
   'dispatch19':
     'prefix': 'dispatch a key down event on the element with the class of "identifier"'
-    'body': 'dispatch a key down event on the element with the class of "$1"'
+    'body': 'dispatch a "keydown" event on the element with the class of "$1"'
   'dispatch20':
     'prefix': 'dispatch a key down event on the element with the class of alias "identifier"'
-    'body': 'dispatch a key down event on the element with the class of alias "$1"'
+    'body': 'dispatch a "keydown" event on the element with the class of alias "$1"'
   'dispatch21':
     'prefix': 'dispatch a key down event on the element with the xpath of "identifier"'
-    'body': 'dispatch a key down event on the element with the xpath of "$1"'
+    'body': 'dispatch a "keydown" event on the element with the xpath of "$1"'
   'dispatch22':
     'prefix': 'dispatch a key down event on the element with the xpath of alias "identifier"'
-    'body': 'dispatch a key down event on the element with the xpath of alias "$1"'
+    'body': 'dispatch a "keydown" event on the element with the xpath of alias "$1"'
   'dispatch23':
     'prefix': 'dispatch a key down event on the element with the name of "identifier"'
-    'body': 'dispatch a key down event on the element with the name of "$1"'
+    'body': 'dispatch a "keydown" event on the element with the name of "$1"'
   'dispatch24':
     'prefix': 'dispatch a key down event on the element with the name of alias "identifier"'
-    'body': 'dispatch a key down event on the element with the name of alias "$1"'
+    'body': 'dispatch a "keydown" event on the element with the name of alias "$1"'
   'dispatch25':
     'prefix': 'dispatch a key down event on the element with the css selector of "identifier"'
-    'body': 'dispatch a key down event on the element with the css selector of "$1"'
+    'body': 'dispatch a "keydown" event on the element with the css selector of "$1"'
   'dispatch26':
     'prefix': 'dispatch a key down event on the element with the css selector of alias "identifier"'
-    'body': 'dispatch a key down event on the element with the css selector of alias "$1"'
+    'body': 'dispatch a "keydown" event on the element with the css selector of alias "$1"'

   'dispatch27':
     'prefix': 'dispatch a key press event on the element with the ID of "identifier"'
-    'body': 'dispatch a key press event on the element with the ID of "$1"'
+    'body': 'dispatch a "keypress" event on the element with the ID of "$1"'
   'dispatch28':
     'prefix': 'dispatch a key press event on the element with the ID of alias "identifier"'
-    'body': 'dispatch a key press event on the element with the ID of alias "$1"'
+    'body': 'dispatch a "keypress" event on the element with the ID of alias "$1"'
   'dispatch29':
     'prefix': 'dispatch a key press event on the element with the class of "identifier"'
-    'body': 'dispatch a key press event on the element with the class of "$1"'
+    'body': 'dispatch a "keypress" event on the element with the class of "$1"'
   'dispatch30':
     'prefix': 'dispatch a key press event on the element with the class of alias "identifier"'
-    'body': 'dispatch a key press event on the element with the class of alias "$1"'
+    'body': 'dispatch a "keypress" event on the element with the class of alias "$1"'
   'dispatch31':
     'prefix': 'dispatch a key press event on the element with the xpath of "identifier"'
-    'body': 'dispatch a key press event on the element with the xpath of "$1"'
+    'body': 'dispatch a "keypress" event on the element with the xpath of "$1"'
   'dispatch32':
     'prefix': 'dispatch a key press event on the element with the xpath of alias "identifier"'
-    'body': 'dispatch a key press event on the element with the xpath of alias "$1"'
+    'body': 'dispatch a "keypress" event on the element with the xpath of alias "$1"'
   'dispatch33':
     'prefix': 'dispatch a key press event on the element with the name of "identifier"'
-    'body': 'dispatch a key press event on the element with the name of "$1"'
+    'body': 'dispatch a "keypress" event on the element with the name of "$1"'
   'dispatch34':
     'prefix': 'dispatch a key press event on the element with the name of alias "identifier"'
-    'body': 'dispatch a key press event on the element with the name of alias "$1"'
+    'body': 'dispatch a "keypress" event on the element with the name of alias "$1"'
   'dispatch35':
     'prefix': 'dispatch a key press event on the element with the css selector of "identifier"'
-    'body': 'dispatch a key press event on the element with the css selector of "$1"'
+    'body': 'dispatch a "keypress" event on the element with the css selector of "$1"'
   'dispatch36':
     'prefix': 'dispatch a key press event on the element with the css selector of alias "identifier"'
-    'body': 'dispatch a key press event on the element with the css selector of alias "$1"'
+    'body': 'dispatch a "keypress" event on the element with the css selector of alias "$1"'

   'dispatchcustom1':
     'prefix': 'dispatch a "change" event on the element found by "identifier"'


GitLab: update sample test data

GitLab: update sample test data

--- servers/lib/server/handlers/api/gitlab/_sampledata.coffee
+++ servers/lib/server/handlers/api/gitlab/_sampledata.coffee
@@ -5,7 +5,7 @@
     'updated_at'             : '2012-07-21T07:38:22Z'
     'event_name'             : 'project_create'
     'name'                   : 'StoreCloud'
-    'owner_email'            : 'johnsmith@gmail.com'
+    'owner_email'            : 'john@koding.com'
     'owner_name'             : 'John Smith'
     'path'                   : 'storecloud'
     'path_with_namespace'    : 'jsmith/storecloud'
@@ -18,7 +18,7 @@
     'updated_at'             : '2012-07-21T07:38:22Z'
     'event_name'             : 'project_destroy'
     'name'                   : 'Underscore'
-    'owner_email'            : 'johnsmith@gmail.com'
+    'owner_email'            : 'john@koding.com'
     'owner_name'             : 'John Smith'
     'path'                   : 'underscore'
     'path_with_namespace'    : 'jsmith/underscore'
@@ -35,7 +35,7 @@
     'path_with_namespace'    : 'jsmith/underscore'
     'project_id'             : 73
     'owner_name'             : 'John Smith'
-    'owner_email'            : 'johnsmith@gmail.com'
+    'owner_email'            : 'john@koding.com'
     'project_visibility'     : 'internal'
     'old_path_with_namespace': 'jsmith/overscore'
   }
@@ -49,7 +49,7 @@
     'path_with_namespace'    : 'scores/underscore'
     'project_id'             : 73
     'owner_name'             : 'John Smith'
-    'owner_email'            : 'johnsmith@gmail.com'
+    'owner_email'            : 'john@koding.com'
     'project_visibility'     : 'internal'
     'old_path_with_namespace': 'jsmith/overscore'
   }
@@ -65,7 +65,7 @@
     'project_name'                : 'StoreCloud'
     'project_path'                : 'storecloud'
     'project_path_with_namespace' : 'jsmith/storecloud'
-    'user_email'                  : 'johnsmith@gmail.com'
+    'user_email'                  : 'john@koding.com'
     'user_name'                   : 'John Smith'
     'user_username'               : 'johnsmith'
     'user_id'                     : 41
@@ -81,7 +81,7 @@
     'project_name'                : 'StoreCloud'
     'project_path'                : 'storecloud'
     'project_path_with_namespace' : 'jsmith/storecloud'
-    'user_email'                  : 'johnsmith@gmail.com'
+    'user_email'                  : 'john@koding.com'
     'user_name'                   : 'John Smith'
     'user_username'               : 'johnsmith'
     'user_id'                     : 41
@@ -96,7 +96,7 @@
     'group_id'                    : 78
     'group_name'                  : 'StoreCloud'
     'group_path'                  : 'storecloud'
-    'user_email'                  : 'johnsmith@gmail.com'
+    'user_email'                  : 'john@koding.com'
     'user_name'                   : 'John Smith'
     'user_username'               : 'johnsmith'
     'user_id'                     : 41
@@ -110,7 +110,7 @@
     'group_id'                    : 78
     'group_name'                  : 'StoreCloud'
     'group_path'                  : 'storecloud'
-    'user_email'                  : 'johnsmith@gmail.com'
+    'user_email'                  : 'john@koding.com'
     'user_name'                   : 'John Smith'
     'user_username'               : 'johnsmith'
     'user_id'                     : 41
@@ -119,20 +119,20 @@
   'user_create'                   : {
     'created_at'                  : '2012-07-21T07:44:07Z'
     'updated_at'                  : '2012-07-21T07:38:22Z'
-    'email'                       : 'js@gitlabhq.com'
+    'email'                       : 'john@koding.com'
     'event_name'                  : 'user_create'
     'name'                        : 'John Smith'
-    'username'                    : 'js'
+    'username'                    : 'john'
     'user_id'                     : 41
   }

   'user_destroy'                  : {
     'created_at'                  : '2012-07-21T07:44:07Z'
     'updated_at'                  : '2012-07-21T07:38:22Z'
-    'email'                       : 'js@gitlabhq.com'
+    'email'                       : 'john@koding.com'
     'event_name'                  : 'user_destroy'
     'name'                        : 'John Smith'
-    'username'                    : 'js'
+    'username'                    : 'john'
     'user_id'                     : 41
   }

@@ -163,7 +163,7 @@
     'updated_at'                  : '2012-07-21T07:38:22Z'
     'event_name'                  : 'group_create'
     'name'                        : 'StoreCloud'
-    'owner_email'                 : 'johnsmith@gmail.com'
+    'owner_email'                 : 'john@koding.com'
     'owner_name'                  : 'John Smith'
     'path'                        : 'storecloud'
     'group_id'                    : 78
@@ -174,7 +174,7 @@
     'updated_at'                  : '2012-07-21T07:38:22Z'
     'event_name'                  : 'group_destroy'
     'name'                        : 'StoreCloud'
-    'owner_email'                 : 'johnsmith@gmail.com'
+    'owner_email'                 : 'john@koding.com'
     'owner_name'                  : 'John Smith'
     'path'                        : 'storecloud'
     'group_id'                    : 78
@@ -231,7 +231,7 @@
     'checkout_sha'           : 'da1560886d4f094c3e6c9ef40349f7d38b5d27d7'
     'user_id'                : 4
     'user_name'              : 'John Smith'
-    'user_email'             : 'john@example.com'
+    'user_email'             : 'john@koding.com'
     'user_avatar'            : 'https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80'
     'project_id'             : 15
     'project'                : {