fix #86

fix #86

--- lib/debugger/stepper.coffee
+++ lib/debugger/stepper.coffee
@@ -20,7 +20,7 @@
   setText: (@text) ->
     for view in @views
       view.clear()
-      view.appendChild views.render span 'stepper-label', text
+      view.appendChild views.render span 'stepper-label', @text
       view.appendChild view.buttonGroup @buttons

   edsForFile: (file) ->


fix a typo bug (#980)

fix a typo bug (#980)

the variable name is typo

--- locales/pivot.jp.coffee
+++ locales/pivot.jp.coffee
@@ -12,8 +12,8 @@
     tpl = $.pivotUtilities.aggregatorTemplates

     jpFmt =    nf(thousandsSep: ",", decimalSep: ".")
-    jaFmtInt = nf(digitsAfterDecimal: 0, thousandsSep: ",", decimalSep: ".")
-    jaFmtPct = nf(digitsAfterDecimal: 1, scaler: 100, suffix: "%", thousandsSep: ",", decimalSep: ".")
+    jpFmtInt = nf(digitsAfterDecimal: 0, thousandsSep: ",", decimalSep: ".")
+    jpFmtPct = nf(digitsAfterDecimal: 1, scaler: 100, suffix: "%", thousandsSep: ",", decimalSep: ".")

     $.pivotUtilities.locales.ja =
         localeStrings:


indent

indent

--- lib/idris-controller.coffee
+++ lib/idris-controller.coffee
@@ -89,119 +89,119 @@
       @statusbar.hide()
     return

-IdrisController::destroy = ->
-  if @idrisModel
-    console.log 'Idris: Shutting down!'
-    @model.stop()
-  @statusbar.destroy()
-  return
-
-IdrisController::getWordUnderCursor = ->
-  editor = atom.workspace.getActiveEditor()
-  cursorPosition = editor.getCursor(0).getCurrentWordBufferRange()
-  editor.getTextInBufferRange cursorPosition
-
-IdrisController::loadFile = (uri) ->
-  console.log 'Loading ' + uri
-  @messages.clear()
-  @model.load uri, ((err, message, progress) ->
-    if err
-      @statusbar.setStatus 'Idris: ' + err.message
-      @messages.show()
-      @messages.clear()
-      @messages.setTitle ' Idris Errors', true
-      i = 0
-      while i < err.warnings.length
-        warning = err.warnings[i]
-        @messages.add new LineMessageView(
-          line: warning[1]
-          character: warning[2]
-          message: warning[3])
-        i++
-    else if progress
-      console.log '... ' + progress
-      @statusbar.setStatus 'Idris: ' + progress
-    else
-      @statusbar.setStatus 'Idris: ' + message
-    return
-  ).bind(this)
-  return
-
-IdrisController::getDocsForWord = ->
-  word = @getWordUnderCursor()
-  @model.docsFor word
-  return
-
-IdrisController::getTypeForWord = ->
-  word = @getWordUnderCursor()
-  @model.getType word, ((err, type) ->
-    if err
-      @statusbar.setStatus 'Idris: ' + err.message
-    else
-      @messages.show()
-      @messages.clear()
-      @messages.setTitle 'Idris: Type of <tt>' + word + '</tt>', true
-      @messages.add new ProofObligationView(obligation: type)
-    return
-  ).bind(this)
-  return
-
-IdrisController::doCaseSplit = ->
-  editor = atom.workspace.getActiveEditor()
-  line = editor.getCursor(0).getBufferRow()
-  word = @getWordUnderCursor()
-  @model.caseSplit line + 1, word, ((err, split) ->
-    if err
-      @statusbar.setStatus 'Idris: ' + err.message
-    else
-      lineRange = editor.getCursor(0).getCurrentLineBufferRange(includeNewline: true)
-      editor.setTextInBufferRange lineRange, split
-    return
-  ).bind(this)
-  return
-
-IdrisController::doAddClause = ->
-  editor = atom.workspace.getActiveEditor()
-  line = editor.getCursor(0).getBufferRow()
-  word = @getWordUnderCursor()
-  @model.addClause line + 1, word, ((err, clause) ->
-    if err
-      @statusbar.setStatus 'Idris: ' + err.message
-    else
-      editor.transact ->
-        # Insert a newline and the new clause
-        editor.insertNewlineBelow()
-        editor.insertText clause
-        # And move the cursor to the beginning of
-        # the new line
-        editor.moveCursorToBeginningOfLine()
-        return
-    return
-  ).bind(this)
-  return
-
-IdrisController::doProofSearch = ->
-  editor = atom.workspace.getActiveEditor()
-  line = editor.getCursor(0).getBufferRow()
-  word = @getWordUnderCursor()
-  @model.proofSearch line + 1, word, ((err, res) ->
-    if err
-      @statusbar.setStatus 'Idris: ' + err.message
-    else
-      editor.transact ->
-        # Move the cursor to the beginning of the word
-        editor.moveCursorToBeginningOfWord()
-        # Because the ? in the metavariable isn't part of
-        # the word, we move left once, and then select two
-        # words
-        editor.moveCursorLeft()
-        editor.selectToEndOfWord()
-        editor.selectToEndOfWord()
-        # And then replace the replacement with the guess..
-        editor.insertText res
-        return
-    return
-  ).bind(this)
-  return
+  destroy: ->
+    if @idrisModel
+      console.log 'Idris: Shutting down!'
+      @model.stop()
+    @statusbar.destroy()
+    return
+
+  getWordUnderCursor: ->
+    editor = atom.workspace.getActiveEditor()
+    cursorPosition = editor.getCursor(0).getCurrentWordBufferRange()
+    editor.getTextInBufferRange cursorPosition
+
+  loadFile: (uri) ->
+    console.log 'Loading ' + uri
+    @messages.clear()
+    @model.load uri, ((err, message, progress) ->
+      if err
+        @statusbar.setStatus 'Idris: ' + err.message
+        @messages.show()
+        @messages.clear()
+        @messages.setTitle ' Idris Errors', true
+        i = 0
+        while i < err.warnings.length
+          warning = err.warnings[i]
+          @messages.add new LineMessageView(
+            line: warning[1]
+            character: warning[2]
+            message: warning[3])
+          i++
+      else if progress
+        console.log '... ' + progress
+        @statusbar.setStatus 'Idris: ' + progress
+      else
+        @statusbar.setStatus 'Idris: ' + message
+      return
+    ).bind(this)
+    return
+
+  getDocsForWord: ->
+    word = @getWordUnderCursor()
+    @model.docsFor word
+    return
+
+  getTypeForWord: ->
+    word = @getWordUnderCursor()
+    @model.getType word, ((err, type) ->
+      if err
+        @statusbar.setStatus 'Idris: ' + err.message
+      else
+        @messages.show()
+        @messages.clear()
+        @messages.setTitle 'Idris: Type of <tt>' + word + '</tt>', true
+        @messages.add new ProofObligationView(obligation: type)
+      return
+    ).bind(this)
+    return
+
+  doCaseSplit: ->
+    editor = atom.workspace.getActiveEditor()
+    line = editor.getCursor(0).getBufferRow()
+    word = @getWordUnderCursor()
+    @model.caseSplit line + 1, word, ((err, split) ->
+      if err
+        @statusbar.setStatus 'Idris: ' + err.message
+      else
+        lineRange = editor.getCursor(0).getCurrentLineBufferRange(includeNewline: true)
+        editor.setTextInBufferRange lineRange, split
+      return
+    ).bind(this)
+    return
+
+  doAddClause: ->
+    editor = atom.workspace.getActiveEditor()
+    line = editor.getCursor(0).getBufferRow()
+    word = @getWordUnderCursor()
+    @model.addClause line + 1, word, ((err, clause) ->
+      if err
+        @statusbar.setStatus 'Idris: ' + err.message
+      else
+        editor.transact ->
+          # Insert a newline and the new clause
+          editor.insertNewlineBelow()
+          editor.insertText clause
+          # And move the cursor to the beginning of
+          # the new line
+          editor.moveCursorToBeginningOfLine()
+          return
+      return
+    ).bind(this)
+    return
+
+  doProofSearch: ->
+    editor = atom.workspace.getActiveEditor()
+    line = editor.getCursor(0).getBufferRow()
+    word = @getWordUnderCursor()
+    @model.proofSearch line + 1, word, ((err, res) ->
+      if err
+        @statusbar.setStatus 'Idris: ' + err.message
+      else
+        editor.transact ->
+          # Move the cursor to the beginning of the word
+          editor.moveCursorToBeginningOfWord()
+          # Because the ? in the metavariable isn't part of
+          # the word, we move left once, and then select two
+          # words
+          editor.moveCursorLeft()
+          editor.selectToEndOfWord()
+          editor.selectToEndOfWord()
+          # And then replace the replacement with the guess..
+          editor.insertText res
+          return
+      return
+    ).bind(this)
+    return

 module.exports = IdrisController


async load links.cson

async load links.cson

--- lib/insert-link-view.coffee
+++ lib/insert-link-view.coffee
@@ -32,8 +32,15 @@
         @ul class: "markdown-writer-list", outlet: "searchResult"

   initialize: ->
+    @editor = atom.workspace.getActiveEditor()
     @fetchPosts()
-    @loadSavedLinks()
+    @loadSavedLinks =>
+      @setLinkFromSelection()
+      if @textEditor.getText()
+        @urlEditor.getEditor().selectAll()
+        @urlEditor.focus()
+      else
+        @textEditor.focus()
     @handleEvents()
     @on "core:confirm", => @onConfirm()
     @on "core:cancel", => @detach()
@@ -52,14 +59,7 @@

   display: ->
     @previouslyFocusedElement = $(':focus')
-    @editor = atom.workspace.getActiveEditor()
-    @setLinkFromSelection()
     atom.workspaceView.append(this)
-    if @textEditor.getText()
-      @urlEditor.getEditor().selectAll()
-      @urlEditor.focus()
-    else
-      @textEditor.focus()

   detach: ->
     return unless @hasParent()
@@ -181,15 +181,16 @@
     catch error
       console.log(error.message)

-  loadSavedLinks: ->
-    try
-      file = @getSavedLinksPath()
-      if fs.existsSync(file)
-        @links = CSON.readFileSync(file)
+  loadSavedLinks: (callback) ->
+    file = @getSavedLinksPath()
+    setLinks = (data) => @links = data || {}; callback()
+    fs.exists file, (exists) ->
+      if exists
+        CSON.readFile file, (error, data) ->
+          setLinks(data)
+          console.log(error.message) if error
       else
-        @links = {}
-    catch error
-      console.log(error.message)
+        setLinks()

   getSavedLinksPath: ->
     atom.config.get("markdown-writer.siteLinkPath") ||


Fixes #171. Fix typo for CSS indent_char

--- lib/language-options.coffee
+++ lib/language-options.coffee
@@ -80,7 +80,7 @@

     # CSS
     css_indent_size: 2
-    css_indent_Char: " "
+    css_indent_char: " "

     # HTML
     html_indent_inner_html: false


Have all GD UI numbers shown as integers

This makes sure various properties which are changing rapidly don't
flicker as they change value, particularly a rapidly changing score
or time value.

--- app/views/play/level/GameDevTrackView.coffee
+++ app/views/play/level/GameDevTrackView.coffee
@@ -53,9 +53,7 @@
     if typeof val is 'object' and val.x? and val.y? and val.z?
       return "x: #{Math.round(val.x)}\ny: #{Math.round(val.y)}"
     if typeof val is 'number'
-      round = Math.round(val * 100) / 100
-      if name is 'time'
-        return round.toFixed(2)
+      round = Math.round(val)
       return round
     return val


Make sure destroying all temporal selection before  set position to avoid order dependent bug.

--- lib/mutation-manager.coffee
+++ lib/mutation-manager.coffee
@@ -67,12 +67,13 @@
         blockwiseSelection.setHeadBufferPosition(point)
         blockwiseSelection.skipNormalization()
     else
+      if occurrenceSelected and not mutation.isCreatedAt('will-select')
+        for selection in @editor.getSelections() when mutation = @mutationsBySelection.get(selection)
+          # When occurrenceSelected, destroy selection which is NOT exists initially.
+          unless mutation.isCreatedAt('will-select')
+            selection.destroy()
+
       for selection in @editor.getSelections() when mutation = @mutationsBySelection.get(selection)
-        # When occurrenceSelected, destroy selection which is NOT exists initially.
-        if occurrenceSelected and not mutation.isCreatedAt('will-select')
-          selection.destroy()
-          continue
-
         if occurrenceSelected and stay
           # This is essencially to clipToMutationEnd when `d o f`, `d o p` case.
           point = @clipToMutationEndIfSomeMutationContainsPoint(@vimState.getOriginalCursorPosition())


minor change

minor change

--- lib/mutation-manager.coffee
+++ lib/mutation-manager.coffee
@@ -113,11 +113,12 @@
   update: (checkpoint) ->
     # Current non-empty selection is prioritized over existing marker's range.
     # We invalidate old marker to re-track from current selection.
-    unless @selection.getBufferRange().isEmpty()
+    range = @selection.getBufferRange()
+    unless range.isEmpty()
       @marker?.destroy()
       @marker = null

-    @marker ?= @markerLayer.markBufferRange(@selection.getBufferRange(), invalidate: 'never')
+    @marker ?= @markerLayer.markBufferRange(range, invalidate: 'never')
     @bufferRangeByCheckpoint[checkpoint] = @marker.getBufferRange()

   getEndBufferPosition: ->


Remove unused arguments

Remove unused arguments

--- src/maji_history.coffee
+++ src/maji_history.coffee
@@ -17,7 +17,7 @@
     @_fireLeaveRoute()
     super # Boolean. True if matched, false otherwise

-  getFragment: (fragment, forcePushState) ->
+  getFragment: ->
     s = super
     @stripQuery(s)


Revert ""fix" crackling when opening/closing gate."

This reverts commit 2caede49d01f4ba0a63603eb3ea2f0f8a5affbfa.

--- src/scripts/Syntho.coffee
+++ src/scripts/Syntho.coffee
@@ -55,9 +55,7 @@
                 @vca.gain.linearRampToValueAtTime(1, @audioContext.currentTime + (@attack / 1000.0))
                 @vca.gain.linearRampToValueAtTime(@sustain, @audioContext.currentTime + (@attack / 1000.0) + (@decay / 1000.0))
             else
-                #@vca.gain.setValueAtTime(1, @audioContext.currentTime)
-                @vca.gain.value = 1
-
+                @vca.gain.setValueAtTime(1, @audioContext.currentTime)
             if (@filter.mod == 'adsr')
                 @filter.frequency.cancelScheduledValues(@audioContext.currentTime)
                 @filter.frequency.setValueAtTime(0, @audioContext.currentTime)
@@ -70,8 +68,7 @@
                 @vca.gain.setValueAtTime(val, @audioContext.currentTime)
                 @vca.gain.linearRampToValueAtTime(0, @audioContext.currentTime + (@release / 1000.0))
             else
-                #@vca.gain.setValueAtTime(0, @audioContext.currentTime)
-                @vca.gain.value = 0
+                @vca.gain.setValueAtTime(0, @audioContext.currentTime)

             if (@filter.mod == 'adsr')
                 val = @filter.frequency.value


Add advanced donation route

Add advanced donation route

--- src/scripts/router.coffee
+++ src/scripts/router.coffee
@@ -19,9 +19,6 @@
       @route 'workspace', 'workspace', () ->
         @appView.render('workspace')

-      @route 'donate', 'donate', () ->
-        @appView.render('donate')
-
       @route 'contents', 'contents', () ->
         @appView.render('contents')

@@ -30,6 +27,9 @@
         uuid = uuid.toLowerCase()
         uuid = settings.shortcodes[uuid] if settings.shortcodes[uuid]
         @appView.render('contents', {uuid: uuid, page: Number(page)})
+
+      @route /^donate\/?([^/;]*)?\/?([^/;]*)?\/?([^/;]*)?/, 'donate', (page, uuid, type) ->
+        @appView.render('donate', {page: page, uuid: uuid, type: type})

       @route /^(search)(?:\?q=)?(.*)/, 'search', () ->
         @appView.render('search')


To figure out later...

To figure out later...

--- src/scripts/sifter.coffee
+++ src/scripts/sifter.coffee
@@ -58,11 +58,6 @@
         do(project) ->
           @project = new Project(project, msg)
           @project.get_all_change_requests_qa(msg)
-
-  setInterval ->
-    users = robot.users
-    console.log users[0]
-  , 5000

 class Project
   constructor: (project, msg) ->


Allow parentheses to match bracketed return values

The modifications applied in 61b62ed neglected to include round brackets
as possible delimiters for multiple return values. While NARS2000's docs
don't mention this syntax anywhere, a method defined in solitaire.dyalog
assigns values to a bracketed list. This is invalid in conventional APL.

--- grammars/apl.cson
+++ grammars/apl.cson
@@ -345,22 +345,28 @@

 							|

-							(\\(\\s*\\{)      (?# 6: punctuation.definition.return-value.begin.apl)
+							(\\()             (?# 6: punctuation.definition.return-value.begin.apl)
 							(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-							(\\}\\s*\\))      (?# 7: punctuation.definition.return-value.end.apl)
+							(\\))             (?# 7: punctuation.definition.return-value.end.apl)

 							|

-							(\\{\\s*\\()      (?# 8: punctuation.definition.return-value.begin.apl)
+							(\\(\\s*\\{)      (?# 8: punctuation.definition.return-value.begin.apl)
 							(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-							(\\)\\s*\\})      (?# 9: punctuation.definition.return-value.end.apl)
+							(\\}\\s*\\))      (?# 9: punctuation.definition.return-value.end.apl)
+
+							|
+
+							(\\{\\s*\\()      (?# 10: punctuation.definition.return-value.begin.apl)
+							(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
+							(\\)\\s*\\})      (?# 11: punctuation.definition.return-value.end.apl)
 						)
 						\\s*
 					)

 					\\s*

-					(?# 10: keyword.operator.assignment.apl)
+					(?# 12: keyword.operator.assignment.apl)
 					(←)
 				)?

@@ -370,41 +376,41 @@
 				(?:
 					(?# MONADIC)
 					(?:
-						(?# 11: entity.function.name.apl)
+						(?# 13: entity.function.name.apl)
 						([A-Za-z_∆⍙][\\w∆⍙¯]*)

 						\\s*

-						(?# 12: entity.function.axis.apl)
+						(?# 14: entity.function.axis.apl)
 						(
-							(?# 13: punctuation.definition.axis.begin.apl)
+							(?# 15: punctuation.definition.axis.begin.apl)
 							(\\[)
 								\\s*
 								(?:
 									\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*

-									(?# 14: invalid.illegal.extra-characters.apl)
+									(?# 16: invalid.illegal.extra-characters.apl)
 									(.*?)
 									|
-									(?# 15: invalid.illegal.apl)
+									(?# 17: invalid.illegal.apl)
 									([^\\]]*)
 								)
 								\\s*
-							(?# 16: punctuation.definition.axis.end.apl)
+							(?# 18: punctuation.definition.axis.end.apl)
 							(\\])
 						)?

 						\\s*?

-						(?# 17: entity.function.arguments.right.apl)
+						(?# 19: entity.function.arguments.right.apl)
 						(
 							(?<=\\s|\\])[A-Za-z_∆⍙][\\w∆⍙¯]*
 							|
-							(\\()   (?# 18: punctuation.definition.arguments.begin.apl)
+							(\\()   (?# 20: punctuation.definition.arguments.begin.apl)
 							(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-							(\\))   (?# 19: punctuation.definition.arguments.end.apl)
+							(\\))   (?# 21: punctuation.definition.arguments.end.apl)
 						)
 						\\s*
 						(?=;|$)
@@ -415,110 +421,110 @@
 					(?# DYADIC/AMBIVALENT)
 					(?#==================)
 						(?:
-							(?# 20: entity.function.arguments.left.apl)
+							(?# 22: entity.function.arguments.left.apl)
 							([A-Za-z_∆⍙][\\w∆⍙¯]*\\s+)

 							|

-							(?# 21: entity.function.arguments.left.optional.apl)
+							(?# 23: entity.function.arguments.left.optional.apl)
 							(
-								(\\{)          (?# 22: punctuation.definition.arguments.begin.apl)
+								(\\{)          (?# 24: punctuation.definition.arguments.begin.apl)
 								(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-								(\\})          (?# 23: punctuation.definition.arguments.end.apl)
+								(\\})          (?# 25: punctuation.definition.arguments.end.apl)
 								|
-								(\\(\\s*\\{)   (?# 24: punctuation.definition.arguments.begin.apl)
+								(\\(\\s*\\{)   (?# 26: punctuation.definition.arguments.begin.apl)
 								(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-								(\\}\\s*\\))   (?# 25: punctuation.definition.arguments.end.apl)
+								(\\}\\s*\\))   (?# 27: punctuation.definition.arguments.end.apl)
 								|
-								(\\{\\s*\\()   (?# 26: punctuation.definition.arguments.begin.apl)
+								(\\{\\s*\\()   (?# 28: punctuation.definition.arguments.begin.apl)
 								(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-								(\\)\\s*\\})   (?# 27: punctuation.definition.arguments.end.apl)
+								(\\)\\s*\\})   (?# 29: punctuation.definition.arguments.end.apl)
 							)
 						)?

 						\\s*

 						(?:
-							(?# 28: entity.function.name.apl)
+							(?# 30: entity.function.name.apl)
 							([A-Za-z_∆⍙][\\w∆⍙¯]*)

 							\\s*

-							(?# 29: entity.function.axis.apl)
+							(?# 31: entity.function.axis.apl)
 							(
-								(?# 30: punctuation.definition.axis.begin.apl)
+								(?# 32: punctuation.definition.axis.begin.apl)
 								(\\[)
 									\\s*
 									(?:
 										\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*

-										(?# 31: invalid.illegal.extra-characters.apl)
+										(?# 33: invalid.illegal.extra-characters.apl)
 										(.*?)
 										|
-										(?# 32: invalid.illegal.apl)
+										(?# 34: invalid.illegal.apl)
 										([^\\]]*)
 									)
 									\\s*
-								(?# 33: punctuation.definition.axis.end.apl)
+								(?# 35: punctuation.definition.axis.end.apl)
 								(\\])
 							)?

 							|

-							(?# 34: entity.function.operands.apl)
+							(?# 36: entity.function.operands.apl)
 							(
-								(?# 35: punctuation.definition.operands.begin.apl)
+								(?# 37: punctuation.definition.operands.begin.apl)
 								(\\()

-								(?# 36: entity.function.operands.left.apl)
+								(?# 38: entity.function.operands.left.apl)
 								(\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*)?

 								\\s*

-								(?# 37: entity.function.name.apl)
+								(?# 39: entity.function.name.apl)
 								([A-Za-z_∆⍙][\\w∆⍙¯]*)

 								\\s*?

-								(?# 38: entity.function.axis.apl)
+								(?# 40: entity.function.axis.apl)
 								(
-									(?# 39: punctuation.definition.axis.begin.apl)
+									(?# 41: punctuation.definition.axis.begin.apl)
 									(\\[)
 										\\s*
 										(?:
 											\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*

-											(?# 40: invalid.illegal.extra-characters.apl)
+											(?# 42: invalid.illegal.extra-characters.apl)
 											(.*?)
 											|
-											(?# 41: invalid.illegal.apl)
+											(?# 43: invalid.illegal.apl)
 											([^\\]]*)
 										)
 										\\s*
-									(?# 42: punctuation.definition.axis.end.apl)
+									(?# 44: punctuation.definition.axis.end.apl)
 									(\\])
 								)?

 								\\s*

-								(?# 43: entity.function.operands.right.apl)
+								(?# 45: entity.function.operands.right.apl)
 								([A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)?

-								(?# 44: punctuation.definition.operands.end.apl)
+								(?# 46: punctuation.definition.operands.end.apl)
 								(\\))
 							)
 						)

 						\\s*

-						(?# 45: entity.function.arguments.right.apl)
+						(?# 47: entity.function.arguments.right.apl)
 						(
 							(?<=\\s|\\])[A-Za-z_∆⍙][\\w∆⍙¯]*
 							|
 							\\s*
-							(\\()   (?# 46: punctuation.definition.arguments.begin.apl)
+							(\\()   (?# 48: punctuation.definition.arguments.begin.apl)
 							(?:\\s*[A-Za-z_∆⍙][\\w∆⍙¯]*\\s*)*
-							(\\))   (?# 47: punctuation.definition.arguments.end.apl)
+							(\\))   (?# 49: punctuation.definition.arguments.end.apl)
 						)?
 					(?#==================)
 				)
@@ -527,12 +533,12 @@
 				\\s*

-				(?# 48: invalid.illegal.arguments.right.apl)
+				(?# 50: invalid.illegal.arguments.right.apl)
 				([^;]+)?

-				(?# 49: entity.function.local-variables.apl)
+				(?# 51: entity.function.local-variables.apl)
 				(
-					(?# 50: Include “;”)
+					(?# 52: Include “;”)
 					(
 						(?:
 							\\s*
@@ -541,13 +547,13 @@
 						)+
 					)
 					|
-					(?# 51: invalid.illegal.local-variables.apl)
+					(?# 53: invalid.illegal.local-variables.apl)
 					([^⍝]+)
 				)?

 				\\s*

-				(?# 52: comment.line.apl)
+				(?# 54: comment.line.apl)
 				(⍝.*)?

 			$"
@@ -564,49 +570,51 @@
 				7:  {name: "punctuation.definition.return-value.end.apl"}
 				8:  {name: "punctuation.definition.return-value.begin.apl"}
 				9:  {name: "punctuation.definition.return-value.end.apl"}
-				10: {name: "keyword.operator.assignment.apl"}
-				11: {name: "entity.function.name.apl"}
-				12: {name: "entity.function.axis.apl"}
-				13: {name: "punctuation.definition.axis.begin.apl"}
-				14: {name: "invalid.illegal.extra-characters.apl"}
-				15: {name: "invalid.illegal.apl"}
-				16: {name: "punctuation.definition.axis.end.apl"}
-				17: {name: "entity.function.arguments.right.apl"}
-				18: {name: "punctuation.definition.arguments.begin.apl"}
-				19: {name: "punctuation.definition.arguments.end.apl"}
-				20: {name: "entity.function.arguments.left.apl"}
-				21: {name: "entity.function.arguments.left.optional.apl"}
-				22: {name: "punctuation.definition.arguments.begin.apl"}
-				23: {name: "punctuation.definition.arguments.end.apl"}
+				10: {name: "punctuation.definition.return-value.begin.apl"}
+				11: {name: "punctuation.definition.return-value.end.apl"}
+				12: {name: "keyword.operator.assignment.apl"}
+				13: {name: "entity.function.name.apl"}
+				14: {name: "entity.function.axis.apl"}
+				15: {name: "punctuation.definition.axis.begin.apl"}
+				16: {name: "invalid.illegal.extra-characters.apl"}
+				17: {name: "invalid.illegal.apl"}
+				18: {name: "punctuation.definition.axis.end.apl"}
+				19: {name: "entity.function.arguments.right.apl"}
+				20: {name: "punctuation.definition.arguments.begin.apl"}
+				21: {name: "punctuation.definition.arguments.end.apl"}
+				22: {name: "entity.function.arguments.left.apl"}
+				23: {name: "entity.function.arguments.left.optional.apl"}
 				24: {name: "punctuation.definition.arguments.begin.apl"}
 				25: {name: "punctuation.definition.arguments.end.apl"}
 				26: {name: "punctuation.definition.arguments.begin.apl"}
 				27: {name: "punctuation.definition.arguments.end.apl"}
-				28: {name: "entity.function.name.apl"}
-				29: {name: "entity.function.axis.apl"}
-				30: {name: "punctuation.definition.axis.begin.apl"}
-				31: {name: "invalid.illegal.extra-characters.apl"}
-				32: {name: "invalid.illegal.apl"}
-				33: {name: "punctuation.definition.axis.end.apl"}
-				34: {name: "entity.function.operands.apl"}
-				35: {name: "punctuation.definition.operands.begin.apl"}
-				36: {name: "entity.function.operands.left.apl"}
-				37: {name: "entity.function.name.apl"}
-				38: {name: "entity.function.axis.apl"}
-				39: {name: "punctuation.definition.axis.begin.apl"}
-				40: {name: "invalid.illegal.extra-characters.apl"}
-				41: {name: "invalid.illegal.apl"}
-				42: {name: "punctuation.definition.axis.end.apl"}
-				43: {name: "entity.function.operands.right.apl"}
-				44: {name: "punctuation.definition.operands.end.apl"}
-				45: {name: "entity.function.arguments.right.apl"}
-				46: {name: "punctuation.definition.arguments.begin.apl"}
-				47: {name: "punctuation.definition.arguments.end.apl"}
-				48: {name: "invalid.illegal.arguments.right.apl"}
-				49: {name: "entity.function.local-variables.apl"}
-				50: {patterns: [{name: "punctuation.separator.apl", match: ";"}]}
-				51: {name: "invalid.illegal.local-variables.apl"}
-				52: {name: "comment.line.apl"}
+				28: {name: "punctuation.definition.arguments.begin.apl"}
+				29: {name: "punctuation.definition.arguments.end.apl"}
+				30: {name: "entity.function.name.apl"}
+				31: {name: "entity.function.axis.apl"}
+				32: {name: "punctuation.definition.axis.begin.apl"}
+				33: {name: "invalid.illegal.extra-characters.apl"}
+				34: {name: "invalid.illegal.apl"}
+				35: {name: "punctuation.definition.axis.end.apl"}
+				36: {name: "entity.function.operands.apl"}
+				37: {name: "punctuation.definition.operands.begin.apl"}
+				38: {name: "entity.function.operands.left.apl"}
+				39: {name: "entity.function.name.apl"}
+				40: {name: "entity.function.axis.apl"}
+				41: {name: "punctuation.definition.axis.begin.apl"}
+				42: {name: "invalid.illegal.extra-characters.apl"}
+				43: {name: "invalid.illegal.apl"}
+				44: {name: "punctuation.definition.axis.end.apl"}
+				45: {name: "entity.function.operands.right.apl"}
+				46: {name: "punctuation.definition.operands.end.apl"}
+				47: {name: "entity.function.arguments.right.apl"}
+				48: {name: "punctuation.definition.arguments.begin.apl"}
+				49: {name: "punctuation.definition.arguments.end.apl"}
+				50: {name: "invalid.illegal.arguments.right.apl"}
+				51: {name: "entity.function.local-variables.apl"}
+				52: {patterns: [{name: "punctuation.separator.apl", match: ";"}]}
+				53: {name: "invalid.illegal.local-variables.apl"}
+				54: {name: "comment.line.apl"}
 			endCaptures:
 				1:  {name: "keyword.operator.nabla.apl"}
 				2:  {name: "keyword.operator.lock.apl"}


whitespace

whitespace

--- src/modelFactory.coffee
+++ src/modelFactory.coffee
@@ -15,6 +15,7 @@
     (url, options) ->
       unless options?
         options = {}
+
       cacheOptions = angular.extend({}, DEFAULT_CACHE_OPTIONS, options.cacheOptions)

       class Model


path activity: re-enable, but recording activity every 15 minutes

--- salvus/hub.coffee
+++ salvus/hub.coffee
@@ -2753,8 +2753,10 @@
         else
             cb(undefined, db))

-# update notifications about non-comment activity on a file with at most this frequency
-MIN_ACTIVITY_INTERVAL_S = 60
+# update notifications about non-comment activity on a file with at most this frequency.
+
+# In deployment, I tried "1 minute" and it killed the system!
+MIN_ACTIVITY_INTERVAL_S = 60*15  # 15 minutes
 #MIN_ACTIVITY_INTERVAL_S = 10   # shorter for testing

 # prioritize notify when somebody edits a file that you edited within this many days
@@ -2835,10 +2837,10 @@
         cb            : undefined

     # completely disable
-    opts.cb?()
-    return
-
-    #dbg = (m) -> winston.debug("path_activity(#{opts.account_id},#{opts.project_id},#{opts.path}): #{m}")
+    ##opts.cb?()
+    ##return
+
+    dbg = (m) -> winston.debug("path_activity(#{opts.account_id},#{opts.project_id},#{opts.path}): #{m}")

     {path, action} = normalize_path(opts.path)
     if not path?
@@ -2851,6 +2853,7 @@
         opts.cb?()
         return

+    dbg("recording new activity")
     path_activity_cache[key] = true
     setTimeout( (()=>delete path_activity_cache[key]), MIN_ACTIVITY_INTERVAL_S*1000)


updated test instance ssh keys

updated test instance ssh keys

--- scripts/node-testing/shell-scripts.coffee
+++ scripts/node-testing/shell-scripts.coffee
@@ -17,7 +17,7 @@
     nodejsServer : (publicIpAddress) ->

       return "ssh -o 'StrictHostKeyChecking no' \
-      -i $KODING_DEPLOYMENT_KEY \
+      -i ./scripts/test-instance/koding-test-instances-2015-06.pem \
       ubuntu@#{publicIpAddress} \
       'sudo /opt/koding/run nodeservertests'"


chore(karma): Generate coverage info for js files

--- misc/grunt/karma.coffee
+++ misc/grunt/karma.coffee
@@ -17,6 +17,7 @@
       singleRun: true
       preprocessors:
         "test/**/*.coffee": ["coffee"]
+        "src/**/*.js": ["coverage"]
         "src/**/*.coffee": ["coverage"]
         "**/*.html": ["ng-html2js"]
       coverageReporter:


Write to stderr instead, for quicker flushing

--- tasks/spec-task.coffee
+++ tasks/spec-task.coffee
@@ -39,7 +39,7 @@
       grunt.verbose.writeln "Launching #{path.basename(packagePath)} specs."
       spawn options, (error, results, code) ->
         if process.platform is 'win32'
-          process.stdout.write(fs.readFileSync(path.join(packagePath, 'ci.log')))
+          process.stderr.write(fs.readFileSync(path.join(packagePath, 'ci.log')))
           fs.unlinkSync(path.join(packagePath, 'ci.log'))

         failedPackages.push path.basename(packagePath) if error
@@ -77,7 +77,7 @@

     spawn options, (error, results, code) ->
       if process.platform is 'win32'
-        process.stdout.write(fs.readFileSync('ci.log'))
+        process.stderr.write(fs.readFileSync('ci.log'))
         fs.unlinkSync('ci.log')
       else
         # TODO: Restore concurrency on Windows


Make help query regular expression case insensitive.

--- src/scripts/help.coffee
+++ src/scripts/help.coffee
@@ -9,7 +9,7 @@
   robot.respond /help\s*(.*)?$/i, (msg) ->
     cmds = robot.helpCommands()
     if msg.match[1]
-      cmds = cmds.filter (cmd) -> cmd.match(new RegExp(msg.match[1]))
+      cmds = cmds.filter (cmd) -> cmd.match(new RegExp(msg.match[1], 'i'))
     emit = cmds.join("\n")
     unless robot.name is 'Hubot'
       emit = emit.replace(/(H|h)ubot/g, robot.name)


match only the word hate

match only the word hate

--- src/hate.coffee
+++ src/hate.coffee
@@ -11,6 +11,6 @@
 #   Sam Lambert

 module.exports = (robot) ->
-  robot.hear /hate/i, (msg) ->
+  robot.hear /\b(hate)\b/i, (msg) ->
     if Math.random() < 0.01
       msg.send 'http://i.imgur.com/A3YuiZ0.jpg'


fix(cell): reenable transclude, so text is always wrapped #9

--- modules/directives/cell/index.coffee
+++ modules/directives/cell/index.coffee
@@ -2,6 +2,12 @@

 angular.module('bp.directives').directive 'bpCell', ->
   restrict: 'E'
-  link: (scope, element, attrs) ->
-    element.attr
-      role: 'listitem'
+  transclude: true
+  template: ''
+  compile: (elem, attrs, transcludeFn) ->
+    (scope, element, attrs) ->
+      transcludeFn scope, (clone) ->
+        element
+          .attr(
+            role: 'listitem')
+          .append clone


Prep for components directory

Prep for components directory

--- gulp-tasks.coffee
+++ gulp-tasks.coffee
@@ -4,6 +4,7 @@

 files =
   html: './html/**/*.ect'
+  components: './{components,}/**/*.html'
   js: ['./{js,}/main.coffee', './{js,}/project.coffee']
   css: ['./{css,}/main.styl']

@@ -45,6 +46,11 @@
       .pipe filelog()
   return

+gulp.task 'components', ->
+  gulp.src files.components
+    .pipe gulp.dest buildDir
+    .pipe filelog()
+
 gulp.task 'js', ->
   browserify = require 'browserify'
   coffeeify = require 'coffeeify'
@@ -74,10 +80,11 @@
     .pipe filelog()
   return

-gulp.task 'build', ['html', 'js', 'css']
+gulp.task 'build', ['html', 'components', 'js', 'css']

 gulp.task 'watch', ['build'], ->
   gulp.watch files.html, ['html']
+  gulp.watch files.components, ['components']
   gulp.watch files.js, ['js']
   gulp.watch files.css, ['css']
   return


Refactor build gulp task

Refactor build gulp task

--- gulp/build.coffee
+++ gulp/build.coffee
@@ -1,15 +1,17 @@
-coffee      = require 'gulp-coffee'
-del         = require 'del'
+coffee = require 'gulp-coffee'
+del = require 'del'
 runSequence = require 'run-sequence'

 module.exports = (gulp) ->
-  gulp.task 'build', (next) ->
-    runSequence 'build:clean', 'build:src', next
+  gulp.task 'build', (callback) ->
+    runSequence 'build:clean', 'build:src', callback

-  gulp.task 'build:clean', (next) ->
-    del './build', force: true, next
+
+  gulp.task 'build:clean', (callback) ->
+    del './build', force: true, callback
+

   gulp.task 'build:src', ->
-    gulp.src(['index.coffee', 'src/!(*.spec)*.coffee'])
+    gulp.src('src/endpoint.coffee')
       .pipe(coffee({bare: true}))
       .pipe(gulp.dest('build/src'))


Extracting events interface out of key handling

--- src/keys.coffee
+++ src/keys.coffee
@@ -23,13 +23,6 @@

 Kona.Keys =
-
-  # Contains info on keys and their associated handler(s)
-  # Example structure:
-  #
-  #       65: [ <function>, <function> ]
-  #       17: [ <function> ]
-  _handlers: {}

   # Mapping of special names --> keycode
   _keycodes: {
@@ -100,22 +93,18 @@
   #   * __key__ - (String) The key to bind to, ex: `'b'`
   #   * __handler__ - (Function) The handler function to invoke when key is pressed
   #
-  bind: (key, handler) ->
+  bind: (key, fn) ->
     key     = key.replace(/\s/g, '')
     keycode = @_keycodes[key] || key.toUpperCase().charCodeAt(0)
-    @_handlers[keycode] ||= []
-    @_handlers[keycode].push(handler)
+    Kona.Events.bind("key_#{keycode}", fn)

   # Internally invoke the associated handler function when a bound key is pressed,
   # and stops further event propagation
   dispatch: (event) ->
     keycode = @eventKeyCode(event)
-    return if @reject(event) || !@_handlers[keycode]?
-
-    for handler in @_handlers[keycode]
-      handler.call(event)
-      false
+    return if @reject(event)
+    Kona.Events.trigger("key_#{keycode}")

   # Ignore keypresses from elements that take keyboard data input,
@@ -132,6 +121,7 @@
   eventKeyCode: (event) -> event.which || event.keyCode

+
 Kona.ready ->

   # Wire up keydown and keyup events to associated handlers if they exist


new way of bindding keyboard-buttons

new way of bindding keyboard-buttons

--- src/kick.coffee
+++ src/kick.coffee
@@ -212,16 +212,25 @@
             @reset()

+bind_menu_hotkeys = (event) ->
+    hotkeys =
+        start: [13] # enter
+        howto: [72] # h
+        gotit: [13] # enter
+    for id, keys of hotkeys
+        button = $("##{id}")
+        if button.is(':visible') and event.keyCode in keys
+            return button.click()
+
+
 $(document).keydown (event) ->
-    if not animate.id?
-        if event.keyCode == 13 # enter
-            animate.start()
-            pool.easter_egg()
-    else
+    if animate.id?
         if event.keyCode == 27 # escape
             animate.pause()
         if event.keyCode in [8, 46] # backspace, delete
             player.reset()
+    else
+        bind_menu_hotkeys(event)

 $(document).keypress (event) ->


remove span if parent does not need

remove span if parent does not need

--- src/line.coffee
+++ src/line.coffee
@@ -103,11 +103,16 @@
   removeRedundant: ->
     key = '_tandemAttributes' + Math.floor(Math.random() * 100000000)
     @node[key] = {}
-    Tandem.Utils.traversePreorder(@node, 0, (node) ->
+    Tandem.Utils.traversePreorder(@node, 0, (node) =>
       if node.nodeType == node.ELEMENT_NODE && node.textContent.length == 0
         return Tandem.Utils.unwrap(node)
-      if node.tagName == 'SPAN' && (node.childNodes.length == 0 || _.any(node.childNodes, (child) -> child.nodeType == child.ELEMENT_NODE))
-        return Tandem.Utils.unwrap(node)
+      if node.tagName == 'SPAN'
+        # Check if children need us
+        if node.childNodes.length == 0 || !_.any(node.childNodes, (child) -> child.nodeType != child.ELEMENT_NODE)
+          return Tandem.Utils.unwrap(node)
+        # Check if parent needs us
+        else if node.previousSibling == null && node.nextSibling == null && !TandemLine.isLineNode(node.parentNode)
+          return Tandem.Utils.unwrap(node)
       attribute = Tandem.Utils.getAttributeForContainer(node)
       if attribute?
         if node.parentNode[key][attribute] == true


Keep options sorted

Keep options sorted

--- src/list.coffee
+++ src/list.coffee
@@ -36,8 +36,8 @@
     options.alias('b', 'bare').boolean('bare').describe('bare', 'Print packages one per line with no formatting')
     options.alias('h', 'help').describe('help', 'Print this usage message')
     options.alias('i', 'installed').boolean('installed').describe('installed', 'Only list installed packages/themes')
+    options.alias('j', 'json').boolean('json').describe('json',  'Output all packages as a JSON object')
     options.alias('t', 'themes').boolean('themes').describe('themes', 'Only list themes')
-    options.alias('j', 'json').boolean('json').describe('json',  'Output all packages as a JSON object')

   isPackageDisabled: (name) ->
     @disabledPackages.indexOf(name) isnt -1


fix #2581

fix #2581

--- src/smc-hub/auth.coffee
+++ src/smc-hub/auth.coffee
@@ -404,11 +404,8 @@
         dbg("handle_get_api_key")
         if req.query.get_api_key
             cookies = new Cookies(req, res)
-            # The maxAge is important -- it has to be long enough for the user to agree to
-            # the oauth.  However, if the user were to not complete the process, then try to
-            # do a normal login and the cookie were still there, it would take them
-            # to the api screen, so it's important that this expire.
-            cookies.set(api_key_cookie_name(base_url), req.query.get_api_key, {maxAge:60*1000})
+            # maxAge: User gets up to 60 minutes to go through the SSO process...
+            cookies.set(api_key_cookie_name(base_url), req.query.get_api_key, {maxAge:30*60*1000})
         next()

     # Define user serialization


invoke callback on listening error

invoke callback on listening error

https://github.com/bladepan/nodermi/issues/10
apparently the best document is hide somewhere in the code comment

--- src/main.coffee
+++ src/main.coffee
@@ -95,12 +95,23 @@
         @server.post('/',(req, res)=>
             @handleRemoteRequest(req, res)
         )
-
-
-        # apparently the callback only fired when it is sucess
-        @server.listen(@port,@host,511, (err)=>
-            if callback?
+        callbackFired = false
+        errorHandler = (err)->
+            if callback
+                callback err
+                callbackFired = true
+
+        httpServer = http.createServer(@server)
+
+        httpServer.on('error',errorHandler)
+
+        # apparently the callback is fired on 'listening' event, aka, it
+        # is only triggered when listening is successful.
+        # http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
+        httpServer.listen(@port,@host,511, (err)=>
+            if callback? and not callbackFired
                 callback err, this
+                @server.removeListener('error', errorHandler)
             @_log "RmiService listening on #{@port}"
         )


Fixed empty args

Fixed empty args

--- src/main.coffee
+++ src/main.coffee
@@ -27,7 +27,6 @@
 		@bot = new irc.client key
 		@bot._emit = @bot.emit
 		@bot.emit = (name)=>
-			# console.log arguments
 			@module.proxyEvent arguments
 			@bot._emit.apply(@bot, arguments)
 		@bot.chat = (msg)->
@@ -147,7 +146,7 @@
 			cmd = message.substring(1, index)

 			if index == message.length
-				args = null
+				args = []
 			else
 				args = message.substring index
 				args = args.trim()
@@ -163,8 +162,14 @@
 			else
 				user.sub = false

+			@bot.emit 'command', user, cmd, args

-			@bot.emit 'command', user, cmd, args
+		dm = (new RegExp('^@?' + config.irc.identity.username + '\\b\\s*')).exec(message)
+		if dm
+			@bot.emit 'message', user, message.substr(dm[0].length)
+
+
+

 	connect: =>


if window is hidden in tray, restore when running yakyak again

closes #1162

--- src/main.coffee
+++ src/main.coffee
@@ -82,6 +82,7 @@
 # If someone tries to run a second instance, we should focus our window.
 app.on 'second-instance', (event, commandLine, workingDirectory) ->
     if mainWindow
+        mainWindow.show() if !mainWindow.isVisible()
         mainWindow.restore() if mainWindow.isMinimized()
         mainWindow.focus()


Initial fixes of lists tab We need to test this in iPhone to make sure my changes do not break anything.

--- Resources/ui.liststab.coffee
+++ Resources/ui.liststab.coffee
@@ -51,6 +51,7 @@
       moveable: true
     })
     tableView.addEventListener('click', (e) ->
+      thistable = this
       Ti.API.info(JSON.stringify(e.row))
       if e.row.listID == 'custom'
         addW = Ti.UI.createWindow({
@@ -86,6 +87,12 @@
             })
             # TODO : show a list of prospects to add to the list
             addW.close()
+            if shl.ui.isAndroid
+              lists = shl.List.find({
+                where: {active: 1},
+                order: 'weight ASC'
+              })
+              thistable.updateLists(lists)
           else
             alert('You must specify a name for the list.')
         )
@@ -142,7 +149,8 @@
           else
             currentList = shl.List.find(e.row.listID)
             prospects = currentList.getProspectList()
-            listWin.setRightNavButton(listedit)
+            if not shl.ui.isAndroid
+              listWin.setRightNavButton(listedit)
             listview.editing = false
           data = shl.ui.processProspectData(prospects)
           listview.setData(data)
@@ -179,12 +187,16 @@
           currentListing.destroy()
         )

+
+
         listWin.add(listview)
         listedit = Titanium.UI.createButton({
           title:'Edit'
         })
-        listedit.addEventListener('click', () ->
-          listWin.setRightNavButton(listcancel)
+
+        makebrow = () ->
+          if not shl.ui.isAndroid
+            listWin.setRightNavButton(listcancel)
           listview.editing = true
           brow = Ti.UI.createTableViewRow({
             backgroundColor : '#999',
@@ -233,7 +245,8 @@
                   listing.destroy()
                 currentList = shl.List.find(e.row.listID)
                 prospects = currentList.getProspectList()
-                listWin.setRightNavButton(listedit)
+                if not shl.ui.isAndroid
+                  listWin.setRightNavButton(listedit)
                 listview.editing = false
                 data = shl.ui.processProspectData(prospects)
                 listview.setData(data)
@@ -272,19 +285,28 @@
             listview.insertRowBefore(0,brow)
           else
             listview.appendRow(brow)
-        )
+
+        listedit.addEventListener('click', makebrow)
+
+

         listcancel = Titanium.UI.createButton({
           title:'Done',
           style:Titanium.UI.iPhone.SystemButtonStyle.DONE
         })
         listcancel.addEventListener('click', () ->
-          listWin.setRightNavButton(listedit)
+          if not shl.ui.isAndroid
+            listWin.setRightNavButton(listedit)
           listview.editing = false
           index = listview.getIndexByName('options');
           listview.deleteRow(index,{animationStyle:Titanium.UI.iPhone.RowAnimationStyle.UP})
         )
-        listWin.setRightNavButton(listedit)
+        if not shl.ui.isAndroid
+          listWin.setRightNavButton(listedit)
+        else
+          makebrow()
+
+

         shl.ui.tabs.activeTab.open(listWin)
     )
@@ -297,7 +319,8 @@
   createAddProspectsWindow : (listId) ->
     self = this
     win = Ti.UI.createWindow({
-      title : 'Add Prospects'
+      title : 'Add Prospects',
+      backgroundColor : '#000000'
     })
     doneBtn = Ti.UI.createButton({
       title:'Done',
@@ -307,7 +330,8 @@
     doneBtn.addEventListener('click', () ->
       win.close()
     )
-    win.setRightNavButton(doneBtn)
+    if not shl.ui.isAndroid
+      win.setRightNavButton(doneBtn)
     prospects = shl.Prospect.find()
     if prospects.length < 1
       return win


proper package deactivation

proper package deactivation

--- lib/block-cursor.coffee
+++ lib/block-cursor.coffee
@@ -44,6 +44,8 @@
     @primaryColorObserveSubscription.dispose()
     @secondaryColorObserveSubscription.dispose()
     @pulseDurationObserveSubscription.dispose()
+    cursorStyle.parentNode.removeChild cursorStyle
+    cursorStyle = null

   applyCursorType: (cursorTypeName) ->
     @cursorType = cursorType = cursorTypeMap[cursorTypeName]


Wait for package activation promise

Wait for package activation promise

--- spec/command-palette-spec.coffee
+++ spec/command-palette-spec.coffee
@@ -7,10 +7,17 @@
   beforeEach ->
     atom.workspaceView = new WorkspaceView
     atom.workspaceView.openSync('sample.js')
-    atom.packages.activatePackage("command-palette")
+
+    activationPromise = atom.packages.activatePackage("command-palette")
+
     atom.workspaceView.attachToDom().focus()
     atom.workspaceView.trigger 'command-palette:toggle'
-    palette = atom.workspaceView.find('.command-palette').view()
+
+    waitsForPromise ->
+      activationPromise
+
+    runs ->
+      palette = atom.workspaceView.find('.command-palette').view()

   afterEach ->
     atom.workspaceView.remove()


Change module.loaders to module.rules syntax

--- src/webpack.config.coffee
+++ src/webpack.config.coffee
@@ -618,14 +618,14 @@
         hashFunction  : 'sha256'

     module:
-        loaders: [
-            { test: /pnotify.*\.js$/, loader: "imports?define=>false,global=>window" },
-            { test: /\.cjsx$/,   loaders: ['coffee-loader', 'cjsx-loader'] },
+        rules: [
+            { test: /pnotify.*\.js$/, use: "imports?define=>false,global=>window" },
+            { test: /\.cjsx$/,   use: ['coffee-loader', 'cjsx-loader'] },
             { test: /\.coffee$/, loader: 'coffee-loader' },
-            { test: /\.less$/,   loaders: ["style-loader", "css-loader", "less-loader?#{cssConfig}"]}, #loader : extractTextLess }, #
-            { test: /\.scss$/,   loaders: ["style-loader", "css-loader", "sass-loader?#{cssConfig}"]}, #loader : extractTextScss }, #
-            { test: /\.sass$/,   loaders: ["style-loader", "css-loader", "sass-loader?#{cssConfig}&indentedSyntax"]}, # ,loader : extractTextSass }, #
-            { test: /\.json$/,   loaders: ['json-loader'] },
+            { test: /\.less$/,   use: ["style-loader", "css-loader", "less-loader?#{cssConfig}"]}, #loader : extractTextLess }, #
+            { test: /\.scss$/,   use: ["style-loader", "css-loader", "sass-loader?#{cssConfig}"]}, #loader : extractTextScss }, #
+            { test: /\.sass$/,   use: ["style-loader", "css-loader", "sass-loader?#{cssConfig}&indentedSyntax"]}, # ,loader : extractTextSass }, #
+            { test: /\.json$/,   use: ['json-loader'] },
             { test: /\.png$/,    loader: "file-loader?#{pngconfig}" },
             { test: /\.ico$/,    loader: "file-loader?#{icoconfig}" },
             { test: /\.svg(\?[a-z0-9\.-=]+)?$/,    loader: "url-loader?#{svgconfig}" },
@@ -641,7 +641,7 @@
             { test: /\.ttf(\?[a-z0-9\.-=]+)?$/, loader: "url-loader?limit=10000&mimetype=application/octet-stream" },
             { test: /\.eot(\?[a-z0-9\.-=]+)?$/, loader: "file-loader?name=#{hashname}" },
             # ---
-            { test: /\.css$/, loaders: ["style-loader", "css-loader?#{cssConfig}"]}, # loader: extractTextCss }, #
+            { test: /\.css$/, use: ["style-loader", "css-loader?#{cssConfig}"]}, # loader: extractTextCss }, #
             { test: /\.pug$/, loader: 'pug-loader' },
         ]


:fire: Remove an outdated spec

:fire: Remove an outdated spec

--- spec/linter-registry-spec.coffee
+++ spec/linter-registry-spec.coffee
@@ -44,20 +44,6 @@
       expect(linterRegistry.hasLinter(linter)).toBe(false)
       linterRegistry.deactivate()
   describe '::lint', ->
-    it "doesn't lint if textEditor is deactivated", ->
-      linterRegistry = new LinterRegistry
-      editorLinter = new EditorLinter(atom.workspace.getActiveTextEditor())
-      editorLinter.status = false
-      linter = {
-        grammarScopes: ['*']
-        lintOnFly: false
-        modifiesBuffer: false
-        scope: 'file'
-        lint: ->
-      }
-      linterRegistry.addLinter(linter)
-      expect(linterRegistry.lint({onChange: false, editorLinter})).toBeUndefined()
-      linterRegistry.deactivate()
     it "doesn't lint if textEditor isn't active one", ->
       linterRegistry = new LinterRegistry
       editorLinter = new EditorLinter(atom.workspace.getActiveTextEditor())


try again to correct the leak reported by travis

--- test/alarm_test.coffee
+++ test/alarm_test.coffee
@@ -45,7 +45,7 @@

     describe "POST alarms/", ->

-        before (done) =>
+        before (done) ->
             @alarm =
                 action: 'DISPLAY'
                 trigg: "Tue Apr 23 2013 14:25:00"


levels and default game states

levels and default game states

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -1,5 +1,5 @@
 TitleScreen = (I={}) ->
-  self = Tex(I)
+  self = TextScree(I)

   self.bind 'update', ->
     engine.nextLevel() if justPressed.any


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -1,5 +1,5 @@
 ###*
-The TimedEvents module allows arbitrary code to be executed at set intervals.
+The TimedEvents module allows arbitrary code to be executed at set intervals. GameObject includes this module by default

 player = GameObject()


levels and default game states

levels and default game states

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -7,6 +7,6 @@
   self.bind "overlay", (canvas) ->
     self.centerText canvas, App.name

-    self.centerText canvas, "Press any key to start", s
+    self.centerText canvas, "Press any key to start", size:

   return self


Check for proper HTML text handling

Check for proper HTML text handling

--- test/elvis-test.coffee
+++ test/elvis-test.coffee
@@ -137,6 +137,10 @@
         ' bar'
       ])
       expect(element.innerHTML).to.equal('foo bar')
+
+    it 'handles HTML text sanely', ->
+      html = el('div', 'foo').innerHTML
+      expect(html).to.equal('<span>foo</span>')

   it 'ignores null', ->
     element = el('div', null)


update firebase path for card creation to "newCard"

--- routes/index.coffee
+++ routes/index.coffee
@@ -26,7 +26,7 @@
   req.body.secret = undefined

   for friendId in req.body.friends
-    firebase.child(friendId).child('created').update
+    firebase.child(friendId).child('newCard').update
       "#{req.body.cardId}":
         userId: req.body.userId
         dts: req.body.dts


Re-enable web

Re-enable web

--- src/assets/javascripts/application.coffee
+++ src/assets/javascripts/application.coffee
@@ -3,6 +3,4 @@
 Web = require './web'
 Mobile = require './mobile'

-$ ->
-  # if Device.isTouch() then new Mobile else new Web
-  new Mobile
+$ -> if Device.isTouch() then new Mobile else new Web


Removed Postgres on Index

Removed Postgres on Index

There trying to find out more postgres information before i write it.

--- help/index.coffee
+++ help/index.coffee
@@ -30,7 +30,6 @@
   help sudo             What is my sudo pass?
   help specs            What are my VMs specifications?
   help mysql            Connect to your MySQL Server on Koding
-  help postgresql       Connect to your PostgreSQL on Koding
   help mongodb          Connect to your MongoDB on Koding
   help ftp              Connect to your VM through FTP


fix specs

fix specs

--- test/index-spec.coffee
+++ test/index-spec.coffee
@@ -508,8 +508,8 @@
       it 'should not have an error', ->
         expect(@error).not.to.exist

-      it 'should return a result merged with the original device (to preserve token)', ->
-        expect(@result).to.deep.equal uuid: '123', token: '456', stuff: []
+      it 'should return the device', ->
+        expect(@result).to.deep.equal uuid: '123', stuff: []

   describe 'subscribe', ->
     beforeEach ->
@@ -539,4 +539,4 @@
       @sut.updateGateblu => done()

     it 'should call update on meshblu', ->
-      expect(@fakeConnection.update).to.have.been.calledWith uuid: 'guid', devices: [type: 'bar'], version: "5.0.0"
+      expect(@fakeConnection.update).to.have.been.calledWith uuid: 'guid', devices: [type: 'bar'], version: "5.0.1"


* typo testing

* typo testing

--- test/index-test.coffee
+++ test/index-test.coffee
@@ -226,7 +226,7 @@
       result = task.inspect(true)
       expect(result).to.be.equal '<Task "Simple": "one":124>'

-    it.only 'should inspect via debug and options', ->
+    it 'should inspect via debug and options', ->
       task = Task.create 'Simple', one:124
       result = task.inspect(true, one:10, two:2)
       expect(result).to.be.equal '<Task "Simple": "one":10>'


Add asm support

Add asm support

Most assemblers support `;` as a comment marker, but multiline comments are far from standardised. Some assemblers (notably, nasm) don't support them at all as far as I can tell. This is to enable at least support for counting lines in assembly files using the standard `;` comment marker.

--- src/sloc.coffee
+++ src/sloc.coffee
@@ -55,7 +55,7 @@
           ///
         r._matchGroup_ = 1 # dirty fix
         r
-      when "rkt", "clj", "cljs", "hy"
+      when "rkt", "clj", "cljs", "hy", "asm"
         /;/
       else null

@@ -242,6 +242,7 @@
   { total, source, comment, single, block, mixed, empty }

 extensions = [
+  "asm"
   "c"
   "cc"
   "clj"


Don't attempt entry hubs tracking if user is logged in; change impression subject based on control vs experiment

--- src/desktop/apps/home/client/index.coffee
+++ src/desktop/apps/home/client/index.coffee
@@ -28,24 +28,24 @@
     new HomeAuthRouter
     Backbone.history.start pushState: true

-    targetElement = if sd.HOMEPAGE_COLLECTION_HUB_ENTRYPOINTS_TEST is "experiment" then ".home-hubs-entry" else ".home-browse-module"
-
-    # Remove after closing the homepage hubs entry points test
-    $(targetElement).waypoint(() ->
-      # Fire impression event
-      analytics.track("Impression", {
-        context_page: "Home",
-        context_module: "HubEntrypoint",
-        subject: "Featured Categories",
+    if !sd.CURRENT_USER
+      isExperiment = sd.HOMEPAGE_COLLECTION_HUB_ENTRYPOINTS_TEST is "experiment"
+      targetElement = if isExperiment then ".home-hubs-entry" else ".home-browse-module"
+      # Remove after closing the homepage hubs entry points test
+      $(targetElement).waypoint(() ->
+        # Fire impression event
+        analytics.track("Impression", {
+          context_page: "Home",
+          context_module: "HubEntrypoint",
+          subject: if isExperiment then "Featured Categories" else "Browse Works for Sale",
+        })
+        # Fire experiment or control viewed event
+        splitTest("homepage_collection_hub_entrypoints_test").view()
+      ,
+      {
+        triggerOnce: true,
+        offset: 500,
       })
-      # Fire experiment viewed event
-      splitTest("homepage_collection_hub_entrypoints_test").view()
-    ,
-    {
-      triggerOnce: true,
-      offset: 500,
-    }
-    )

     # Render Featured Sections
     @setupHeroUnits()


minor disas tweaks

minor disas tweaks

--- src/disassembler.coffee
+++ src/disassembler.coffee
@@ -49,16 +49,21 @@
     rv += access_string m.access_flags
     rv += if m.access_flags.static then 'static ' else ''
     # TODO other flags
-    rv += (m.return_type?.type or "") + " "
-    rv += m.name
+    if m.name is '<init>'  # constructors are special-cased
+      rv += canonical(class_file.this_class)
+    else
+      rv += (m.return_type?.type or "") + " "
+      rv += m.name
     rv += "(#{p.type for p in m.param_types});"
     rv += "\n"
     unless m.access_flags.native or m.access_flags.abstract
       rv += "  Code:\n"
       code = m.get_code()
-      rv += "   Stack=#{code.max_stack}, Locals=#{code.max_locals}, Args_size=#{m.param_types.length}\n"
+      args_size = m.param_types.length + (if m.access_flags.static then 0 else 1)  # nonstatic methods get 'this'
+      rv += "   Stack=#{code.max_stack}, Locals=#{code.max_locals}, Args_size=#{args_size}\n"
       code.each_opcode((idx, oc) ->
         rv += "   #{idx}:\t#{oc.name}"
+        #TODO: add the appropriate comments for the refs here (as in the constant pool)
         rv += switch oc.constructor.name
           when 'InvokeOpcode' then "\t##{oc.method_spec_ref};"
           when 'ClassOpcode' then "\t##{oc.class_ref};"
@@ -69,12 +74,11 @@
           else ""
         rv += "\n"
       )
-      rv += "\n"
       for attr in code.attrs
         switch attr.constructor.name
           when 'LineNumberTable'
             rv += "  LineNumberTable:\n"
-            rv += "   line#{entry.line_number}: #{entry.start_pc}\n" for entry in attr
+            rv += "   line #{entry.line_number}: #{entry.start_pc}\n" for entry in attr
             rv += "\n"
           when 'StackMapTable'
             rv += "  StackMapTable: number_of_entries = #{attr.num_entries}\n"


[master] bug fix

[master] bug fix

--- scraper/guba.coffee
+++ scraper/guba.coffee
@@ -114,6 +114,6 @@
   database.redis.getConnection(0)
   .then (redis) ->
     parseAll redis
-  .then ->
-    redis.closeConnection()
+    .then ->
+      redis.closeConnection()
   .done()


fix input method's marker range, now we can input symbols in between other words

--- lib/input-method.coffee
+++ lib/input-method.coffee
@@ -20,55 +20,55 @@

       # range & marker
       start = @agda.editor.getCursorBufferPosition()
-      end = start.translate new Point 0, 1
-      range = new Range start, end
-      @marker = @agda.editor.markBufferRange range
+      @marker = @agda.editor.markBufferRange(new Range start, start)

       # insert '\' to the buffer
       @agda.editor.getBuffer().insert start, '\\'

       # kick off the decorator view
-      @decorator.resize range
+      @decorator.resize @marker.bufferMarker.range

       # triggered then new characters are typed in
       @marker.on 'changed', (ev) =>
-
         # range & decorator
         range = new Range ev.newTailBufferPosition, ev.newHeadBufferPosition

+        # console.log "old range: #{@marker.bufferMarker.range.start} #{@marker.bufferMarker.range.end}"
+        # console.log "new range: #{range.start} #{range.end}"
+
         # input content
-        content = @agda.editor.getBuffer().getTextInRange range
-        content = content.substr 1 # strip the leading \
+        content = @agda.editor.getBuffer().getTextInRange(range).substr(1)

         # see if the input is in the keymap
         {valid, result} = @validate content

         if valid
-          # no further possible key combinations
-          # replace with symbol right away
           if Object.keys(result).length is 1
+            # no further possible key combinations
+            # replace with symbol right away
             @deactivate()
             symbol = result['>>'][0]
             @agda.editor.getBuffer().setTextInRange range, symbol

-          # further key combinations are possible
           else
+            # further key combinations are possible
             @decorator.resize range

-        # key combination out of keymap
-        # replace with closest the symbol possible
         else
+          # key combination out of keymap
+          # replace with closest the symbol possible
           @deactivate()
           symbol = result['>>']
           if symbol.length > 0
             lastInput = content.substr -1
             refill = symbol[0] + lastInput
+            # console.log "symbol #{symbol} lastInput #{lastInput} refill #{refill}"
             @agda.editor.getBuffer().setTextInRange range, refill

-    # input method already activated
-    # this will happen only 2 consecutive backslash '\' was punched in
-    # and we shall leave 1 backslash in the buffer, then deactivate
     else
+      # input method already activated
+      # this will happen only 2 consecutive backslash '\' was punched in
+      # and we shall leave 1 backslash in the buffer, then deactivate
       @deactivate()


cleanup baseUrl

cleanup baseUrl

--- src/api/settings.coffee
+++ src/api/settings.coffee
@@ -1,7 +1,4 @@
 settings =
-  # to customize, set environmental var BASE_URL when building or running webpack-dev-server
-  # Currently is set on an endpoint by endpoint basis until all are implemented by BE
-  # baseUrl: process?.env?.BASE_URL

   endpoints:
     'exercise.*.send.save':
@@ -27,21 +24,20 @@
     'task.*.send.fetchByModule':
       url: 'api/cc/tasks/{collectionUUID}/{moduleUUID}'
       method: 'GET'
-      # baseUrl: process?.env?.BASE_URL
+      loadLocally: true
       completedEvent: 'task.{collectionUUID}/{moduleUUID}.receive.fetchByModule'

     'user.send.statusUpdate':
       url: 'auth/status'
       method: 'GET'
       useCredentials: true
-      baseUrl: process?.env?.BASE_URL
       completedEvent: 'user.receive.statusUpdate'

     'course.*.send.registration':
       url: 'api/enrollment_changes'
       method: 'POST'
       useCredentials: true
-      baseUrl: process?.env?.BASE_URL
+      loadLocally: true
       failedEvent: 'course.{book_uuid}.receive.registration.failure'
       completedEvent: 'course.{book_uuid}.receive.registration.complete'

@@ -49,7 +45,7 @@
       url: 'api/enrollment_changes/{id}/approve'
       method: 'PUT'
       useCredentials: true
-      baseUrl: process?.env?.BASE_URL
+      loadLocally: true
       failedEvent: 'course.{id}.receive.confirmation.failure'
       completedEvent: 'course.{id}.receive.confirmation.complete'


Implement album previews in home page history

--- scripts/home.coffee
+++ scripts/home.coffee
@@ -71,7 +71,7 @@
     pasteTarget.focus()
     setTimeout(forceFocus, 250)

-createHistoryItem = (h) ->
+createHistoryItem = (h, noLink = false) ->
     item = h.item
     container = null
     if h.base?
@@ -106,9 +106,12 @@
         preview.src = '/static/audio-player-narrow.png'
         preview.className = 'item-view'
     else if item.type == 'application/album'
-        console.log('album')
+        preview = document.createElement('div')
+        preview.className = 'album-preview'
+        for file in item.files
+            preview.appendChild(createHistoryItem(file, true))
     if preview
-        if not h.nolink
+        if not nolink
             a = document.createElement('a')
             a.href = '/' + h.hash
             a.target = '_blank'
@@ -122,7 +125,6 @@
             return 'If you leave this page, your uploads will be cancelled.'

 handleWorkerMessage = (e) ->
-    console.log(JSON.stringify(e.data))
     if e.data.execute?
         eval(e.data.execute)
     if e.data.event?
@@ -321,9 +323,6 @@
     )

 window.statusHook = (file, status, oldStatus) ->
-    console.log(file)
-    console.log(status)
-    console.log(oldStatus)
     if oldStatus?
         return if status == 'ready' and oldStatus == 'done'
     updateAlbumUI()


PLEASE PLEASE WORK

PLEASE PLEASE WORK

--- scripts/loud.coffee
+++ scripts/loud.coffee
@@ -18,7 +18,7 @@
 #   annabunches

 module.exports = (robot) ->
-  robot.hear /^([A-Z"][A-Z0-9 .,'"()\?!&$#@+-]+)$/, (res) ->
+  robot.hear /^([A-Z"][A-Z0-9 .,'"()\?!&%$#@+-]+)$/, (res) ->
     # Pick a loud from the stored list and say it. Skip if there are no louds.
     old_loud = res.random(robot.brain.get('louds'))
     if old_loud?


Bug fixing

Bug fixing

--- scripts/mail.coffee
+++ scripts/mail.coffee
@@ -46,7 +46,7 @@
         DeleteByRecipient = (recipient) ->
             if mails = GetMail()[recipient.toLowerCase()]
                 for mail, index in mails by -1
-                    if mail[0] is msg.message.user.name.toLowercase()
+                    if mail[0] is msg.message.user.name.toLowerCase()
                         mails.splice index, 1
                         ++deleted

@@ -58,17 +58,17 @@
             else
                 msg.reply "#{deleted} of your mail(s) towards #{recipient} has been deleted."
                 robot.brain.save()
-            return

         # Delete all from sender / command executor
-        for recipient, mails of GetMail()
-            DeleteByRecipient recipient
+        else
+            for recipient, mails of GetMail()
+                DeleteByRecipient recipient

-        if deleted is 0
-            msg.reply "There are no outbound mail sent by you."
-        else
-            msg.reply "#{deleted} of your mail(s) has been deleted."
-            robot.brain.save()
+            if deleted is 0
+                msg.reply "There are no outbound mail sent by you."
+            else
+                msg.reply "#{deleted} of your mail(s) has been deleted."
+                robot.brain.save()

     robot.respond /mail (\S+) (.+)/i, (msg) ->
         [_command, recipient, message] = msg.match
@@ -77,18 +77,16 @@

         if sender is recipient
             msg.reply "Are you sure you want to send a mail to yourself? Sad."
-            false
-        if recipient is robot.name.toLowerCase()
+        else if recipient is robot.name.toLowerCase()
             msg.reply "Thanks, but no thanks! I do not need any mail."
-            false
-
-        try
-            GetMail()[recipient] or= []
-            GetMail()[recipient].push [sender, moment().unix(), message]
-            robot.brain.save()
-            msg.reply "Your mail has been prepared for #{recipient}."
-        catch error
-            return robot.logger.error error
+        else
+            try
+                GetMail()[recipient] or= []
+                GetMail()[recipient].push [sender, moment().unix(), message]
+                robot.brain.save()
+                msg.reply "Your mail has been prepared for #{recipient}."
+            catch error
+                robot.logger.error error

     #
     # Hubot events


Use english fields in event display

Use english fields in event display

If the finnish field missing then use the english fields instead.

--- events/static/events/displayEvents.coffee
+++ events/static/events/displayEvents.coffee
@@ -6,8 +6,9 @@
   if Object.keys(eventData).length == 0
     $list.append $("
Tällä hetkellä ei tulevia tapahtumia.
")
   for event in eventData
+    eventName = event.name.fi || event.name.en
     if event.info_url?
-      eventLink=event.info_url.fi
+      eventLink=event.info_url.fi || event.info_url.en
     else
       eventLink = "http://www.hel.fi/www/helsinki/fi/tapahtumakalenteri/tapahtuma/?id=" + event.id
     if event.images.length > 0
@@ -15,15 +16,22 @@
     else
       eventImage = "/static/images/share-default.jpg"
     if event.location?
-      eventLocationLink = "https://palvelukartta.hel.fi/unit/" + event.location.id.split('tprek:').pop()
-      eventLocationName = event.location.name.fi
+      eventLocationLinkFi = "https://palvelukartta.hel.fi/unit/" + event.location.id.split('tprek:').pop()
+      eventLocationLinkEn = "https://servicemap.hel.fi/unit/" + event.location.id.split('tprek:').pop()
+      eventLocationName = event.location.name.fi || event.location.name.en
+      if eventLocationName == event.location.name.fi?
+        eventLocationLink = eventLocationLinkFi
+      else
+        eventLocationLink = eventLocationLinkEn
     else
       eventLocationLink = null
-      eventLocationName = event.location_extra_info.fi
+      eventLocationName = event.location_extra_info.fi || event.location_extra_info.en
     if event.short_description?
-      eventDescription = event.short_description.fi
+      eventDescription = event.short_description.fi || event.short_description.en
     else
-      eventDescription = event.description.fi.substr(0,event.description.fi.indexOf('.')+1)
+      eventDescriptionFi = event.description.fi.substr(0,event.description.fi.indexOf('.')+1)
+      eventDescriptionEn = event.description.en.substr(0,event.description.en.indexOf('.')+1)
+      eventDescription = eventDescriptionFi || eventDescriptionEn
     eventTime = moment(event.start_time).format('dd DD.MM.YYYY HH:mm')
     if grid
       $li = $("
")
@@ -35,7 +43,7 @@

aika <time datetime="#{eventTime}">#{eventTime}</time>

paikka #{eventLocationName}

-
#{event.name.fi}

+
#{eventName}

             #{eventDescription}

@@ -47,11 +55,11 @@
     else
       $li = $("
")
       template = """
-
#{event.name.fi}

+
#{eventName}

aika <time datetime="#{eventTime}">#{eventTime}</time>

paikka #{eventLocationName}

         Lue lisää »
       """
       $li.append $($.trim template)
       $footnote.before $li
-  $('.event-preview').matchHeight();+  $('.event-preview').matchHeight();


:fire: Remove getActiveTab

:fire: Remove getActiveTab

--- lib/linter-views.coffee
+++ lib/linter-views.coffee
@@ -173,10 +173,6 @@
       @renderPanel()
     @setShowPanel @showPanel

-  # TODO: Remove me and use @scope instead
-  getActiveTab: ->
-    @tabs.find (tab) -> tab.active
-
   getVisibleTabs: ->
     toReturn = new Set
     toReturn.add 'line' if atom.config.get('linter.showErrorTabLine')


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -5,7 +5,8 @@
     width: 32
     height: 32

-  # This is kind of gross, but we need to ma
+  # This is kind of gross, but we need to make sure
+  # a
   App ||= {}
   App.width ||= 480
   App.height ||= 320


Use home-rolled debounce in transcoding source

--- src/streammachine/sources/transcoding.coffee
+++ src/streammachine/sources/transcoding.coffee
@@ -32,22 +32,20 @@

         # -- watch for discontinuities -- #

-        @_pingData = _.debounce =>
+        @_pingData = new TranscodingSource.Debounce (@opts.discontinuityTimeout || 30*1000), (last_ts) =>
             # data has stopped flowing. mark a discontinuity in the chunker.
             @log?.info "Transcoder data interupted. Marking discontinuity."
-            @emit "discontinuity_stop"
+            @emit "discontinuity_stop", last_ts

             @o_stream.once "data", (chunk) =>
                 @log?.info "Transcoder data resumed. Reseting time to #{chunk.ts}."
-                @emit "discontinuity_start"
+                @emit "discontinuity_start", chunk.ts, last_ts
                 @chunker.resetTime chunk.ts
-
-        , @opts.discontinuityTimeout || 30*1000

         # -- chunking -- #

         @oDataFunc = (chunk) =>
-            @_pingData()
+            @_pingData.ping()
             @_buf.write chunk.data

         @o_stream.once "data", (first_chunk) =>


Add filename to coffeescript error messages

--- tasks/coffee_build.coffee
+++ tasks/coffee_build.coffee
@@ -54,7 +54,7 @@
             bare: not options.wrap
           })
         catch e
-          grunt.log.error("#{e.message}(line: #{e.location.last_line}, column: #{e.location.last_column})")
+          grunt.log.error("#{e.message}(file: #{file}, line: #{e.location.last_line}, column: #{e.location.last_column})")
           throw e
         grunt.log.writeln("Compiled #{file}")
         if options.sourceMap
@@ -231,7 +231,7 @@
           {js, v3SourceMap} = compile(grunt.file.read(fp), {
             sourceMap: true, bare: true})
         catch e
-          grunt.log.error("#{e.message}(line: #{e.location.last_line}, column: #{e.location.last_column})")
+          grunt.log.error("#{e.message}(file: #{fn}, line: #{e.location.last_line}, column: #{e.location.last_column})")
           throw e
       else # plain js
         js = grunt.file.read(fp)


crash reporting

crash reporting


Remove Trix.config.useMobileInputMode

Remove Trix.config.useMobileInputMode

--- src/trix.coffee
+++ src/trix.coffee
@@ -4,6 +4,4 @@
 #= require trix/elements/trix_editor_element

 @Trix =
-  config:
-    useMobileInputMode: ->
-      /iPhone|iPad|Android|Windows Phone/.test(navigator.userAgent)
+  config: {}


Hide status indicator as well when packages are uninstalled

--- lib/package-card.coffee
+++ lib/package-card.coffee
@@ -167,6 +167,7 @@
         @uninstallButton.hide()
         @settingsButton.hide()
         @enablementButton.hide()
+        @statusIndicator.hide()

     if @isInstalled() or @isDisabled()
       @installButton.hide()


Comments :memo:

Comments :memo:

--- lib/package-card.coffee
+++ lib/package-card.coffee
@@ -336,8 +336,13 @@
     @subscribe @packageManager, event, (pack, error) =>
       callback(pack, error) if pack.name is @pack.name

+  ###
+  Section: Methods that should be on a Package model
+  ###
+
   install: ->
     @installButton.addClass('is-installing')
+    # SKETCH: we shouldnt be emitting this event here
     @packageManager.emit('package-installing', @installablePack ? @pack)
     @packageManager.install @installablePack ? @pack, (error) =>
       @installButton.removeClass('is-installing')
@@ -349,6 +354,7 @@
           atom.packages.enablePackage(@pack.name)

   uninstall: ->
+    # SKETCH: we shouldnt be emitting this event here
     @packageManager.emit('package-uninstalling', @pack)
     @packageManager.uninstall @pack, (error) =>
       if error?


Updated extendAttribute. Set value to true if key exist.

--- src/util.coffee
+++ src/util.coffee
@@ -81,7 +81,12 @@
   extendAttributes: (prefix, defaults, attributes) ->
     output = {}
     for own key, value of defaults
-      output[key] = attributes["#{prefix}#{@capitalize key}"] or value
+      macKey = "#{prefix}#{@capitalize key}"
+      output[key] =
+        if attributes[macKey]?
+          attributes[macKey] or true
+        else
+          value

       # Convert to true boolean if passing in boolean string
       if output[key] in ["true", "false"]


Fix subscription channel and message content decoding

--- src/vent.coffee
+++ src/vent.coffee
@@ -5,7 +5,7 @@
 amqp            = require 'amqplib'
 logger          = require('dl-logger')("dl:vent")
 uuid            = require 'node-uuid'
-w               = require 'when'
+when_           = require 'when'

 DEFAULT_OPTIONS =
@@ -20,6 +20,7 @@
     Jobs a general purpose Pub/Sub event lib hased on AMQP

     You can subscribe or publish event based on the following concepts
+
     ## Channels
     A channel is used to group common types of event. This maps to a EXCHANGE
     on both publish and subscribe
@@ -38,14 +39,22 @@
     of the same worker/service. In some cases you will only want one service
     to handle a particular event. This is were groups are useful

+    By default, subscription that use groups will not be auto-deleted.
+
     ## options
     durable - is a non-transient setup, meaning that queues and thier content
               will be persisted through restarts
     group   - SEE ABOVE
+
+    ## TODO: Handling errors
+
+    We are planning to add support for metric processing errors. You will be able
+    to provide error channel, that will be used to publish all messages that caused
+    processing error together with error explanation.
     ###

-    constructor: (@url, options) ->
-        assert _.isString(@url), "missing url"
+    constructor: ({@url}, options) ->
+        assert _.isString(@url), "missing vent url"
         @options = _.extend({}, DEFAULT_OPTIONS, options)
         @_reset_connection()

@@ -108,6 +117,11 @@
         options.group ?= uuid.v4()

         @_create_subscription_channel(options, listener)
+            .then(() ->
+                logger.info('Subscription created', {options})
+            , (err) ->
+                logger.error({err}, 'Error when opening new subscription', {options})
+            )
         @

     unsubscribe: (event, options, listener) ->
@@ -142,11 +156,13 @@
         if _.isString(options)
             options = {group: options}

-        stream = new vent_stream.ConsumerStream(_.pick(options, high_watermark)
+        stream = new vent_stream.ConsumerStream(_.pick(options, high_watermark))

         @subscribe(event, _.extend({}, options, ack: true), stream.push_message)
         @cb(null, stream)
         @
+
+    # TODO: add vent close method implementation

     #
     # Connection and channel handling
@@ -161,21 +177,22 @@
     # closed handler, we can figgure out if vent is closed depending whether any
     # subscription was reconneted. Potential subscription reconnect logic will
     # kick in on channel closed event.
-
+
     _open_connection: =>
         ###
         Open new connection

         It is subject to _.memoize, so it will be called only once per connection
         ###
-        conn_options = _.pick(@options, 'hearbeat')
-        logger.debug("creating queue connection", {url, conn_options})
-        amqp.connect(@url, con_options).then (conn) =>
+        url = @_get_connection_url()
+        logger.debug("Opening new vent connection", {url, @options})
+        amqp.connect(url).then (conn) =>
             logger.debug('amqp connection created', {conn})
             conn.on 'error', (err) ->
                     logger.error("Connection error", {err, url})
                     @emit('error', err)
-                    @_reset_connection()
+                    process.exit(1)
+                    #@_reset_connection()
                 .on 'close', ->
                     logger.info('Connection closed', {url})
                     if not @_connect.has()
@@ -184,10 +201,20 @@
                     logger.warn('Connection blocked', {url})
                 .on 'unblocked', ->
                     logger.info('Connection unblocked', {url})
+            conn
+
+    _get_connection_url: =>
+        url = @url
+        heartbeat = @options.heartbeat
+        if heartbeat?
+            separator = if url.indexOf('?') >= 0 then '&' else '?'
+            url += "#{separator}heartbeat=#{heartbeat}"
+        url

     _reset_connection: ->
         logger.debug('connection reset')
-        @_connect = _.memoize(@_open_connection)
+        #@_connect = _.memoize(@_open_connection)
+        @_connect = @_open_connection
         @_subscriptions = []

     _create_channel: ->
@@ -201,33 +228,32 @@
             exch_name = queue_binding_source = options.channel
             exch_options = @_generate_exchange_options(options)
             topic = options.topic
-            consumer = @_wrap_consumer_callback(listener)
-            if options.ack
-                consumer = @_wrap_ack_callback(listener, channel)
-
-            logger.debug('setting up queue', {queue_name, queue_options, exch_name, topic})
+            consumer = @_wrap_consumer_callback(listener, ch, options)
+
+            logger.debug('setting up queue', {queue_name, queue_options, exch_name, exch_options, topic})
             steps = [
                 ch.assertQueue(queue_name, queue_options)
-                ch.assertExchange(exch_name, exch_options)
+                ch.assertExchange(exch_name, 'topic', exch_options)
             ]

             if options.partition?
                 partition_exch_name = "#{exch_name}.#{options.group}-splitter"
                 partition_exch_options =
-                    type: 'x-consistent-hash'
                     autoDelete: if options.autoDelete? then options.autoDelete else true
                 steps.concat([
-                    ch.assertExchange(partition_exch_name)
+                    ch.assertExchange(partition_exch_name, 'x-consistent-hash')
                     ch.bindExchange(partition_exch_name, exch_options, topic)
                 ])
                 topic = '10' # for x-consistent hash echange topic is a weight

             steps.concat([
                 ch.bindQueue(queue_name, queue_binding_source, topic)
-                ch.consume(queue_name, listener)
+                ch.consume(queue_name, consumer)
             ])
-            w.all(steps)
             # TODO: add channel bindings to restart whole subscription if channel is closed
+            p = when_.all(steps)
+            logger.debug('Preapred promise: ', {p})
+            p

     _parse_event: (event) ->
         assert _.isString(event), "event string required"
@@ -279,30 +305,54 @@
             arguments: args

     _generate_exchange_options: (options) ->
-        exch_options =
-            type: options.type or 'topic'
-            autoDelete: false
-            durable: options.durable
-
-    _wrap_consumer_callback: (fn) ->
+        autoDelete: false
+        durable: options.durable
+
+    _decode_message: (msg) =>
+        content = msg.content
+        content_type = msg.content_type
+        switch content_type
+            when 'application/json'
+                try
+                    content = JSON.parse(content)
+                catch err
+                    logger.warn('Error parsing json message', {err, msg})
+                    throw err
+            when 'text/plain'
+                content = content.toString('utf8')
+            when undefined
+                content = content.toString('utf8')
+            else
+                loger.warn('Recived message with unknown content_type', {content_type, msg})
+                throw new Error("Do not know how to hange message type: " + content_type)
+        content
+
+    _wrap_consumer_callback: (fn, channel, options) ->
         """ Wrapper for unpacking message content """
-        (msg) -> fn(msg.content)
+        decode = @_decode_message
+        wrapped = (msg) ->
+            when_.try(-> decode(msg)).then(fn)
+        if options.ack
+            wrapped = @_wrap_ack_promise(wrapped, channel)
+        wrapped

     _wrap_ack_callback: (fn, channel) ->
         """ Wrapper that adds ack callback to argumetns"""
-        (msg) -> fn(msg, (err) ->
-            if err?
-                # TODO: Right now there is not much we can do about errors beside
-                # jsut dropping mesage one a floor and logging message. In feature
-                # version we should have support for configurable errors queue,
-                # where errors coudl be forwarded for operator intervention.
-                # We defenitelly don't want to re-put into queue, because if it is
-                # problem with message itself, we can end up in indefenite loop
-                logger.error('Error in message consumer', {err})
-            channel.ack(msg)
-        )
+        (msg) ->
+            when_(fn(msg))
+                .catch (err) ->
+                    # TODO: Right now there is not much we can do about errors beside
+                    # jsut dropping mesage one a floor and logging message. In feature
+                    # version we should have support for configurable errors queue,
+                    # where errors coudl be forwarded for operator intervention.
+                    # We defenitelly don't want to re-put into queue, because if it is
+                    # problem with message itself, we can end up in indefenite loop
+                    logger.error('Error in message consumer', {err})
+                .finally ->
+                    channel.ack(msg)

 module.exports = (setup, options) ->
     setup = {url: setup} if _.isString(setup)
+    logger.debug('setup', {setup})
     new Vent(setup, options)


cleanup consoles

cleanup consoles

--- src/client/current-config.coffee
+++ src/client/current-config.coffee
@@ -92,7 +92,6 @@
     checkConfig(config).then (config)=>
       org = extractDomainFromUrl(config.orgUrl)
       ns = ['hull'].concat(org.split('.')).join('_')
-      console.warn('storage namespace: ', ns)
       @storage = localstorage.create({ namespace: ns })
       @_clientConfig = config
       @
@@ -149,7 +148,6 @@
     else
       ident ?= getReferralContext()
     ident.id = id if id?
-    console.warn('Storage set: ', key, ident)
     @storage.set(key, ident)
     ident


sanity check mesh data assignment arguments

--- lib/assets/javascripts/jax/mesh/data.js.coffee
+++ lib/assets/javascripts/jax/mesh/data.js.coffee
@@ -186,6 +186,7 @@
   ###
   set: (vars, mapping) ->
     throw new Error "Jax context for this pass is not set" unless @_context
+    throw new Error "Expected two arguments, mapping is undefined" unless mapping isnt undefined
     @bind @_context unless @_bound

     for key, target of mapping


run: accept status string

run: accept status string

--- src/commands/run.coffee
+++ src/commands/run.coffee
@@ -44,6 +44,7 @@
       line += "#{pad ctx.config.host, hostlength}"
       line += "#{pad ctx.action.name, 40}"
       statusmsg = if err then "\x1b[35m#{ctx.action.label_error || 'ERROR'}\x1b[39m"
+      else if typeof status is 'string' then status
       else if status then "\x1b[36m#{ctx.action.label_true || 'MODIFIED'}\x1b[39m"
       else "\x1b[36m#{ctx.action.label_false || 'OK'}\x1b[39m"
       line += "#{pad statusmsg, 20}"


Renamed new retract method to withdraw

Renamed new retract method to withdraw

--- src/view.coffee
+++ src/view.coffee
@@ -276,7 +276,7 @@
 		@insertBefore((view.el or view).nextSibling)
 		@

-	retract: ->
+	withdraw: ->
 		parentNode = @el.parentNode
 		nextSibling = @el.nextSibling
 		@el.parentNode.removeChild(@el)


Output error details in notification

Output error details in notification

--- lib/server/build.coffee
+++ lib/server/build.coffee
@@ -1,6 +1,8 @@
 childProcess = require 'child_process'

-module.exports =
+Builder =
+  error: null
+
   build: ->
     buildCommand = atom.config.get('jekyll.buildCommand')

@@ -14,8 +16,15 @@
       else
         throw error

+    @buildProcess.stdout.on 'data', (data) ->
+      message = data.toString()
+      if message.includes('Error:')
+        Builder.error =  message
+
     @buildProcess.on 'exit', (code, signal) ->
       if code is 0
         atom.notifications.addSuccess('Jekyll site build complete!')
       else
-        atom.notifications.addError('Jekyll site build failed!')
+        atom.notifications.addError('Jekyll site build failed!', {detail: Builder.error})
+
+module.exports = Builder


Rename callHandler to useSmartHandler

Rename callHandler to useSmartHandler

--- src/Editor.coffee
+++ src/Editor.coffee
@@ -37,7 +37,7 @@
     @medium.value()

   handleKeydown: (event) =>
-    callHandler = (handler) =>
+    useSmartHandler = (handler) =>
       selection   = window.getSelection()
       range       = selection.getRangeAt 0
       caretOffset = range.startOffset
@@ -48,8 +48,8 @@
     # TODO intelligently handle Up Arrow at the beginning of a section
     # TODO intelligently handle Down Arrow at the end of a section
     switch event.keyCode
-      when 222 then callHandler @applySmartQuote
-      when 189 then callHandler @applySmartEmDash
+      when 222 then useSmartHandler @applySmartQuote
+      when 189 then useSmartHandler @applySmartEmDash
       when 83
         # Disable Cmd+S and Ctrl+S
         if event.metaKey || event.ctrlKey


Require ipc-renderer to avoid deprecations

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -1,5 +1,5 @@
 BrowserWindow = null # Defer require until actually used
-RendererIpc = require 'ipc'
+ipc = require 'ipc-renderer'

 {matches, closest, indexOf} = require './html-helpers'
 {CompositeDisposable} = require 'atom'
@@ -82,10 +82,10 @@
     @addEventListener "dblclick", @onDoubleClick
     @addEventListener "click", @onClick

-    RendererIpc.on('tab:dropped', @onDropOnOtherWindow.bind(this))
+    ipc.on('tab:dropped', @onDropOnOtherWindow.bind(this))

   unsubscribe: ->
-    RendererIpc.removeListener('tab:dropped', @onDropOnOtherWindow.bind(this))
+    ipc.removeListener('tab:dropped', @onDropOnOtherWindow.bind(this))
     @subscriptions.dispose()

   handleTreeViewEvents: ->


Fix tabs drag&drop

Fix tabs drag&drop

--- lib/tab-bar-view.coffee
+++ lib/tab-bar-view.coffee
@@ -60,7 +60,7 @@
       if which is 1 and not target.classList.contains('close-icon')
         @pane.activateItem(tab.item)
         @pane.activate()
-        false
+        true
       else if which is 3 or (which is 1 and ctrlKey is true)
         @find('.right-clicked').removeClass('right-clicked')
         tab.classList.add('right-clicked')


fix: a babeljs issue

fix: a babeljs issue

--- src/yaku.coffee
+++ src/yaku.coffee
@@ -1,6 +1,6 @@

-do (root = this) -> class Yaku
+do (root = this or global) -> class Yaku

 	###*
 	 * This class follows the [Promises/A+](https://promisesaplus.com) and


Spacing issue.

Spacing issue.

--- lib/type/factory.coffee
+++ lib/type/factory.coffee
@@ -31,7 +31,7 @@
       t

     else if isNativeType(t)
-      new BuiltinType(t, name || t.constructor.name)
+      new BuiltinType(t, name || t.constructor.name)

     else if isRegexp(t)
       @subtype(String, t)


Avoid block 127.0.0.1

Avoid block 127.0.0.1

--- lib/zen.firewall.coffee
+++ lib/zen.firewall.coffee
@@ -48,7 +48,7 @@
       valid = false
       response.run "", code = 403
     # Add to blacklist request
-    if valid is false
+    if valid is false and request.ip isnt "127.0.0.1"
       ZEN.blacklist[request.ip] = (ZEN.blacklist[request.ip] or 0) + 1
       fs.writeFile file_name, JSON.stringify(ZEN.blacklist, null, 0), "utf8"


syntax hl for :Namespace,:Class,etc in header line

--- client/codemirror-apl-mode.coffee
+++ client/codemirror-apl-mode.coffee
@@ -27,7 +27,7 @@
   token: (stream, state) ->
     if state.isHeader
       delete state.isHeader; stream.skipToEnd(); s = stream.current()
-      if /\{\s*(⍝.*)?$/.test s
+      if /^\s*[:0-9]|\{\s*(⍝.*)?$/.test s
         stream.backUp s.length
       else if /^\s*$/.test s
         delete state.vars


auto pin mode

auto pin mode

--- grovepi.coffee
+++ grovepi.coffee
@@ -38,7 +38,7 @@
 	mode: (port, mode, callback) ->
 		unless modes[port]? is mode
 			modes[port] = mode
-			@send CMD.mode, port, [mode, 0], -> callback()
+			@send CMD.mode, port, [mode, 0], callback

 	send: ( cmd, port, args... ) ->
 		writeArgs = [cmd]


Atom.app doesn't exist in windows releases

--- tasks/build-task.coffee
+++ tasks/build-task.coffee
@@ -11,7 +11,12 @@

     rm shellAppDir
     mkdir path.dirname(buildDir)
-    cp 'atom-shell/Atom.app', shellAppDir
+
+    if process.platform is 'darwin'
+      cp 'atom-shell/Atom.app', shellAppDir
+    else if process.platform is 'win32'
+      console.log shellAppDir
+      cp 'atom-shell/', shellAppDir

     if process.platform is 'darwin'
       cp 'atom-shell/Atom.app', shellAppDir


clean up process refs

clean up process refs

--- src/join-request.coffee
+++ src/join-request.coffee
@@ -10,7 +10,8 @@

 module.exports = (robot) ->
   app = robot.router
-  team = process.env.HUBOT_SLACK_TEAM or ''
+  env = process.env
+  team = env.HUBOT_SLACK_TEAM or ''

   app.engine 'html', cons.hogan
   app.set 'view engine', 'html'
@@ -33,8 +34,8 @@
     user = req.session.user
     viewData =
       team: team
-      title: process.env.HUBOT_INGRESS_INVITE_TITLE or "You're almost there!"
-      description: process.env.HUBOT_INGRESS_INVITE_DESC or 'Please fill out
+      title: env.HUBOT_INGRESS_INVITE_TITLE or "You're almost there!"
+      description: env.HUBOT_INGRESS_INVITE_DESC or 'Please fill out
  the form below and upload your verification screenshot to complete your
  application. We have attempted to determine your agent name automatically,
  please check that this information is correct. Your application will be


Fixed #1 reload only when it is watching

--- templates/gulpfile.coffee
+++ templates/gulpfile.coffee
@@ -1,4 +1,5 @@
 LOCALS = require("./locals.json")
+isWatching = false
 {dir, server} = require("./config.json")
 gulp = require("gulp")
 $ = require("gulp-load-plugins")(lazy: false) #plugins
@@ -20,7 +21,7 @@
   gulp.src(dir.source + "/*.jade")
     .pipe $.jade(locals: LOCALS)
     .pipe gulp.dest(dir.build)
-    .pipe $.connect.reload()
+    .pipe (if isWatching then $.connect.reload() else $.util.noop())
     .pipe $.notify(message: "Jade task complete")

 gulp.task "coffee", ->
@@ -33,7 +34,7 @@
     .pipe $.rename(suffix: ".min")
     .pipe $.uglify()
     .pipe gulp.dest(dir.build + dir.scripts)
-    .pipe $.connect.reload()
+    .pipe (if isWatching then $.connect.reload() else $.util.noop())
     .pipe $.notify(message: "Scripts task complete")

 gulp.task "stylus", ->
@@ -43,7 +44,7 @@
       import: ["nib"]
     )
     .pipe gulp.dest(dir.build + dir.styles)
-    .pipe $.connect.reload()
+    .pipe (if isWatching then $.connect.reload() else $.util.noop())
     .pipe $.notify(message: "Styles task complete")

 gulp.task "images", ->
@@ -54,7 +55,7 @@
       progressive: true
       interlaced: true
     )
-    .pipe $.connect.reload()
+    .pipe (if isWatching then $.connect.reload() else $.util.noop())
     .pipe gulp.dest(dir.build + dir.images)
     .pipe $.notify(message: "Images task complete")

@@ -68,6 +69,7 @@
   return

 gulp.task "watch", ["connect"], ->
+  isWatching = true;
   gulp.watch dir.source + dir.styles + "**/*.styl", ["stylus"]
   gulp.watch dir.source + dir.scripts + "**/*.coffee", ["coffee"]
   gulp.watch dir.source + dir.images + "**/*", ["images"]


updating homepage signup panel

updating homepage signup panel

--- app/coffee/loginpanel.coffee
+++ app/coffee/loginpanel.coffee
@@ -9,6 +9,7 @@
     $('.joinWrap').click ->
       $(this).find('.join').hide()
       $(this).find('.joinButton').show()
+      $(this).parent().find('.intro').slideUp()
       $(this).parent().find('.joinForm').slideDown()

       $('.haveSeedcode').click =>


Added maximize toggling the proper way.

Added maximize toggling the proper way.

--- app/controllers/panel.coffee
+++ app/controllers/panel.coffee
@@ -16,9 +16,15 @@
     "click #decor img": "windowControl"
     "click #noteControls img": "noteControl"

+  maximized: false
+
   constructor: ->
     super
     Note.bind "changeNote", @toggle
+    win.on 'maximize', =>
+      @maximized = true
+    win.on 'unmaximize', =>
+      @maximized = false

   windowControl: (e) ->
     switch e.currentTarget.className
@@ -27,7 +33,8 @@
       when "minimize"
         win.minimize()
       when "maximize"
-        win.maximize()
+        win.maximize() if @maximized is false
+        win.unmaximize() if @maximized is true

   noteControl: (e) ->
     switch e.currentTarget.id


Make showMyRepositories action play nicely with URLs

--- app/controllers/repos.coffee
+++ app/controllers/repos.coffee
@@ -11,7 +11,13 @@
       @activate('running')

     showMyRepositories: ->
-      @activate('owned')
+      # this is a bit of a hack. I don't want to switch URL for 'running'
+      # so depending on current state I'm either just switching back or
+      # redirecting
+      if @get('tab') == 'running'
+        @activate('owned')
+      else
+        @transitionToRoute('main.repositories')

   tabOrIsLoadedDidChange: (->


:crossed_flags::leftwards_arrow_with_hook: Updated at https://danielx.net/editor/

--- load-n-play-midi.coffee
+++ load-n-play-midi.coffee
@@ -1,10 +1,9 @@
 clone = (obj) ->
   JSON.parse(JSON.stringify(obj))
+
+MidiReader = require "./midi_reader"

 module.exports = (buffer, adapter) ->
-  # Midi loading
-  MidiReader = require "./midi_reader"
-
   {playNote, releaseNote, programChange, pitchBend} = adapter

   reader = MidiReader(buffer)


Update pivot.de.coffee

Update pivot.de.coffee

--- locales/pivot.de.coffee
+++ locales/pivot.de.coffee
@@ -19,10 +19,10 @@
         localeStrings:
             renderError: "Bei der Darstellung der Pivot-Tabelle ist ein Fehler aufgetreten."
             computeError: "Bei der Berechnung der Pivot-Tabelle ist ein Fehler aufgetreten."
-            uiRenderError: "Bei der Darstellung Oberflche der Pivot-Tabelle ist ein Fehler aufgetreten."
-            selectAll: "Alles auswhlen"
-            selectNone: "Nichts auswhlen"
-            tooMany: "(zu viele fr Liste)"
+            uiRenderError: "Bei der Darstellung Oberfläche der Pivot-Tabelle ist ein Fehler aufgetreten."
+            selectAll: "Alles auswählen"
+            selectNone: "Nichts auswählen"
+            tooMany: "(zu viele für Liste)"
             filterResults: "Ergebnisse filtern"
             totals: "Gesamt"
             vs: "gegen"
@@ -37,7 +37,7 @@
             "Durchschnitt":                 tpl.average(frFmt)
             "Minimum":                      tpl.min(frFmt)
             "Maximum":                      tpl.max(frFmt)
-            "Summe ber Summe":             tpl.sumOverSum(frFmt)
+            "Summe über Summe":             tpl.sumOverSum(frFmt)
             "80% Obergrenze":               tpl.sumOverSumBound80(true, frFmt)
             "80% Untergrenze":        		tpl.sumOverSumBound80(false, frFmt)
             "Summe als Anteil von Gesamt":  tpl.fractionOf(tpl.sum(),   "total", frFmtPct)
@@ -48,7 +48,7 @@
             "Anzahl als Anteil von Spalte": tpl.fractionOf(tpl.count(), "col",   frFmtPct)

         renderers:
-            "Talelle":                      $.pivotUtilities.renderers["Table"]
+            "Tabelle":                      $.pivotUtilities.renderers["Table"]
             "Tabelle mit Balkendiagramm":   $.pivotUtilities.renderers["Table Barchart"]
             "Heatmap":                      $.pivotUtilities.renderers["Heatmap"]
             "Heatmap pro Zeile":            $.pivotUtilities.renderers["Row Heatmap"]


Fix indentation

Fix indentation

--- app/lib/coursesHelper.coffee
+++ app/lib/coursesHelper.coffee
@@ -202,8 +202,8 @@
               courseProgress[levelID].dateFirstCompleted = null
               courseProgress[levelID][userID].dateFirstCompleted = null

-          if isPractice and not courseProgress[levelID].started
-            courseProgress[levelID].completed = false # edge for practice levels, not considered complete if never started either
+            if isPractice and not courseProgress[levelID].started
+              courseProgress[levelID].completed = false # edge for practice levels, not considered complete if never started either

     _.assign(progressData, progressMixin)
     return progressData