Always fetchFromDB first then when it fails try to fetch from FS

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -70,8 +70,6 @@
       if not @appStorage.getValue 'shortcuts'
         @putDefaultShortcutsToAppStorage()

-    @fetchedFromFs = no
-
   # #
   # FETCHERS
   # #
@@ -81,20 +79,14 @@
     if Object.keys(@constructor.manifests).length isnt 0
       callback null, @constructor.manifests
     else
-      if not @fetchedFromFs
-        @fetchAppsFromFs (err, apps)=>
-          if err then callback()
-          else
-            callback null, apps
-      else
-        @fetchAppsFromDb (err, apps)=>
-          if err
-            @fetchAppsFromFs (err, apps)=>
-              if err then callback()
-              else
-                callback null, apps
-          else
-            callback? err, apps
+      @fetchAppsFromDb (err, apps)=>
+        if err
+          @fetchAppsFromFs (err, apps)=>
+            if err then callback()
+            else
+              callback null, apps
+        else
+          callback? err, apps

   fetchAppsFromFs:(callback)->

@@ -146,7 +138,6 @@

           @putAppsToAppStorage manifests
           callback? null, manifests
-          @fetchedFromFs = yes

   fetchAppsFromDb:(callback)->

@@ -259,7 +250,7 @@
   runApp:(manifest, callback)->

     {options, name, devMode} = manifest
-    {stylesheets}   = manifest.source if manifest.source
+    {stylesheets} = manifest.source if manifest.source

     if stylesheets
       stylesheets.forEach (sheet)->


BulletEnemySystem no longer needs visual enemy comp

--- src/javascript/game/systems/bullet_enemy_system.coffee
+++ src/javascript/game/systems/bullet_enemy_system.coffee
@@ -5,7 +5,7 @@
 class BulletEnemySystem extends BaseSystem
   @Subscribe: [
       [ "bullet", "hit_box" ],
-      [ "enemy", "hit_box", "visual"]
+      [ "enemy", "hit_box"]
     ]
   @ImplyEntity: 'enemy'


Long Poll should support IE8

Long Poll should support IE8

--- lib/assets/javascripts/firehose/long_poll.js.coffee
+++ lib/assets/javascripts/firehose/long_poll.js.coffee
@@ -6,7 +6,7 @@
   # access "simple request" response headers. This means we don't yet have a
   # plan to support IE<10 (when it gets a real XHR2 implementation). Sucks...
   # $.browser.msie and parseInt($.browser.version) >= 8 # DEPRECATED
-  @ieSupported: -> (document.documentMode || 10) > 8
+  @ieSupported: -> (document.documentMode || 10) >= 8

   @supported: ->
     # IE 8+, FF 3.5+, Chrome 4+, Safari 4+, Opera 12+, iOS 3.2+, Android 2.1+


JProvisioner: remove the provisioner if requester is an owner

--- workers/social/lib/social/models/computeproviders/provisioner.coffee
+++ workers/social/lib/social/models/computeproviders/provisioner.coffee
@@ -204,11 +204,15 @@
       Relationship.one
         targetId : @getId()
         sourceId : delegate.getId()
-      , (err, rel)->
+      , (err, rel)=>

         return callback err   if err?
         return callback null  unless rel?
-        rel.remove callback
+
+        if rel.data.as is 'owner'
+          @remove callback
+        else
+          rel.remove callback

   update$: permit


change 'shell' from remote to local

change 'shell' from remote to local

--- browser/src/coffee/common.coffee
+++ browser/src/coffee/common.coffee
@@ -61,4 +61,4 @@
         message: (e)->
             console.log e.message
         openInBrowser: ->
-            remote.require('shell').openExternal(@webContentSrc)+            require('shell').openExternal(@webContentSrc)


fix bug in vehicle capability eventing

fix bug in vehicle capability eventing

--- lib/capabilities/vehicles/VehiclesCapability.coffee
+++ lib/capabilities/vehicles/VehiclesCapability.coffee
@@ -25,11 +25,12 @@
     onlyConsumeAtHome: true

   start: ->
+    notifyChangeSoon = _.debounce(=>
+      @trigger 'change', this
+      @trigger 'consumption:change', this)
     _.each @get('vehicles'), (vehicle, id) =>
       @_server.adapters.onEventAtPath vehicle.path,
-        'aspectData:change', =>
-        @trigger 'change', this
-        @trigger 'consumption:change', this
+        'aspectData:change', notifyChangeSoon
     @setValid true

   vehicleState: (id) ->


Remove R$ da tabela em pagamentos por mês

Já dizemos no monitor que os valores estão em reais

--- app/assets/javascripts/angular_app/directives/summary_table.js.coffee
+++ app/assets/javascripts/angular_app/directives/summary_table.js.coffee
@@ -1,10 +1,10 @@
 angular.module('InescApp').directive 'summaryTable', ['$filter', ($filter) ->
   columns = [
     { sTitle: 'Mês', bSortable: false, sClass: 'month' }
-    { sTitle: 'Autorizado (em R$)', bSortable: false, sClass: 'currency' }
-    { sTitle: 'Pago (em R$)', bSortable: false, sClass: 'currency' }
-    { sTitle: 'RP Pago (em R$)', bSortable: false, sClass: 'currency' }
-    { sTitle: 'Pagamentos (Pago + RP Pago, em R$)', bSortable: false, sClass: 'currency' }
+    { sTitle: 'Autorizado', bSortable: false, sClass: 'currency' }
+    { sTitle: 'Pago', bSortable: false, sClass: 'currency' }
+    { sTitle: 'RP Pago', bSortable: false, sClass: 'currency' }
+    { sTitle: 'Pagamentos (Pago + RP Pago)', bSortable: false, sClass: 'currency' }
     { sTitle: 'Mês', bVisible: false } # Usado só para sorting
   ]


fixed bad lifecycle bug

fixed bad lifecycle bug

--- modules/stores/platforms/node/lib/engines/FileStore.coffee
+++ modules/stores/platforms/node/lib/engines/FileStore.coffee
@@ -24,6 +24,7 @@
                         return done(err) if err
                         @_memory = JSON.parse json
                         done()
+                else done()

         ##
         ##


Extract helper in spec to set up refactor

This will make it easier to refactor the implementation to use
highlight decorations without changing the tests

--- spec/bracket-matcher-spec.coffee
+++ spec/bracket-matcher-spec.coffee
@@ -27,96 +27,90 @@
       buffer = editor.getBuffer()

   describe "matching bracket highlighting", ->
+    expectNoHighlights = ->
+      expect(editorView.underlayer.find('.bracket-matcher:visible')).not.toExist()
+
+    expectHighlights = (startBufferPosition, endBufferPosition) ->
+      highlights = editorView.underlayer.find('.bracket-matcher:visible')
+      expect(highlights.length).toBe(2)
+
+      expect(highlights.eq(0).position()).toEqual(editor.pixelPositionForBufferPosition(startBufferPosition))
+      expect(highlights.eq(0).width()).toBeGreaterThan(0)
+      expect(highlights.eq(0).height()).toBeGreaterThan(0)
+
+      expect(highlights.eq(1).position()).toEqual(editor.pixelPositionForBufferPosition(endBufferPosition))
+      expect(highlights.eq(1).width()).toBeGreaterThan(0)
+      expect(highlights.eq(1).height()).toBeGreaterThan(0)
+
     describe "when the cursor is before a starting pair", ->
       it "highlights the starting pair and ending pair", ->
         editor.moveToEndOfLine()
         editor.moveLeft()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
-
-        expect(editorView.underlayer.find('.bracket-matcher:first').width()).toBeGreaterThan 0
-        expect(editorView.underlayer.find('.bracket-matcher:last').width()).toBeGreaterThan 0
-        expect(editorView.underlayer.find('.bracket-matcher:first').height()).toBeGreaterThan 0
-        expect(editorView.underlayer.find('.bracket-matcher:last').height()).toBeGreaterThan 0
+        expectHighlights([0,28], [12,0])

     describe "when the cursor is after a starting pair", ->
       it "highlights the starting pair and ending pair", ->
         editor.moveToEndOfLine()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
+        expectHighlights([0,28], [12,0])

     describe "when the cursor is before an ending pair", ->
       it "highlights the starting pair and ending pair", ->
         editor.moveToBottom()
         editor.moveLeft()
         editor.moveLeft()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
+        expectHighlights([12,0], [0,28])

     describe "when the cursor is after an ending pair", ->
       it "highlights the starting pair and ending pair", ->
         editor.moveToBottom()
         editor.moveLeft()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
+        expectHighlights([12,0], [0,28])

     describe "when there are unpaired brackets", ->
       it "highlights the correct start/end pairs", ->
         editor.setText '(()'
         editor.setCursorBufferPosition([0,0])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 0
+        expectNoHighlights()

         editor.setCursorBufferPosition([0,1])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,2])
+        expectHighlights([0,1], [0,2])

         editor.setCursorBufferPosition([0,2])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,2])
+        expectHighlights([0,1], [0,2])

         editor.setText ('())')
         editor.setCursorBufferPosition([0,0])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+        expectHighlights([0,0], [0,1])

         editor.setCursorBufferPosition([0,1])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+        expectHighlights([0,0], [0,1])

         editor.setCursorBufferPosition([0,2])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 0
+        expectNoHighlights()

     describe "when the cursor is moved off a pair", ->
       it "removes the starting pair and ending pair highlights", ->
         editor.moveToEndOfLine()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
+        expectHighlights([0,28], [12,0])
+
         editor.moveToBeginningOfLine()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 0
+        expectNoHighlights()

     describe "when the pair moves", ->
       it "repositions the highlights", ->
         editor.moveToEndOfLine()
         editor.moveLeft()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
+        expectHighlights([0,28], [12,0])
+
         editor.deleteToBeginningOfLine()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
+        expectHighlights([0,0], [12,0])

     describe "when the font size changes", ->
       it "repositions the highlights", ->
         editor.moveToBottom()
         editor.moveLeft()
         atom.config.set('editor.fontSize', editorView.getFontSize() + 10)
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
+        expectHighlights([12,0], [0,28])

     describe "when the soft wrap setting changes on the editor", ->
       it "repositions the highlights", ->
@@ -126,49 +120,40 @@
         editor.moveLeft()
         editorView.setWidthInChars(23)

-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
+        expectHighlights([12,0], [0,28])

         editor.setSoftWrapped(false)
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
+        expectHighlights([12,0], [0,28])

     describe "when code is folded", ->
       it "repositions the highlights", ->
         editor.moveToEndOfLine()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
+        expectHighlights([0,28], [12,0])

         editor.foldBufferRow(1)
         # Explicitly trigger an editor:display-updated event since this happens
         # synchronously in specs and so it will fire before screen-lines-changed
         # fires
         editorView.trigger('editor:display-updated')
-
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-        expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,28])
-        expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([12,0])
+        expectHighlights([0,28], [12,0])

     describe "pair balancing", ->
       describe "when a second starting pair preceeds the first ending pair", ->
         it "advances to the second ending pair", ->
           editor.setCursorBufferPosition([8,42])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([8,42])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([8,54])
+          expectHighlights([8,42], [8,54])

     describe "when the cursor is destroyed", ->
       it "updates the highlights to use the editor's last cursor", ->
         editor.setCursorBufferPosition([0,29])
         editor.addCursorAtBufferPosition([9,0])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
+        expectHighlights([0,28], [12,0])
+
         editor.consolidateSelections()
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 0
+        expectNoHighlights()
+
         editor.setCursorBufferPosition([0,29])
-        expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
+        expectHighlights([0,28], [12,0])

     describe "HTML/XML tag matching", ->
       beforeEach ->
@@ -190,14 +175,10 @@
           """

           editor.setCursorBufferPosition([0,0])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([3,2])
+          expectHighlights([0,1], [3,2])

           editor.setCursorBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([3,2])
+          expectHighlights([0,1], [3,2])

       describe "when on a closing tag", ->
         it "highlight the opening and closing tag", ->
@@ -209,14 +190,10 @@
           """

           editor.setCursorBufferPosition([3,0])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([3,2])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+          expectHighlights([3,2], [0,1])

           editor.setCursorBufferPosition([3,2])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([3,2])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+          expectHighlights([3,2], [0,1])

           buffer.setText """
             <test>
@@ -226,14 +203,10 @@
           """

           editor.setCursorBufferPosition([1,Infinity])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([1,14])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([1,3])
+          expectHighlights([1,14], [1,3])

           editor.setCursorBufferPosition([2,Infinity])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([2,14])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([2,3])
+          expectHighlights([2,14], [2,3])

       describe "when the tag spans multiple lines", ->
@@ -246,14 +219,10 @@
           """

           editor.setCursorBufferPosition([3,2])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([3,2])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+          expectHighlights([3,2], [0,1])

           editor.setCursorBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([3,2])
+          expectHighlights([0,1], [3,2])

       describe "when the tag has attributes", ->
         it "highlights the opening and closing tags", ->
@@ -264,28 +233,20 @@
           """

           editor.setCursorBufferPosition([2,2])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([2,2])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+          expectHighlights([2,2], [0,1])

           editor.setCursorBufferPosition([0,7])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([2,2])
+          expectHighlights([0,1], [2,2])

       describe "when the opening and closing tags are on the same line", ->
         it "highlight the opening and closing tags", ->
           buffer.setText "<test>text</test>"

           editor.setCursorBufferPosition([0,2])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,12])
+          expectHighlights([0,1], [0,12])

           editor.setCursorBufferPosition([0,12])
-          expect(editorView.underlayer.find('.bracket-matcher:visible').length).toBe 2
-          expect(editorView.underlayer.find('.bracket-matcher:first').position()).toEqual editor.pixelPositionForBufferPosition([0,12])
-          expect(editorView.underlayer.find('.bracket-matcher:last').position()).toEqual editor.pixelPositionForBufferPosition([0,1])
+          expectHighlights([0,12], [0,1])

   describe "when bracket-matcher:go-to-matching-bracket is triggered", ->
     describe "when the cursor is before the starting pair", ->


メッセージの追加

メッセージの追加

--- scripts/help-message.coffee
+++ scripts/help-message.coffee
@@ -12,6 +12,10 @@
      　`cbot (bus or バス)`
      　_ios版ではキャッシュが原因で最新の画像が送られない可能性があります。_
      　_解決するには 設定 -> slack -> Reset Cache on Next Launch_
+     *メンバーの中でくじ引きを行う*
+      `cbot (lottery or lot or くじ or randam or ランダム or 抽選)`
+      オプション
+        `-list` [メンバー全員にランダムで順番をつける]
      *天気を聞く*
      　`(今日 or 明日 or 明後日)の天気`
      *電車の遅延を確認する*


Added :ant:

Added :ant:

--- scripts/idobata-talk.coffee
+++ scripts/idobata-talk.coffee
@@ -62,6 +62,9 @@

   robot.hear /ごめん|すみません/i, (msg) ->
     msg.send "分かればいいのよ"
+
+  robot.hear /:ant/i, (msg) ->
+    msg.send Array(Math.floor(Math.random() * 100) + 1).join ':ant:'

   # respond
   robot.respond /嫌い？$/i, (msg) ->


minor

minor

--- tom.coffee
+++ tom.coffee
@@ -1,11 +1,5 @@
-####
-# Scrolls the window to element:
-#   $('element').scrollTo()
+# Scrolls the window to element at the specified speed:
 #   $('element').scrollTo(speed)
-#
-# Scrolls element1 to element2:
-#   $('element1').scrollTo($('element2'))
-#   $('element1').scrollTo($('element2'), speed)
 $.fn.scrollTo: (speed) ->
   target: this
   container:'html,body'
@@ -17,18 +11,19 @@
 $ ->
   $('#demo').click ->
     $('#demo-box').toggle()
-    if $('#demo-box:visible').length > 0
+    if $('#demo-box:visible').length > 0
       $('#demo').scrollTo(1)
-      window.location.hash: '#demo'
-    else
+      window.location.hash: '#demo'
+    else
       window.location.hash: ''
     false
-
-  $('#demo').click() if window.location.hash is "#demo"
-
+
+  $('#demo').click() if window.location.hash is "#demo"
+
   $('.run').click ->
     template: $('.template').val()
     json: $.parseJSON $('.json').val()
     html: Mustache.to_html(template, json).replace(/^\s*/mg, '')
+
     $('.html').text(html).scrollTo(1)
-    Highlight.highlightDocument()
+    Highlight.highlightDocument()


Extra text in beacons

Extra text in beacons

--- client.coffee
+++ client.coffee
@@ -777,18 +777,7 @@

 				location = L.latLng(beacon.get('location', 'lat'), beacon.get('location', 'lng'))
 				marker = L.marker(location, {icon: areaIcon})
-				popup = L.popup()
-					.setLatLng(location)
-					.setContent("Beacon owned by " + Db.shared.peek('colors', beacon.peek('owner'), 'name') + " team."
-				marker.bindPopup(popup)
-				marker.addTo(map)
-				beaconMarkers.push marker
-				#log 'Added marker, marker list: ', beaconMarkers
-
-				# Add the area circle to the map
-				if not window.beaconCircles?
-					log "beaconCircles list reset"
-					window.beaconCircles = [];
+
 				circle = L.circle(location, Db.shared.get('game', 'beaconRadius'), {
 					color: teamColor,
 					fillColor: teamColor,
@@ -805,7 +794,7 @@
 					popup = L.popup()
 						.setLatLng(location)
 						.setContent("Beacon owned by team " + Db.shared.peek('colors', beacon.peek('owner'), 'name') + "." +
-							"

lat: " + location.lat + "
long: " + location.lng)
+							"

Value: " + beacon.peek('captureValue' + " points!"))
 					marker.bindPopup(popup)
 					markerClick = () ->
 						beaconMarkers[beacon.key()].togglePopup()


#3 исправлена ошибка неверным анлоком

#3 исправлена ошибка неверным анлоком

--- builder.coffee
+++ builder.coffee
@@ -21,10 +21,10 @@
   cp = new CopyFiles options.source, options.destination,
     replaceStrategy: CopyFiles.REPLACE_OLDER
     on_complete: (stat, cp) ->
-      builder.unlock()
       console.log "#{name}: #{stat.filesCopied} files copied".green
       rollback = cp.generateRollback()
       builder.setState(name, rollback: rollback)
+      builder.unlock()
     on_progress: (ctx, cp) ->
       if builder.verbose and not ctx.skipped
         console.log "#{relative(process.cwd(), ctx.src)} -> #{relative(process.cwd(), ctx.dst)}".grey


Add enable, disable methods

Add enable, disable methods

--- src/widgets/button.coffee
+++ src/widgets/button.coffee
@@ -22,8 +22,9 @@
       @button = @_prepareButton() unless @button
       @element.append @button

-      @button.bind 'change', (event) =>
-        @options.editable.execute @options.command
+      if @options.command
+        @button.bind 'change', (event) =>
+          @options.editable.execute @options.command

       return unless @options.queryState

@@ -42,13 +43,19 @@
       editableElement.bind 'hallodisabled', =>
         editableElement.unbind 'keyup paste change mouseup hallomodified', queryState

+    enable: ->
+      @button.button 'enable'
+
+    disable: ->
+      @button.button 'disable'
+
     _prepareButton: ->
       id = "#{@options.uuid}-#{@options.label}"
-      buttonEl = jQuery """<input id=\"#{id}\" type=\"checkbox\" />
+      @buttonEl = jQuery """<input id=\"#{id}\" type=\"checkbox\" />
         <label for=\"#{id}\" class=\"btn #{@options.command}_button\" title=\"#{@options.label}\">
           <i class=\"#{@options.icon}\"></i>
         </label>"""
-      button = buttonEl.button()
+      button = @buttonEl.button()
       button.data 'hallo-command', @options.command
       button


Implement DELETE /tags/:id

Implement DELETE /tags/:id

--- api/routes/tags.coffee
+++ api/routes/tags.coffee
@@ -61,10 +61,26 @@
                     res.status 404
                     .json { status: 404, error: 'no such id' }

-    app.delete '/tags/:id', (req, res, next) ->
-        res.status 501
-        .json { status: 501, error: 'not yet implemented' }
-
+    app.delete '/tags/:id'
+    , middleware.requireMinPrivilegeLevel(privilegeLevels.editor)
+    , (req, res, next) ->
+        db.get 'SELECT * FROM tTag WHERE id = ?', req.params.id, (err, row) ->
+            if err?
+                res.status 500
+                .json { status: 500, error: 'database error' }
+            else
+                if row?
+                    db.run 'DELETE FROM tTag WHERE id = ?', req.params.id, (err) ->
+                        if err?
+                            res.status 500
+                            .json { status: 500, error: 'database error' }
+                        else
+                            res.status 200
+                            .json row
+                else
+                    res.status 404
+                    .json { status: 404, error: 'no such id' }
+
     app.patch '/tags/:id', (req, res, next) ->
         res.status 501
         .json { status: 501, error: 'not yet implemented' }


Fixes path to version

Fixes path to version

--- src/api.coffee
+++ src/api.coffee
@@ -1,4 +1,4 @@
-define ['underscore', 'lib/version', 'lib/api/params', 'lib/api/auth', 'easyXDM', 'lib/utils/promises'], (_, version, apiParams, authModule, easyXDM, promises)->
+define ['underscore', 'lib/utils/version', 'lib/api/params', 'lib/api/auth', 'easyXDM', 'lib/utils/promises'], (_, version, apiParams, authModule, easyXDM, promises)->
   slice = Array.prototype.slice

   # Builds the URL used by easyXDM
@@ -57,8 +57,8 @@
       if data.headers && data.headers['Hull-User-Id']
         setCurrentUser data.headers
       window.clearTimeout(timeout)
-
-
+
+

       dfd.resolve
         auth: authModule api, config, remoteConfig.services.types.auth


getResourcePath: linux: calculate asarPath and return nextTick -> callback

--- src/apm.coffee
+++ src/apm.coffee
@@ -50,10 +50,10 @@
           asarPath = "#{appLocation}/Contents/Resources/app.asar"
           return process.nextTick -> callback(asarPath)
       when 'linux'
-        appLocation = '/usr/local/share/atom/resources/app.asar'
+        asarPath = '/usr/local/share/atom/resources/app.asar'
         unless fs.existsSync(appLocation)
-          appLocation = '/usr/share/atom/resources/app.asar'
-        process.nextTick -> callback(appLocation)
+          asarPath = '/usr/share/atom/resources/app.asar'
+        return process.nextTick -> callback(asarPath)
       when 'win32'
         glob = require 'glob'
         pattern = "/Users/#{process.env.USERNAME}/AppData/Local/atom/app-+([0-9]).+([0-9]).+([0-9])/resources/app.asar"


Add static routes

Add static routes

--- src/app.coffee
+++ src/app.coffee
@@ -16,6 +16,9 @@
 # Add JSON Body Parser Middleware
 app.use bodyParser.json()

+app.use '/', express.static("www/app/www")
+app.use '/report', express.static("www/report")
+
 # Add routes for attendance service api
 app.use '/api/v1', api_routes


Don't forget next()

Don't forget next()

--- src/app.coffee
+++ src/app.coffee
@@ -70,6 +70,7 @@
       res.locals.user = req.user
     else
       req.user = res.locals.user = null
+    next()

   app.use express.static(path.join(__dirname, '..', 'public'))


minor removed semicolon

minor removed semicolon

--- src/app.coffee
+++ src/app.coffee
@@ -3,7 +3,7 @@
 $ ->
 	cells = $(".cell-value")
 	nums = _.range(1, 10)
-	counter = 0;
+	counter = 0
 	maxAnimationFrames = 50

 	randomizeNumbers = ->


Removed empty vent

Removed empty vent


[sessions] use configured session store to store express' sessions

--- src/core/voicious.coffee
+++ src/core/voicious.coffee
@@ -25,6 +25,7 @@
 {Translator} = require './trans'
 {Db}         = require '../common/' + Config.Database.Connector

+SStore       = (require 'connect-' + Config.Voicious.Sessions.Connector) Express

 # Just implement a _currying_ system, it will be used for routes.
 Function.prototype.curry = () ->
@@ -70,6 +71,10 @@

     # Configure the __Express__ instance.
     configure       : () =>
+        sstore = new SStore {
+            db   : 'vcssess'
+            host : Config.Voicious.Sessions.Hostname.Internal
+        }
         @app.set 'port', Config.Voicious.Port
         @app.set 'views', Config.Paths.Views
         @app.set 'view engine', 'jade'
@@ -79,7 +84,10 @@
         @app.use do Express.bodyParser
         @app.use do Express.methodOverride
         @app.use Express.cookieParser 'your secret here'
-        @app.use do Express.session
+        @app.use Express.session {
+            secret : 'your secret here',
+            store  : sstore
+        }
         @app.use @app.router
         @app.use Express.static Config.Paths.Webroot
         do @setAllRoutes


ajax loading indicator fix for forge

ajax loading indicator fix for forge

--- app/index.coffee
+++ app/index.coffee
@@ -29,6 +29,7 @@
     dfd = jQuery.Deferred()
     options.success = (data) ->
       # console.log "forge ajax resolve", data
+      $(document).trigger 'ajaxStop', [null, options]
       dfd.resolve data

     options.error = (error) ->
@@ -36,10 +37,14 @@
       error.responseText = error.content
       error.statusText = error.message
       error.status = parseInt(error.statusCode)
+
+      $(document).trigger 'ajaxStop', [null, options]
+
       # arguments: event, xhr, ajaxSettings, thrownError
       dfd.reject error
       $(document).trigger 'ajaxError', error

+    $(document).trigger 'ajaxSend', [null, options]
     forge.ajax options
     dfd.promise()

@@ -111,7 +116,7 @@

   setupAJAX: ->
     el = $('

').prependTo($('body')).hide()
-    el.ajaxSend( (e, xhr, options) ->
+    $(document).ajaxSend( (e, xhr, options) ->
       return unless options.url.match(Spine.Model.host)
       el.show()
     ).ajaxStop( =>


Eager-load english translations

Eager-load english translations

--- app/index.coffee
+++ app/index.coffee
@@ -16,6 +16,9 @@
 ClassifyPage = require 'controllers/classify_page'
 AboutPage = require 'controllers/about_page'
 ProfilePage = require 'controllers/profile_page'
+
+enUs = require 'lib/en_us'
+translate.load enUs

 new Api project: 'planet_four'

@@ -45,7 +48,6 @@
 app.stack.classify.classificationTools.el.appendTo app.navigation.classificationToolsContainer
 app.stack.el.appendTo app.container

-enUs = require 'lib/en_us'
 languageManager = new LanguageManager
   translations:
     en: label: 'English', strings: enUs


clean up app code

clean up app code

--- app/index.coffee
+++ app/index.coffee
@@ -38,32 +38,21 @@

     linesMode = ->
         console.info "Starting Lines Mode."
-
         getJson "get-lines.json", "Requesting Lines..."
             .then vis.addLines

     chainMode = ->
         console.info "Starting Chain Mode."
-
-        poetry_chain_loaded = new Promise (resolve) ->
-            console.log "Requesting poetry chain..."
-            url = "#{window.location.origin}/api/get-chain.json"
-            d3.json(url, resolve)
-
-        poetry_chain_loaded.then (d) ->
-            # TODO: Get font with em-dash
-            # d.forEach (chain) ->
-            #     chain.forEach (line) ->
-            #         line.line = line.line.replace("--", "—")
-            vis.addChain d[0]
+        getJson "get-chain.json", "Requesting poetry chain..."
+            .then (d) ->
+                d.forEach (chain) ->
+                    chain.forEach (line) ->
+                        line.line = line.line.replace("--", "—")
+                        line.line = line.line.replace("––", "—")
+                        line.line = line.line.replace("——", "—")
+                vis.addChain d[0]

     colocationMode = ->
         console.info "Starting Colocation Mode."
-
-        network_loaded = new Promise (resolve) ->
-            console.log "Requesting colocation network..."
-            url = "#{window.location.origin}/api/get-colocation.json"
-            d3.json(url, resolve)
-
-        network_loaded.then (d) ->
-            vis.addNetwork d
+        getJson "get-colocation.json", "Requesting colocation network..."
+            .then vis.addNetwork


I'd rather have a long line than an orphan.

--- command.coffee
+++ command.coffee
@@ -63,8 +63,7 @@
   loadRequires()                         if opts.require
   return require './repl'                if opts.interactive
   if opts.watch and !fs.watch
-    printWarn "The --watch feature depends on Node v0.6.0+. You are running \
-#{process.version}."
+    printWarn "The --watch feature depends on Node v0.6.0+. You are running #{process.version}."
   return compileStdio()                  if opts.stdio
   return compileScript null, sources[0]  if opts.eval
   return require './repl'                unless sources.length


updated public es index

updated public es index

--- command.coffee
+++ command.coffee
@@ -43,7 +43,7 @@
     uri = url.format
       protocol: 'http'
       host: @destinationElasticsearchUrl
-      pathname: "/gateblu_device_add_history/event/#{connector.connector}"
+      pathname: "/gateblu_device_detail_history/event/#{connector.connector}"

     console.log "updating with connector...", connector


Removed data storage, it now just stores as a buffer

Before using data would store as both data and a buffer, now just
stores only as a buffer

--- src/lib/models/file.coffee
+++ src/lib/models/file.coffee
@@ -40,11 +40,6 @@
 	# Stat Object
 	stat: null

-	# File data
-	# When we do not have a path to scan
-	# we can just pass over some data instead
-	data: null
-
 	# File buffer
 	buffer: null

@@ -54,7 +49,7 @@

 	# Get Opts
 	getOpts: ->
-		return {@outDirPath, @detectEncoding, @stat, @data, @buffer, @meta}
+		return {@outDirPath, @detectEncoding, @stat, @buffer, @meta}

 	# Clone
 	clone: ->
@@ -192,17 +187,9 @@
 	# ---------------------------------
 	# Helpers

-	# Set Data
-	setData: (data) ->
-		@data = data
-		@
-
-	# Get Data
-	getData: ->
-		return @data
-
 	# Set Buffer
 	setBuffer: (buffer) ->
+		buffer = new Buffer(buffer)  unless Buffer.isBuffer(buffer)
 		@buffer = buffer
 		@

@@ -378,7 +365,7 @@
 			delete attrs.data
 			delete @attributes.data
 		if data?
-			@setData(data)
+			@setBuffer(data)

 		# Buffer
 		if attrs.buffer?
@@ -413,6 +400,14 @@

 		# Log
 		file.log('debug', "Loading the file: #{filePath}")
+
+		# If stat is set, use that
+		if opts.stat
+			file.setStat(opts.stat)
+
+		# If buffer is set, use that
+		if opts.buffer
+			file.setBuffer(opts.buffer)

 		# Async
 		tasks = new TaskGroup().setConfig(concurrency:0).once 'complete', (err) =>
@@ -423,20 +418,6 @@
 				file.normalize (err) ->
 					return next(err)  if err
 					return next(null, file.buffer)
-
-		# If data is set, use that as the buffer
-		data = file.getData()
-		if data?
-			buffer = new Buffer(data)
-			file.setBuffer(buffer)
-
-		# If stat is set, use that
-		if opts.stat
-			file.setStat(opts.stat)
-
-		# If buffer is set, use that
-		if opts.buffer
-			file.setBuffer(opts.buffer)

 		# Stat the file and cache the result
 		tasks.addTask (complete) ->


Fixing issue for calculation of clustering. Improved rendering for points (using middle point).

--- src/d3.timeslider.coffee
+++ src/d3.timeslider.coffee
@@ -503,6 +503,8 @@
             elem.attr('class', 'record')
                 .attr('cx', (a) =>
                     if Array.isArray(a)
+                        if a[0] != a[1]
+                            return @scales.x(new Date(a[0].getTime() + Math.abs(a[1] - a[0]) / 2))
                         return @scales.x(new Date(a[0]))
                     else
                         return @scales.x(new Date(a))
@@ -657,6 +659,8 @@
                           new Date(d3.max(intersecting, (b) -> b[1])),
                           intersecting.map((b) -> b[2]).reduce(((a, r) -> a.concat(r)), [])
                         ]
+                        newBin[0] = current[0] if current[0] < newBin[0]
+                        newBin[1] = current[1] if current[1] > newBin[1]
                         newBin[2].push(current)
                         newBin.cluster = true
                         nonIntersecting.push(newBin)


add demo redirect (#4868)

add demo redirect (#4868)

--- app/core/Router.coffee
+++ app/core/Router.coffee
@@ -135,6 +135,7 @@
     'editor/course/:courseID': go('editor/course/CourseEditView')

     'etc': redirect('/teachers/demo')
+    'demo': redirect('/teachers/demo')

     'file/*path': 'routeToServer'


Delete dead method

Delete dead method

--- src/lines-component.coffee
+++ src/lines-component.coffee
@@ -107,9 +107,6 @@
   hasLineNode: (lineId) ->
     @lineNodesByLineId.hasOwnProperty(lineId)

-  buildTranslate3d: (top) ->
-    "translate3d(0px, #{top}px, 0px)"
-
   buildLineHTML: (line, screenRow) ->
     {editor, mini, showIndentGuide, lineHeight} = @props
     {tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line


テストされたもので書きなおした

テストされたもので書きなおした

--- client/coffee/game.coffee
+++ client/coffee/game.coffee
@@ -61,27 +61,31 @@
       board = new Board(board_array)
       lines = BoardRule.findLinedUpPieces(board)
       marked = BoardRule.markToDeletePieces(lines, board)
+      ns = BoardRule.calcNumberOfPicesToGenerateForColumns(marked)
+      movings = BoardRule.calcPieceMovings(marked, ns)

-      for p in pieces
-        p.del = marked[p.row][p.col]
+      to_add_pieces = ([] for c in [0...6])

-      for r, cs of _.groupBy(pieces, (p) -> p.col)
-        {true:dels, false:lefs} = _.groupBy(cs, (p) -> p.del)
+      for rs, row in board.array
+        for p, col in rs
+          if marked[row][col]
+            to_add_pieces[col].push(p)

-        for p, i in _.sortBy(lefs, (p) -> -p.row)
-          p.row = (4 - i)
+      new_board = BoardRule.makeBoardMove(board, movings, to_add_pieces)

-        if dels?
-          for p, i in dels
-            p.resetColor(_.sample(_.keys(Piece.colorToIndex)))
-            p.moveTo(p.x, (-i - 1) * 128)
-            p.row = 4 - lefs.length - i
-
-      for p in pieces
+      for moving in movings
+        {from:from, to:to} = moving
+        p = new_board.array[to.row][to.col]
+        p.moveTo(from.col * 128, from.row * 128)
+        p.resetColor(_.sample(Piece.color))
+        p.row = to.row
+        p.col = to.col
         p.tl.exec(-> @moving = on)
-        p.tl.moveTo(p.col * 128, p.row * 128, 10).exec(-> @moving = off)
+        p.tl.moveTo(to.col * 128, to.row * 128, 10).exec(-> @moving = off)

-      if pieces.filter((p) -> p.del).length != 0
+      pieces = _.flatten(new_board.array)
+
+      if marked.filter((f) -> f).length != 0
         game.rootScene.tl.delay(10).exec ->
           delete_pieces(pieces)

@@ -132,6 +136,9 @@

       p.on 'touchend', (evt) ->
         delete_pieces(pieces)
+
+        if @x != @col * 128 and @y != @row * 128
+          @tl.moveTo(@col * 128, @row * 128, 10)

         if touch isnt this
           return


Improved when we rerender publications.

Improved when we rerender publications.

Previously, we rerendered a publication only when its display fields
changed, but ignored any other rerendered callback. In fact this is not
good enough because sometimes display wrapper DOM element gets changed
and we do have to rerender into it. This was happening regularly when
one switched from closed access to open access, in another browser
publication did not automatically render now (it did, but into wrong
display wrapper DOM element not in the DOM anymore).

--- client/publication.coffee
+++ client/publication.coffee
@@ -648,32 +648,37 @@

 Template.publicationDisplay.created = ->
   @_displayHandle = null
-  @_displayRendered = false
+  @_displayWrapper = null

 Template.publicationDisplay.rendered = ->
-  return if @_displayRendered
-  @_displayRendered = true
-
-  Deps.nonreactive =>
-    @_displayHandle = Deps.autorun =>
-      publication = Publication.documents.findOne Session.get('currentPublicationId'), Publication.DISPLAY_FIELDS()
-
-      return unless publication
-
-      # Maybe we don't yet have whole publication object available
-      try
-        unless publication.url()
-          return
-      catch error
+  # We want to rendered the publication only if display wrapper DOM element has changed,
+  # so we store a random ID in the DOM element so that we can check if it is an old or
+  # new DOM element. We ignore rendered callbacks which happen for example because
+  # display wrapper's child templates were rendered (eg., when one hovers over a highlight).
+  return if @_displayWrapper?[0]?._displayWrapperId and @_displayWrapper[0]._displayWrapperId is @findAll('.display-wrapper')?[0]._displayWrapperId
+  @_displayWrapper = @findAll '.display-wrapper'
+  @_displayWrapper?[0]?._displayWrapperId = Random.id()
+
+  @_displayHandle?.stop()
+  @_displayHandle = Deps.autorun =>
+    publication = Publication.documents.findOne Session.get('currentPublicationId'), Publication.DISPLAY_FIELDS()
+
+    return unless publication
+
+    # Maybe we don't yet have whole publication object available
+    try
+      unless publication.url()
         return
-
-      publication.show $(@findAll '.display-wrapper')
-      Deps.onInvalidate publication.destroy
+    catch error
+      return
+
+    publication.show $(@_displayWrapper)
+    Deps.onInvalidate publication.destroy

 Template.publicationDisplay.destroyed = ->
   @_displayHandle?.stop()
   @_displayHandle = null
-  @_displayRendered = false
+  @_displayWrapper = null

 makePercentage = (x) ->
   100 * Math.max(Math.min(x, 1), 0)


Clean

Clean

--- client/publication.coffee
+++ client/publication.coffee
@@ -646,7 +646,6 @@

     # Focus body no matter where the annotation was clicked
     # TODO: Improve this
-    console.log e.target
     unless $(e.target).hasClass 'delete'
       Meteor.setTimeout ->
         $(template?.findAll '.body[contenteditable=true]').get(0)?.focus()


Home: campaign removed by status

Home: campaign removed by status

--- client/landing/Intro/home.coffee
+++ client/landing/Intro/home.coffee
@@ -48,8 +48,8 @@

     @campaignContainer = new KDCustomHTMLView

-    # if KD.campaign?.status
-    @campaignContainer.addSubView new TBCampaignHomePageView {}, KD.campaign
+    if KD.campaign?.status
+      @campaignContainer.addSubView new TBCampaignHomePageView {}, KD.campaign

   show:->


Button has some color and a glyphicon.

Button has some color and a glyphicon.

--- picoCTF-web/web/coffee/management-problems.coffee
+++ picoCTF-web/web/coffee/management-problems.coffee
@@ -253,15 +253,14 @@
   render: ->

     statusButton =
-    <Button bsSize="xsmall" onClick={@onStateToggle}>
-      {if @props.disabled then "Enable" else "Disable"}
+    <Button bsSize="xsmall" bsStyle={if @props.disabled then "info" else "warning"} onClick={@onStateToggle}>
+      {if @props.disabled then "Enable" else "Disable"} <Glyphicon glyph={if @props.disabled then "ok" else "minus"}/>
     </Button>

     problemHeader =

       {@props.category} - {@props.name}

-        <Glyphicon className="pad" color="green" glyph="ok"/>
         {statusButton}


Add descriptions, refs noflo/noflo#410

Add descriptions, refs noflo/noflo#410

--- components/ParseSource.coffee
+++ components/ParseSource.coffee
@@ -5,11 +5,16 @@

   # Initialize the component and ports
   c = new noflo.Component
+  c.description = 'Parse a source file into documentation chunks'
+  c.icon = 'code'
   c.inPorts.add 'filename',
+    description: 'Original file name, used for determining syntax'
     datatype: 'string'
   c.inPorts.add 'source',
+    description: 'Source code'
     datatype: 'string'
   c.outPorts.add 'out',
+    description: 'Produced documentation chunks'
     datatype: 'object'

   c.process (input, output) ->


Added command check and second aliases for commands

--- src/cli.coffee
+++ src/cli.coffee
@@ -8,7 +8,30 @@
 module.exports = cli

 ######### - Argument checks and preprocess - ##########
-cli.notEnoughArguments = process.argv.length <= 2
+N_META_ARGUMENTS = 2
+
+cli.notEnoughArguments = process.argv.length <= N_META_ARGUMENTS
+
+# Replace the command argument if it is a second alias defined for convenience
+# (Commander only allows one alias per command)
+replaceSecondAlias = ->
+    SECOND_ALIAS =
+        spd: 'speedup'
+        rm: 'clean'
+        eq: 'equal'
+        an: 'analyze'
+        pf: 'profile'
+        everything: 'all'
+
+    realCommand = SECOND_ALIAS[process.argv[N_META_ARGUMENTS]]
+    process.argv[N_META_ARGUMENTS] = realCommand if realCommand?
+
+checkCommandExists = ->
+    COMMANDS = ['speedup', 's', 'clean', 'C', 'equal', 'e', 'compile', 'c',
+                'profile', 'p']
+
+    # TODO: Replace for logger method call
+    console.log "Invalid command" unless process.argv[N_META_ARGUMENTS] in COMMANDS

 ######### - CLI command, options and version definitions- ##########
 cli.version version
@@ -26,7 +49,7 @@
         "Forward arguments to the programs"
     .option '-l, --last',
         "Only check equality with the program with greatest lexicographic name"
-    .action -> console.log "Equal"
+    .action -> console.log "Equal" # TODO: Implement

 # Compile command
 cli
@@ -36,7 +59,7 @@
     .option '-f, --flags [program-specification:]<flags-string>',
         "Indicate flags to forward to the compilation of programs"
     .option '-a, --all', 'Compile all matching programs in lexicographic order'
-    .action -> console.log "Compile"
+    .action -> console.log "Compile" # TODO: Implement

 # Speedup command
 cli
@@ -55,7 +78,7 @@
         "Forward arguments to the programs"
     .option '-l, --last',
         "Only compute info for the program with greatest lexicographic name"
-    .action -> console.log "Speedup"
+    .action -> console.log "Speedup" # TODO: Implement

 # Profile command
 cli
@@ -66,7 +89,7 @@
         "Profile with OProfile's opannotate"
     .option '-g, --gprof [:options-string]', "Profile with gprof"
     .option '-n, --no-clean', "Do not clean profiler's intermediate files"
-    .action -> console.log "Profile"
+    .action -> console.log "Profile" # TODO: Implement

 # TODO: Analyze = Speedup + Profile command
 # TODO: All = Check + Speedup + Profile command
@@ -79,4 +102,7 @@
     .action -> console.log "Clean"

 cli.help() if cli.notEnoughArguments
+replaceSecondAlias()
+checkCommandExists()
+
 cli.parse process.argv


disable mouse-scroll

disable mouse-scroll

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -11,3 +11,6 @@
   highlightStyle    : 'monokai'
   highlightLanguage : 'remark'
   ratio             : '16:9'
+  navigation: {
+    scroll: false
+  }


Added client side debugging for push.

Added client side debugging for push.

Signed-off-by: Dennis J Harrison Jr <7d2c6da4f2a499159615adaeee258d08b01ee847@gmail.com>

--- app/client/index.coffee
+++ app/client/index.coffee
@@ -0,0 +1,3 @@
+Push.addListener('token', (token) ->
+  alert(JSON.stringify(token))
+)


rewrite by thomas

rewrite by thomas

--- src/scripts/modules/search/advanced/advanced.coffee
+++ src/scripts/modules/search/advanced/advanced.coffee
@@ -65,15 +65,19 @@

       $form = $(e.currentTarget)
       values = $form.serializeArray()
-      query = @formatQuery(values)
+      if @validateSearchable(values)
+        query = @formatQuery(values)
+        @search(query)
+      else
+        $("#alert-danger").show()

-      @search(query)
+    validateSearchable: (values) ->
+      values
+        .filter (field) -> !!field.value?.length
+        .some (field) -> field.name != "sort"

-    search: (query,values) ->
-      if !values || values == 'sort:popularity' || values == 'sort:pubDate'
-        $("#alert-danger").show()
-      else
-        router.navigate("search?q=#{query}", {trigger: true})
+    search: (query) ->
+      router.navigate("search?q=#{query}", {trigger: true})

     formatQuery: (obj) ->
       format = (obj) ->


removed debug

removed debug

--- public/scripts/backbone-schedule/views/friends-list.coffee
+++ public/scripts/backbone-schedule/views/friends-list.coffee
@@ -13,7 +13,6 @@
       @render();

     render: ->
-      console.log(@$el)
       @$el.html $ @friendsListTemplate()

   FriendsListView


Lines 1962-1972 translated (#3994)

Lines 1962-1972 translated (#3994)

Hi. I have some free minutes so i supossed it could be helpfull to translate some lines. Im testing the way to collaborate. If this is the correct way i will make more translations in the future !! Best regards.

Lines 1962-1972 translated
1960 changed from "ciclos" to "bucles While"

--- app/locale/es-ES.coffee
+++ app/locale/es-ES.coffee
@@ -1957,19 +1957,19 @@
     strings: "Cadenas"
     variables: "Variables"
     vectors: "Vectores"
-    while_loops: "Ciclos" # {change}
+    while_loops: "Bucles While" # {change}
     recursion: "Recursividad"
-#    basic_html: "Basic HTML" # TODO: these web-dev concepts will change, don't need to translate
-#    basic_css: "Basic CSS"
-#    basic_web_scripting: "Basic Web Scripting"
-#    intermediate_html: "Intermediate HTML"
-#    intermediate_css: "Intermediate CSS"
-#    intermediate_web_scripting: "Intermediate Web Scripting"
-#    advanced_html: "Advanced HTML"
-#    advanced_css: "Advanced CSS"
-#    advanced_web_scripting: "Advanced Web Scripting"
-#    jquery: "jQuery"
-#    bootstrap: "Bootstrap"
+    basic_html: "HTML Básico" # TODO: these web-dev concepts will change, don't need to translate
+    basic_css: "CSS Básico"
+    basic_web_scripting: "Programación web básica"
+    intermediate_html: "HTML intermedio"
+    intermediate_css: "CSS intermedio"
+    intermediate_web_scripting: "Programación web intermedia"
+    advanced_html: "HTML avanzado"
+    advanced_css: "CSS avanzado"
+    advanced_web_scripting: "Programación web avanzada"
+    jquery: "jQuery"
+    bootstrap: "Bootstrap"

   delta:
     added: "Añadido"


activate discussions in widget list ;)

activate discussions in widget list ;)

--- client/app/Applications/Activity.kdapplication/widgets/widgetview.coffee
+++ client/app/Applications/Activity.kdapplication/widgets/widgetview.coffee
@@ -94,7 +94,7 @@
         callback      : (treeItem, event)=> @changeTab "codeshare", treeItem.getData().title
       "Discussion"    :
         type          : "discussion"
-        disabled      : yes
+        disabled      : no
         callback      : (treeItem, event)=> @changeTab "discussion", treeItem.getData().title
       "Link"          :
         disabled      : no


Restore old module name prefix

Restore old module name prefix

--- tasks/coffee_build.coffee
+++ tasks/coffee_build.coffee
@@ -110,7 +110,7 @@
 # '$$__a_b_d'
 #
 # This assumes you won't name your variables using this prefix
-generateNameForUrl = (grunt, url, from, cwd = '.', prefix = '$$__$$__') ->
+generateNameForUrl = (grunt, url, from, cwd = '.', prefix = '$__') ->
   try
     cwd = path.resolve(cwd)
     from = path.resolve(path.dirname(from))


Fix the handling of the stripe update fn for IE 8.

--- src/main/webapp/coffeescripts-hidden/manager.coffee
+++ src/main/webapp/coffeescripts-hidden/manager.coffee
@@ -87,7 +87,7 @@
       if response.error
         anchortabSite.validationError("#card-number", response.error.message)
       else
-        updateStripeTokenFn = eval("(" + event.updateStripeTokenFn + ")")
+        updateStripeTokenFn = eval("(function() {return " + event.updateStripeTokenFn + ";})()")
         updateStripeTokenFn(response.id)

     nodes = [


Wirepatternize find faces component

Wirepatternize find faces component

--- components/FindFaces-node.coffee
+++ components/FindFaces-node.coffee
@@ -4,32 +4,33 @@
 # @runtime noflo-nodejs
 # @name FindFaces

-class FindFaces extends noflo.Component
-  description: 'Finds faces from a canvas element.'
-  icon: 'smile-o'
-  constructor: ->
-    @inPorts =
-      in: new noflo.Port 'object'
-    @outPorts =
-      faces: new noflo.Port 'array'
+exports.getComponent = ->
+  c = new noflo.Component
+  c.icon = 'smile-o'
+  c.description = 'Finds faces from a canvas element.'

-    @inPorts.in.on 'begingroup', (group) =>
-      @outPorts.faces.beginGroup group
-    @inPorts.in.on "data", (data) =>
-      result = ccv.detect_objects
-        canvas: data,
-        interval: 5,
-        min_neighbors: 1
-      result.sort (a,b) -> return b.confidence-a.confidence
-      for face in result
-        face.x = Math.round face.x
-        face.y = Math.round face.y
-        face.width = Math.round face.width
-        face.height = Math.round face.height
-      @outPorts.faces.send result
-    @inPorts.in.on 'endgroup', =>
-      @outPorts.faces.endGroup()
-    @inPorts.in.on 'disconnect', =>
-      @outPorts.faces.disconnect()
+  c.inPorts.add 'in',
+    datatype: 'object'
+  c.outPorts.add 'faces',
+    datatype: 'array'

-exports.getComponent = -> new FindFaces
+  noflo.helpers.WirePattern c,
+    in: 'in'
+    out: 'faces'
+    forwardGroups: true
+    async: true
+  , (data, groups, out, callback) ->
+    result = ccv.detect_objects
+      canvas: data,
+      interval: 5,
+      min_neighbors: 1
+    result.sort (a,b) -> return b.confidence-a.confidence
+    for face in result
+      face.x = Math.round face.x
+      face.y = Math.round face.y
+      face.width = Math.round face.width
+      face.height = Math.round face.height
+    out.send result
+    do callback
+
+  c


Added simple alert if there was a problem loading the book

--- scripts/gh-book/app.coffee
+++ scripts/gh-book/app.coffee
@@ -144,8 +144,16 @@

           # Delay the route handling until the initial content is loaded
           # TODO: Move this into the controller
-          goWorkspace: () -> setDefaultRepo(); allContent.load().done () => controller.goWorkspace()
-          goEdit: (id)    -> setDefaultRepo(); allContent.load().done () => controller.goEdit(id)
+          goWorkspace: () ->
+            setDefaultRepo()
+            allContent.load()
+            .fail((err) => alert('There was a problem loading the repo. Are you pointing to a valid book?'))
+            .done () => controller.goWorkspace()
+          goEdit: (id)    ->
+            setDefaultRepo()
+            allContent.load()
+            .fail((err) => alert('There was a problem loading the repo. Are you pointing to a valid book?'))
+            .done () => controller.goEdit(id)

         Backbone.history.start


Couple more debug messages

Couple more debug messages

--- src/api/Remote-Chrome-API.coffee
+++ src/api/Remote-Chrome-API.coffee
@@ -59,7 +59,7 @@
     @_chrome.Page.enable();
     @_chrome.Page.frameNavigated (data)=>
       #console.log(">>> frameNavigated: #{data.json_pretty()}")
-      #console.log(">>> frameNavigated #{data.frame.url}")
+      console.log(">>> frameNavigated #{data.frame.url}")
       eventKey = data.frame.id
       @page_Events.emit(eventKey)

@@ -67,7 +67,7 @@
       #console.log(">>> domContentEventFired: #{data.json_pretty()}")

     @_chrome.Page.loadEventFired (data)=>
-      #console.log(">>> loadEventFired: #{data.json_pretty()}")
+      console.log(">>> loadEventFired: #{data.json_pretty()}")
       @page_Events.emit('loadEventFired')

     @_chrome.DOM.documentUpdated ()=>
@@ -79,7 +79,7 @@
     @_chrome.Page.navigate {url:url},  (error, data)=>
       if not error
         eventKey = data.frameId
-
+        ">>> console.log: setting events for page; #{url}".log()
         @page_Events.removeAllListeners('loadEventFired')   # seems to be more reliable (but we don't an eventKey
         @page_Events.on 'loadEventFired', callback          # the problem is that at the moment if we get the DOM just after an frameNavigated, in losts of cases
                                                             # the DOM is not fully (loaded)


kubernikus: improve create button visibility check.

--- plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/list.coffee
+++ plugins/kubernetes/app/assets/javascripts/kubernetes/components/clusters/list.coffee
@@ -16,7 +16,7 @@
     {flashError, isFetching, clusters, handleNewCluster, error, kubernikusBaseUrl} = @props

     div null,
-      if flashError or error
+      if flashError? or error?
         div className: 'alert alert-error alert-dismissible',
           button className: 'close', type: 'button', 'data-dismiss': 'alert',
             span null,
@@ -24,7 +24,7 @@
           flashError
           error

-      unless clusters && clusters.length
+      unless isFetching || error? || (clusters? && clusters.length > 0)
         div className: 'toolbar toolbar-controlcenter',
           div className: 'main-control-buttons',
             button className: "btn btn-primary", onClick: ((e) => e.preventDefault(); handleNewCluster()),
@@ -48,7 +48,7 @@
               td colSpan: '5',
                 span className: 'spinner'
         else
-          if clusters && clusters.length
+          if clusters? && clusters.length
             for cluster in clusters
               React.createElement ClusterItem, cluster: cluster, key: cluster.name, kubernikusBaseUrl: kubernikusBaseUrl

@@ -56,7 +56,7 @@
             tbody null,
               tr null,
                 td colSpan: '5',
-                  if error
+                  if error?
                     'Could not retrieve clusters'
                   else
                     'No clusters found'


fix for deprecated warning message getting from moment js for DHL carrier

Getting following error for DHL carrier,

```
Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versi
ons. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.
```

--- src/dhl.coffee
+++ src/dhl.coffee
@@ -43,7 +43,8 @@

   getEta: (shipment) ->
     eta = shipment['EstDlvyDate']?[0]
-    if eta? then moment(eta).toDate()
+    formatSpec = 'YYYYMMDD HHmmss ZZ'
+    if eta? then moment(eta, formatSpec).toDate()

   getService: (shipment) ->

@@ -55,7 +56,8 @@
     return unless dateString?
     timeString ?= '00:00'
     inputString = "#{dateString} #{timeString} +0000"
-    moment(inputString).toDate()
+    formatSpec = 'YYYYMMDD HHmmss ZZ'
+    moment(inputString, formatSpec).toDate()

   presentAddress: (rawAddress) ->
     return unless rawAddress?


Remove Visibility API usage from Pusher

Remove Visibility API usage from Pusher

--- app/utils/pusher.coffee
+++ app/utils/pusher.coffee
@@ -11,13 +11,6 @@
   Pusher.warn = @warn.bind(this)
   Pusher.host = config.host if config.host
   @pusher = new Pusher(config.key, encrypted: config.encrypted, disableStats: true)
-
-  @callbacksToProcess = []
-
-  Visibility.change (e, state) =>
-    @processSavedCallbacks() if state == 'visible'
-
-  setInterval @processSavedCallbacks.bind(this), @processingIntervalWhenHidden

 TravisPusher.prototype.subscribeAll = (channels) ->
   @subscribe(channel) for channel in channels
@@ -45,35 +38,18 @@
   else
     channel

-# process pusher messages in batches every 5 minutes when the page is hidden
-TravisPusher.prototype.processingIntervalWhenHidden = 1000 * 60 * 5
-
 TravisPusher.prototype.receive = (event, data) ->
   return if event.substr(0, 6) == 'pusher'
   data = @normalize(event, data) if data.id

-  @processWhenVisible =>
-    # TODO remove job:requeued, once sf-restart-event has been merged
-    # TODO this also needs to clear logs on build:created if matrix jobs are already loaded
-    if event == 'job:created' || event == 'job:requeued'
-      if job = @store.getById('job', data.job.id)
-        job.clearLog()
+  # TODO remove job:requeued, once sf-restart-event has been merged
+  # TODO this also needs to clear logs on build:created if matrix jobs are already loaded
+  if event == 'job:created' || event == 'job:requeued'
+    if job = @store.getById('job', data.job.id)
+      job.clearLog()

-    Ember.run.next =>
-      @store.receivePusherEvent(event, data)
-
-TravisPusher.prototype.processSavedCallbacks = ->
-  while callback = @callbacksToProcess.shiftObject()
-    callback.call(this)
-
-TravisPusher.prototype.processLater = (callback) ->
-  @callbacksToProcess.pushObject(callback)
-
-TravisPusher.prototype.processWhenVisible = (callback) ->
-  if Visibility.hidden() && Visibility.isSupported()
-    @processLater(callback)
-  else
-    callback.call(this)
+  Ember.run.next =>
+    @store.receivePusherEvent(event, data)

 TravisPusher.prototype.normalize = (event, data) ->
   switch event


Change Markdown formatter

Change Markdown formatter

--- atom/config.cson
+++ atom/config.cson
@@ -5,7 +5,8 @@
     json:
       beautify_on_save: true
     markdown:
-      default_beautifier: "Remark"
+      beautify_on_save: true
+      default_beautifier: "Prettier"
   "atom-material-ui":
     colors:
       abaseColor: "#2679db"


Disable Deprecation Cop package

Disable Deprecation Cop package

--- atom/config.cson
+++ atom/config.cson
@@ -17,6 +17,7 @@
       "tree-view"
       "bookmarks"
       "autosave"
+      "deprecation-cop"
     ]
     projectHome: "~"
     themes: [


Switch to the regular font weight

Switch to the regular font weight

Thick or thin ... the eternal question ...

--- atom/config.cson
+++ atom/config.cson
@@ -6,7 +6,7 @@
   'metrics':
     'userId': '51eeb6113c1ae801c9aade9b6d679aa5189ced25'
   'editor':
-    'fontFamily': 'SourceCodePro-Light'
+    'fontFamily': 'Source Code Pro'
     'preferredLineLength': 100
     'invisibles':
       'cr': '↩'


Also auto-indent after shift+a

Also auto-indent after shift+a

--- atom/init.coffee
+++ atom/init.coffee
@@ -1,8 +1,13 @@
-# auto-indent after changing line (`c c`)
+# auto-indent when changing line or inserting at end of line
 atom.commands.onDidDispatch (evt) ->
-  return unless evt.type is 'vim-mode-plus:change'
+  validCommands = [
+    'vim-mode-plus:change',
+    'vim-mode-plus:insert-after-end-of-line'
+  ]
+  return unless evt.type in validCommands
   editor = atom.workspace.getActivePaneItem()
+  element = editor.getElement()
+  return unless 'insert-mode' in element.classList
   for cursor in editor.getCursors()
     return unless cursor.getBufferColumn() is 0
-  element = editor.getElement()
-  editor.autoIndentSelectedRows() if 'insert-mode' in element.classList
+  editor.autoIndentSelectedRows()


Social: fix error message

Social: fix error message

--- workers/social/lib/social/models/socialapi/requests.coffee
+++ workers/social/lib/social/models/socialapi/requests.coffee
@@ -47,7 +47,7 @@

 postToChannel = (data, callback)->
   if not data.channelId or not data.accountId or not data.body
-    return callback { message: "Request is not valid for creating channel"}
+    return callback { message: "Request is not valid for posting message"}

   url = "#{SOCIAL_API_URL}/channel/#{data.channelId}/message"
   post url, data, callback


use native function

use native function

--- src/dom.coffee
+++ src/dom.coffee
@@ -1,5 +1,4 @@
 _     = require('lodash')
-_.str = require('underscore.string')

 lastKeyEvent = null    # Workaround for fact we can't dispatch keyboard event via javascript

@@ -101,7 +100,7 @@
     if node.classList?
       node.classList.add(cssClass)
     else if node.className?
-      node.className = _.str.trim(node.className + ' ' + cssClass)
+      node.className = (node.className + ' ' + cssClass).trim()

   addEventListener: (node, eventName, listener) ->
     node.addEventListener(eventName, (event) ->
@@ -154,8 +153,8 @@
     obj = _.reduce(styleString.split(';'), (styles, str) ->
       [name, value] = str.split(':')
       if name and value
-        name = _.str.trim(name)
-        value = _.str.trim(value)
+        name = name.trim()
+        value = value.trim()
         styles[name.toLowerCase()] = value
       return styles
     , {})


handle multiple newlines and windows

handle multiple newlines and windows

--- src/dom.coffee
+++ src/dom.coffee
@@ -148,7 +148,7 @@
       when DOM.ELEMENT_NODE
         return "" if node.tagName == DOM.DEFAULT_BREAK_TAG
         return node.textContent if node.textContent?
-        return node.innerText.replace('\n', '') if node.innerText?
+        return node.innerText.replace(/[\r\n]/g, '') if node.innerText?
         return ""
       when DOM.TEXT_NODE then return node.data or ""
       else return ""


get rid of config commands

get rid of config commands

--- server-ce/Gruntfile.coffee
+++ server-ce/Gruntfile.coffee
@@ -51,7 +51,6 @@
 	repo: "https://github.com/sharelatex/spelling-sharelatex.git"
 	version: "master"
 }]
-
 module.exports = (grunt) ->
 	grunt.loadNpmTasks 'grunt-bunyan'
 	grunt.loadNpmTasks 'grunt-execute'
@@ -76,7 +75,7 @@
 					limit: SERVICES.length
 					logConcurrentOutput: true
 		coffee:
-			migrate:
+			migrate:
 				expand: true,
 				flatten: false,
 				cwd: './',
@@ -109,9 +108,8 @@
 						"Misc": [
 							"help"
 						]
-						"Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install", "install:dirs", "install:config"])
+						"Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install", "install:dirs"])
 						"Update tasks": ("update:#{service.name}" for service in SERVICES).concat(["update:all", "update"])
-						"Config tasks": ["install:config"]
 						"Checks": ["check", "check:redis", "check:latexmk", "check:s3", "check:make"]

 	for service in SERVICES
@@ -127,14 +125,13 @@
 				done = @async()
 				Helpers.createNewRelease(service, grunt.option("release"), done)

-	grunt.registerTask 'install:config', "Copy the example config into the real config", () ->
-		Helpers.installConfig @async()
+
 	grunt.registerTask 'install:dirs', "Copy the example config into the real config", () ->
 		Helpers.createDataDirs @async()
 	grunt.registerTask 'install:all', "Download and set up all ShareLaTeX services",
 		["check:make"].concat(
 			("install:#{service.name}" for service in SERVICES)
-		).concat(["install:config", "install:dirs"])
+		).concat([ "install:dirs"])
 	grunt.registerTask 'install', 'install:all'
 	grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services",
 		["check:make"].concat(
@@ -214,7 +211,7 @@
 				proc = spawn "git", ["pull"], cwd: dir, stdio: "inherit"
 				proc.on "close", () ->
 					callback()
-
+
 		createNewRelease: (service, version, callback = (error) ->) ->
 			dir = service.name
 			proc = spawn "sed", [
@@ -307,9 +304,9 @@
 					latexmk comes with TexLive 2013, and must be a version from 2013 or later.
 					If you have already have TeXLive installed, then make sure it is
 					included in your PATH (example for 64-bit linux):
-
+
 						export PATH=$PATH:/usr/local/texlive/2014/bin/x86_64-linux/
-
+
 					This is a not a fatal error, but compiling will not work without latexmk.
 					"""
 					return callback(error)
@@ -334,7 +331,7 @@
 							"""
 							error = new Error("latexmk is too old")
 				callback(error)
-
+
 		checkAspell: (callback = (error) ->) ->
 			grunt.log.write "Checking aspell is installed... "
 			exec "aspell dump dicts", (error, stdout, stderr) ->
@@ -342,15 +339,15 @@
 					grunt.log.error "FAIL."
 					grunt.log.errorlns """
 					Either aspell is not installed or is not in your PATH.
-
+
 					On Ubuntu you can install aspell with:
-
+
 						sudo apt-get install aspell
-
+
 					Or on a mac:
-
+
 						brew install aspell
-
+
 					This is not a fatal error, but the spell-checker will not work without aspell
 					"""
 					return callback(error)
@@ -382,11 +379,11 @@
 					Please configure your Amazon S3 credentials in config/settings.development.coffee

 					Amazon S3 (Simple Storage Service) is a cloud storage service provided by
-					Amazon. ShareLaTeX uses S3 for storing binary files like images. You can
+					Amazon. ShareLaTeX uses S3 for storing binary files like images. You can
 					sign up for an account and find out more at:

 							http://aws.amazon.com/s3/
-
+
 					"""
 					return callback()
 				client.getFile "does-not-exist", (error, response) ->
@@ -413,7 +410,7 @@
 					else
 						grunt.log.error "FAIL."
 						grunt.log.errorlns """
-						Could not find directory "#{Settings.filestore.stores.user_files}".
+						Could not find directory "#{Settings.filestore.stores.user_files}".
 						Please check your configuration.
 						"""
 					callback()
@@ -428,11 +425,11 @@
 					grunt.log.error "FAIL."
 					grunt.log.errorlns """
 					Either make is not installed or is not in your path.
-
+
 					On Ubuntu you can install make with:
-
+
 					    sudo apt-get install build-essential
-
+
 					"""
 					return callback(error)
 				else if error?
@@ -445,4 +442,3 @@
 			template = fs.readFileSync("package/upstart/sharelatex-template.conf").toString()
 			for service in SERVICES
 				fs.writeFileSync "package/upstart/sharelatex-#{service.name}.conf", template.replace(/__SERVICE__/g, service.name)
-


ignore 404 even if there's supposed to be something there

--- resources/assets/coffee/_classes/osu-audio.coffee
+++ resources/assets/coffee/_classes/osu-audio.coffee
@@ -42,8 +42,8 @@
     @publish 'initializing'
     promise = @player().play()
     # old api returns undefined
-    promise?.catch (error) =>
-      return if error.name == 'AbortError' || error.name == 'NotSupportedError' && !osu.present(@urlGet())
+    promise?.catch (error) ->
+      return if error.name == 'AbortError' || error.name == 'NotSupportedError'
       throw error


remove unused async require from test helpers

--- server/test/helpers.coffee
+++ server/test/helpers.coffee
@@ -3,7 +3,6 @@
 GLOBAL.sequelize ||= require('../model_bindings.coffee')(ENV)

 app = require('../app.coffee')
-async = require('async')
 test_server = null


Stop passing in includes separately to the CollectionLoader

--- vendor/assets/javascripts/brainstem/data-loader.coffee
+++ vendor/assets/javascripts/brainstem/data-loader.coffee
@@ -6,6 +6,8 @@

   _parseLoadOptions: (loadOptions) ->
     @loadOptions = $.extend {}, loadOptions
+    @loadOptions.plainInclude = @loadOptions.include
+    @loadOptions.include = Brainstem.Utils.wrapObjects(Brainstem.Utils.extractArray "include", @loadOptions)
     @loadOptions.only = if @loadOptions.only then _.map((Brainstem.Utils.extractArray "only", @loadOptions), (id) -> String(id)) else null
     @loadOptions.filters ?= {}
     @loadOptions.thisLayerInclude = _(@loadOptions.include).map((i) -> _.keys(i)[0]) # pull off the top layer of includes
@@ -226,7 +228,7 @@
   loadCollection: (name, options) =>
     options = $.extend({}, options, name: name)
     @_checkPageSettings options
-    include = Brainstem.Utils.wrapObjects(Brainstem.Utils.extractArray "include", options)
+
     if options.search
       options.cache = false

@@ -239,7 +241,7 @@
       @storageManager.handleExpectations name, collection, options
     else
       cl = new Brainstem.CollectionLoader(storageManager: @storageManager)
-      collection = cl.loadCollection($.extend({}, options, include: include, plainInclude: options.include))
+      collection = cl.loadCollection(options)

     collection


inherit _reloadUIElements from GenericPage

Signed-off-by: Steven Hoffman <fe20d0b9f22d8cad9ff6cecdb579c0c0dbedec8a@me.com>

--- vendor/assets/javascripts/fustrate/generic_form.coffee
+++ vendor/assets/javascripts/fustrate/generic_form.coffee
@@ -2,7 +2,7 @@

 class Fustrate.GenericForm extends Fustrate.GenericPage
   _reloadUIElements: =>
-    @fields = {}
+    super

     for domObject in $('[name][id]', @root)
       element = $ domObject


removed extra space

removed extra space

--- public/dreamcatcher/controllers/settings_controller.coffee
+++ public/dreamcatcher/controllers/settings_controller.coffee
@@ -79,8 +79,7 @@

     $('form#change_password').bind 'ajax:error', (xhr, status, error)->
       log xhr.errors
-
-
+
   '#default-sharing-list change': (element) ->
     defaultSharingLevel = element.val()
     @displayDefaultSharingLevel defaultSharingLevel


code formatting

code formatting

--- packages/rocketchat-hubot/hubot.coffee
+++ packages/rocketchat-hubot/hubot.coffee
@@ -55,8 +55,8 @@
 		console.log 'ROCKETCHATADAPTER -> send'.blue
 		# console.log envelope, strings
 		sendHelper @robot, envelope, strings, (string) =>
-			# console.log "send #{envelope.room}: #{string} (#{envelope.user.id})" if DEBUG
-			RocketChat.sendMessage  RocketBot.user, { msg: string }, { _id: envelope.room }
+			console.log "send #{envelope.room}: #{string} (#{envelope.user.id})" if DEBUG
+			RocketChat.sendMessage RocketBot.user, { msg: string }, { _id: envelope.room }

 	# Public: Raw method for sending emote data back to the chat source.
 	#


Read CSRF token from meta tag, send with requests

--- src/api.coffee
+++ src/api.coffee
@@ -7,6 +7,7 @@

 $ = require 'jquery'
 _ = require 'underscore'
+CSRF_Token = $('meta[name=csrf-token]').attr('content')

 {TimeActions} = require './flux/time'
 {CurrentUserActions, CurrentUserStore} = require './flux/current-user'
@@ -44,6 +45,7 @@
         method: httpMethod or httpMethodOverride
         dataType: 'json'
         headers:
+          'X-CSRF-Token': CSRF_Token,
           token: CurrentUserStore.getToken()
       if payload?
         opts.data = JSON.stringify(payload)


just kidding, now 'uid' requirements are completely gone

--- src/app.coffee
+++ src/app.coffee
@@ -23,7 +23,6 @@
       description: "Earth fissure maps are prepared by the Arizona Geological Survey (\"AZGS\") in accordance \
         with Ariz. Rev. Stat. § 27-152.01(3)."
       legend: new app.models.Legend [
-          uid: "continuousearthfissure"
           caption: "Continuous Earth Fissure"
           attribute: "fisstype"
           value: "Continuous Earth Fissure"
@@ -31,7 +30,6 @@
           imageInfo:
             color: "#000000"
         ,
-          uid: "discontinuousearthfissure"
           caption: "Discontinuous Earth Fissure"
           attribute: "fisstype"
           value: "Discontinuous Earth Fissure"
@@ -39,7 +37,6 @@
           imageInfo:
             color: "#FF0000"
         ,
-          uid: "reportedunconfirmedearthfissure"
           caption: "Reported, Unconfirmed Earth Fissure"
           attribute: "fisstype"
           value: "Reported, Unconfirmed Earth Fissure"
@@ -59,7 +56,6 @@
       typeName: "azgs:activefaults"
       useD3: true
       legend: new app.models.Legend [
-          uid: "holocene10ka"
           caption: "Holocene ( <10 ka )"
           attribute: "activefaults"
           value: "2.13.2"
@@ -67,7 +63,6 @@
           imageInfo:
             color: "#FFA500"
         ,
-          uid: "latequaternary750ka"
           caption: "Late Quaternary ( <750 ka )"
           attribute: "activefaults"
           value: "2.13.3"
@@ -75,7 +70,6 @@
           imageInfo:
             color: "#008000"
         ,
-          uid: "quaternaryundifferentiated"
           caption: "Quaternary (Undifferentiated)"
           attribute: "activefaults"
           value: "2.13.4"
@@ -93,7 +87,6 @@
       serviceUrl: geoserverUrl
       typeName: "azgs:earthquakedata"
       legend: new app.models.Legend [
-          uid: "0-1"
           caption: "0 - 1"
           attribute: "calculated_magnitude"
           value: "[-0.1, 1.1]"
@@ -102,7 +95,6 @@
             radius: 5
             color: "#FFFF00"
         ,
-          uid: "1-2"
           caption: "1 - 2"
           attribute: "calculated_magnitude"
           value: "[0.9, 2.1]"
@@ -111,7 +103,6 @@
             radius: 10
             color: "#FFDD00"
         ,
-          uid: "2-3"
           caption: "2 - 3"
           attribute: "calculated_magnitude"
           value: "[1.9, 3.1]"
@@ -120,7 +111,6 @@
             radius: 15
             color: "#FFBF00"
         ,
-          uid: "3-4"
           caption: "3 - 4"
           attribute: "calculated_magnitude"
           value: "[2.9, 4.1]"
@@ -129,7 +119,6 @@
             radius: 20
             color: "#FF9D00"
         ,
-          uid: "4-5"
           caption: "4 - 5"
           attribute: "calculated_magnitude"
           value: "[3.9, 5.1]"
@@ -138,7 +127,6 @@
             radius: 25
             color: "#FF8000"
         ,
-          uid: "5-6"
           caption: "5 - 6"
           attribute: "calculated_magnitude"
           value: "[4.9, 6.1]"
@@ -147,7 +135,6 @@
             radius: 30
             color: "#FF5E00"
         ,
-          uid: "6-7"
           caption: "6 - 7"
           attribute: "calculated_magnitude"
           value: "[5.9, 7.1]"
@@ -156,7 +143,6 @@
             radius: 35
             color: "#FF4000"
         ,
-          uid: "7-8"
           caption: "7 - 8"
           attribute: "calculated_magnitude"
           value: "[6.9, 8.1]"
@@ -197,13 +183,11 @@
       wfsUrl: "http://data.usgin.org/arizona/ows"
       typeName: "azgs:floods"
       legend: new app.models.Legend [
-          uid: "floodshigh"
           caption: "High"
           imageTemplateId: "floodImage"
           imageInfo:
             color: "#0039BF"
         ,
-          uid: "floodsmedium"
           caption: "Medium"
           imageTemplateId: "floodImage"
           imageInfo:


This updates the wording, but I haven't been able to test it yet.  I'm not sure if I should keep the nbsp's in there because I haven't seen it with my eyes yet.

--- src/components/scores/index.cjsx
+++ src/components/scores/index.cjsx
@@ -193,9 +193,9 @@
         </span>
       else
         <span className='course-scores-note tab'>
-          Scores on the due date are displayed.
+          Scores reflect work submitted on time.
           &nbsp
-          Click an orange triangle to see late work.
+          To accept late work, click the orange triangle.
         </span>
     tableFilters =
       <TableFilters


ops, remove those semicolons

ops, remove those semicolons

--- src/app.coffee
+++ src/app.coffee
@@ -102,9 +102,9 @@
 		wifi = Promise.promisifyAll(wifi)
 		console.log('WiFi initialized')

-		app.use(bodyParser.urlencoded());
-		app.use(bodyParser.json());
-
+		app.use(bodyParser.urlencoded())
+		app.use(bodyParser.json())
+
 		app.use(express.static(__dirname + '/public'))
 		app.get '/ssids', (req, res) ->
 			res.send(ssidList)


change location for geoserver

change location for geoserver

--- src/app.coffee
+++ src/app.coffee
@@ -16,14 +16,14 @@
   minZoom: 6
   maxZoom: 15

-app.geoserverUrl = "http://data.azgs.az.gov/arizona-hazards/azgs/ows"
+app.geoserverUrl = "http://10.208.3.125:8080/geoserver"

 # Setup data layers
 dataLayers = [
     new app.models.GeoJSONLayer
       id: "earthFissures"
       layerName: "Earth Fissures"
-      serviceUrl: app.geoserverUrl
+      serviceUrl: app.geoserverUrl + "/azgs/ows"
       serviceType: "WFS"
       typeName: "azgs:earthfissures"
       active: false
@@ -86,7 +86,7 @@
     new app.models.GeoJSONLayer
       id: "activeFaults"
       layerName: "Active Faults"
-      serviceUrl: app.geoserverUrl
+      serviceUrl: app.geoserverUrl + "/azgs/ows"
       serviceType: "WFS"
       typeName: "azgs:activefaults"
       active: false
@@ -140,7 +140,7 @@
     new app.models.GeoJSONLayer
       id: "earthquakes"
       layerName: "Earthquake Epicenters"
-      serviceUrl: app.geoserverUrl
+      serviceUrl: app.geoserverUrl + "/azgs/ows"
       serviceType: "WFS"
       typeName: "azgs:earthquakedata"
       citation: "Arizona Geological Survey"
@@ -243,9 +243,9 @@
     new app.models.WmsLayer
       id: "floodPotential"
       layerName: "Flood Potential"
-      serviceUrl: "http://data.azgs.az.gov/arizona-hazards/azgs/wms"
+      serviceUrl: app.geoserverUrl + "/azgs/wms"
       serviceType: "WMS"
-      wfsUrl: "http://data.azgs.az.gov/arizona-hazards/azgs/ows"
+      wfsUrl: app.geoserverUrl + "/azgs/ows"
       typeName: "azgs:floods"
       active: false
       citation: "Arizona Division of Emergency Management and Military Affairs"


test language service

test language service

--- karma/test-services.coffee
+++ karma/test-services.coffee
@@ -365,6 +365,48 @@
       it('posts to export endpoint', () ->
         $httpBackend.expectPOST('/messageexport/create/?archived=0&folder=inbox', null).respond('')
         MessageService.startExport({folder: "inbox"})
+        $httpBackend.flush()
+      )
+    )
+  )
+
+  #=======================================================================
+  # Tests for LanguageService
+  #=======================================================================
+  describe('LanguageService', () ->
+    LanguageService = null
+
+    beforeEach(inject((_LanguageService_) ->
+      LanguageService = _LanguageService_
+
+      test.language = {
+        id: 602,
+        code: "afr_ZA",
+        name: "Afrikaans",
+        location: "South Africa"
+      }
+    ))
+
+    describe('fetchLanguages', () ->
+      it('gets Languages from search endpoint', () ->
+        $httpBackend.expectGET('/language/search/?name=afr')
+        .respond('{
+          "results": [{
+            "id": 602,
+            "code": "afr_ZA",
+            "name": "Afrikaans",
+            "location": "South Africa"
+          }],
+          "has_more": false
+        }')
+        LanguageService.fetchLanguages({name: "afr"}).then((replies) ->
+          expect(replies).toEqual([{
+            id: 602,
+            code: "afr_ZA",
+            name: "Afrikaans",
+            location: "South Africa"
+          }])
+        )
         $httpBackend.flush()
       )
     )


for interactive use only: li list is back in colour

--- code/li.coffee
+++ code/li.coffee
@@ -1,10 +1,14 @@
 #!/usr/bin/env coffee
+
+tty = require 'tty'

 _ = require 'underscore'
 _s = require 'underscore.string'
 async = require 'async'

 Linode = require 'linode'
+
+interactive = tty.isatty(process.stdout.fd)

 command = {}

@@ -165,18 +169,22 @@
           log_one_item item for item in list

 log_one_item = (item) ->
-  colour = pick_colour item.state
-  colour_off = pick_colour()
+  colour = ''
+  colour_off = ''
+  name_colour = ''
+  # It's critical that we don't use colour when the output
+  # is going into a pipe, because some scripts would get
+  # confused by colour.
+  if interactive
+    colour = pick_colour item.state
+    colour_off = pick_colour()
+    name_colour = '\x1b[22;37m'
   ipstuff = ''
   if item.ip_address?
     ipstuff += ' Pub:' + item.ip_address
   if item.private_ip_address?
     ipstuff += ' Priv:' + item.private_ip_address
-  # Disable colour for now as doesn't work with some scripting of li list
-  # XXX DO NOT enable without making the colour conditional on it being called by a human
-  colour = ''
-  colour_off = ''
-  console.log "#{colour}#{item.name}#{colour_off} \x1b[22;37m[#{item.config.name}]#{ipstuff}\x1b[0m #{item.comments}"
+  console.log "#{colour}#{item.name}#{colour_off} #{name_colour}[#{item.config.name}]#{ipstuff}#{colour_off} #{item.comments}"

 friendly_state = (state) ->
   if LINODE_STATE[state]?


Updating to work with latest hubot.

Updating to work with latest hubot.

--- src/irc.coffee
+++ src/irc.coffee
@@ -1,17 +1,10 @@
-Robot   = require('hubot').robot()
-Adapter = require('hubot').adapter()
+Robot   = require('hubot').Robot
+Adapter = require('hubot').Adapter
+TextMessage = require('hubot').TextMessage

 Irc     = require 'irc'

 class IrcBot extends Adapter
-  constructor: (@robot) ->
-    super @robot
-
-    @robot.notice = (user, strings...) ->
-      @adapter.notice user, strings...
-
-    @robot.Response = IrcResponse
-
   send: (user, strings...) ->
     for str in strings
       if not str?
@@ -47,6 +40,12 @@
   part: (channel) ->
     @bot.part channel, () ->
       console.log('left %s', channel)
+
+  kick: (channel, client, message) ->
+    @bot.emit 'raw',
+      command: 'KICK'
+      nick: process.env.HUBOT_IRC_NICK
+      args: [ channel, client, message ]

   command: (command, strings...) ->
     @bot.send command, strings...
@@ -110,7 +109,7 @@
         user.room = null
         console.log "msg <#{from}> #{message}"

-      self.receive new Robot.TextMessage(user, message)
+      self.receive new TextMessage(user, message)

     bot.addListener 'error', (message) ->
         console.error('ERROR: %s: %s', message.command, message.args.join(' '))
@@ -135,7 +134,7 @@

     self.emit "connected"

-class IrcResponse extends Robot.Response
+class IrcResponse extends Response
   notice: (strings...) ->
     @robot.adapter.notice @message.user, strings...


Remove unused variables

Remove unused variables

--- resources/assets/coffee/_classes/forum-post-preview.coffee
+++ resources/assets/coffee/_classes/forum-post-preview.coffee
@@ -18,16 +18,6 @@

 class @ForumPostPreview
   constructor: ->
-    @input = '.js-forum-topic-reply--input'
-
-    @writeButton = '.js-forum-reply-preview--hide'
-    @previewButton = '.js-forum-reply-preview--show'
-
-    @editBox = '.js-forum-reply-write'
-    @previewBox = '.js-forum-reply-preview'
-
-    @lastBody = null
-
     $(document).on 'click', '.js-forum-post-preview--show', @fetchPreview
     $(document).on 'click', '.js-forum-post-preview--hide', @hidePreview


Update bounds for orto map.

Update bounds for orto map.

--- src/map.coffee
+++ src/map.coffee
@@ -11,11 +11,7 @@
     RETINA_MODE = window.devicePixelRatio > 1

     getMaxBounds = (layer) ->
-        if layer == 'ortographic'
-            L.latLngBounds L.latLng(60.11322159453442, 24.839029712845157),
-                L.latLng(60.30146342058585, 25.23664312801843)
-        else
-            L.latLngBounds L.latLng(59.5, 24.2), L.latLng(60.5, 25.5)
+        L.latLngBounds L.latLng(59.5, 24.2), L.latLng(60.5, 25.5)

     wmtsPath = (style, language) ->
         stylePath =


cleanup. doNothing -> noop

cleanup. doNothing -> noop

--- src/mpd.coffee
+++ src/mpd.coffee
@@ -95,11 +95,11 @@
       throw "obj already exists"
     list.splice pos, 0, obj

-  doNothing = ->
+  noop = ->

   escape = (str) ->
     # replace all " with \"
-    str.replace /"/g, '\\"'
+    str.toString().replace /"/g, '\\"'

   createEventHandlers: =>
     registrarNames = [
@@ -194,11 +194,11 @@
         handlers.splice i, 1
         return

-  sendCommand: (command, callback) =>
+  sendCommand: (command, callback=noop) =>
     @msgHandlerQueue.push callback
     @send command

-  sendCommands: (command_list, callback) =>
+  sendCommands: (command_list, callback=noop) =>
     return if command_list.length == 0
     @msgHandlerQueue.push callback
     @send "command_list_begin\n#{command_list.join("\n")}\ncommand_list_end"
@@ -242,7 +242,7 @@
       # notify listeners
       @raiseEvent 'onLibraryUpdate'

-  addTracksToLibrary: (msg, mpdTracksHandler=->) =>
+  addTracksToLibrary: (msg, mpdTracksHandler=noop) =>
     # build list of tracks from msg
     mpd_tracks = {}
     current_file = null
@@ -304,20 +304,13 @@

   queueFile: (file) =>
-    @sendCommand "add \"#{escape(file)}\"", doNothing, doNothing
-
-  play: =>
-    @sendCommand "play", doNothing, doNothing
-
-  pause: =>
-    @sendCommand "pause", doNothing, doNothing
-
-  next: =>
-    @sendCommand "next", doNothing, doNothing
-
-  prev: =>
-    @sendCommand "previous", doNothing, doNothing
+    @sendCommand "add \"#{escape(file)}\""
+
+  play: => @sendCommand "play"
+  pause: => @sendCommand "pause"
+  next: => @sendCommand "next"
+  prev: => @sendCommand "previous"

   playId: (track_id) =>
-    @sendCommand "playid #{track_id}", doNothing, doNothing
-
+    @sendCommand "playid #{escape(track_id)}"
+


`zappa.app` argument order doesn't matter (closes #78)

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -122,7 +122,16 @@

 # Takes in a function and builds express/socket.io apps based on the rules
 # contained in it.
-zappa.app = (func,options={}) ->
+zappa.app = ->
+  for a in arguments
+    switch typeof a
+      when 'function'
+        func = a
+      when 'object'
+        options = a
+
+  options ?= {}
+
   context = {id: uuid.v4(), zappa, express}

   real_root = path.dirname(module.parent.filename)


Fixed #4

Fixed #4

--- views/navigation-bar.cjsx
+++ views/navigation-bar.cjsx
@@ -32,6 +32,7 @@
   psAddEventLogger 'did-fail-load'

 NavigationBar = React.createClass
+  canSetState: true
   getInitialState: ->
     navigateStatus: 'Loading'
   getIcon: ->
@@ -45,15 +46,18 @@
   onResize: (e) ->
     $('inner-page')?.style?.height = "#{window.innerHeight - 50}px"
     $('inner-page webview')?.style?.height = $('inner-page webview /deep/ object[is=browserplugin]')?.style?.height = "#{window.innerHeight - 50}px"
-  onStartedLoading: (e) ->
-    @setState
-      navigateStatus: 'Loading'
+  onStartedLoading: ->
+    if @canSetState and @state.navigateStatus isnt 'Loading'
+      @setState
+        navigateStatus: 'Loading'
   onStoppedLoading: ->
-    @setState
-      navigateStatus: 'OK'
+    if @canSetState and @state.navigateStatus isnt 'OK'
+      @setState
+        navigateStatus: 'OK'
   onFailedToLoad: ->
-    @setState
-      navigateStatus: 'Failed'
+    if @canSetState and @state.navigateStatus isnt 'Failed'
+      @setState
+        navigateStatus: 'Failed'
   componentDidMount: ->
     window.addEventListener 'resize', @onResize
     webview.addEventListener 'did-start-loading', @onStartedLoading
@@ -64,6 +68,10 @@
     webview.removeEventListener 'did-start-loading', @onStartedLoading
     webview.removeEventListener 'did-stop-loading', @onStoppedLoading
     webview.removeEventListener 'did-fail-load', @onFailedToLoad
+  componentWillUpdate: ->
+    @canSetState = false
+  componentDidUpdate: ->
+    @canSetState = true

   goBack: ->
     if webview.canGoBack()


Fix unmounting bootstrap slider

Fix unmounting bootstrap slider

--- assets/javascripts/react/components/bootstrap_slider.coffee
+++ assets/javascripts/react/components/bootstrap_slider.coffee
@@ -22,7 +22,7 @@
       .setAttribute 'max', nextProps.max + 100

   componentWillUnmount: ->
-    @state.slider.off 'change', @handleChange
+    @state.slider.destroy()

   componentDidMount: ->
     toolTip = if @props.toolTip then 'show' else 'hide'


fix(cli): convert code from syntax highlighter to lexical analyser

--- src/cli.coffee
+++ src/cli.coffee
@@ -1,7 +1,7 @@
 path = require 'path'
 fs = require 'fs-plus'
 optimist = require 'optimist'
-Highlights = require './highlights'
+Textlex = require './textlex'

 module.exports = ->
   cli = optimist.describe('h', 'Show this message').alias('h', 'help')
@@ -11,13 +11,13 @@
                 .describe('v', 'Output the version').alias('v', 'version').boolean('v')
                 .describe('f', 'File path to use for grammar detection when reading from stdin').alias('f', 'file-path').string('f')
   optimist.usage """
-    Usage: highlights [options] [file]
+    Usage: textlex [options] [file]

-    Output the syntax highlighted HTML for a file.
+    Lexically analyse text and output the tokens for each line in JSON format.

-    If no input file is specified then the text to highlight is read from standard in.
+    If no input file is specified then the text to analyse is read from standard in.

-    If no output file is specified then the HTML is written to standard out.
+    If no output file is specified then the JSON is written to standard out.
   """

   if cli.argv.help
@@ -41,7 +41,7 @@
       process.exit(1)
       return

-    html = new Highlights().highlightSync({filePath, scopeName: cli.argv.scope})
+    html = new Textlex().lexSync({filePath, scopeName: cli.argv.scope})
     if outputPath
       fs.writeFileSync(outputPath, html)
     else
@@ -53,7 +53,7 @@
     fileContents = ''
     process.stdin.on 'data', (chunk) -> fileContents += chunk.toString()
     process.stdin.on 'end', ->
-      html = new Highlights().highlightSync({filePath, fileContents, scopeName: cli.argv.scope})
+      html = new Textlex().lexSync({filePath, fileContents, scopeName: cli.argv.scope})
       if outputPath
         fs.writeFileSync(outputPath, html)
       else


Indentation.

Indentation.

--- src/cli.coffee
+++ src/cli.coffee
@@ -26,14 +26,14 @@
   process.exit 0

 opts =
-  browser:   false
+  browser:    false
   checkLeaks: false
-  compilers: []
-  globals:   []
-  host:      'localhost'
-  port:      8080
-  recursive: false
-  timeout:   2000
+  compilers:  []
+  globals:    []
+  host:       'localhost'
+  port:       8080
+  recursive:  false
+  timeout:    2000

 args = process.argv.slice 2


add request for fetching each page

add request for fetching each page

--- src/cli.coffee
+++ src/cli.coffee
@@ -1,5 +1,6 @@
 fs = require 'fs'
 path = require 'path'
+cheerio = require 'cheerio'
 commander = require 'commander-b'
 request = require './request'

@@ -30,6 +31,30 @@
       detailMonth: 1
       output: 'web'

+fetchForPage = (cookieStore, pageNo) ->
+  throw new Error("invalid pageNo: #{pageNo}") if pageNo < 0 or 6 < pageNo
+  request
+    jar: jar
+    url: 'https://my.jcb.co.jp/iss-pc/member/details_inquiry/detail.html'
+    qs:
+      detailMonth: pageNo
+      output: 'web'
+  .then (res) ->
+    $ = cheerio.load res.body
+    data = null
+    $('select option[selected=selected]').each ->
+      e = $ @
+      data =
+        label: e.text()
+        amount: $('.amount strong').text()
+    data
+
+delayedResolve = (value, delay) ->
+  new Promise (resolve) ->
+    setTimeout ->
+      resolve value
+    , delay
+
 fetch = ->
   # get cookie store
   jar = request.jar()
@@ -41,6 +66,20 @@
   .then ->
     console.log 'fetch cookie'
     fetchForCookie jar
+  .then ->
+    console.log 'fetch [0..6]'
+    [0..6].reduce (promise, i) ->
+      promise
+      .then (result) ->
+        console.log("fetch [#{i}]")
+        fetchForPage jar, i
+        .then ({ label, amount } = {}) ->
+          result[label] = amount if label?
+        .then ->
+          deleyedResolve result, 500
+    , Promise.resolve {}
+  .then (months) ->
+    console.log months
   .catch (e) ->
     console.error e


add form controls to interaction class

add form controls to interaction class

--- breeze/lightside/static/lightside/logic/Interactions.coffee
+++ breeze/lightside/static/lightside/logic/Interactions.coffee
@@ -31,6 +31,8 @@
 		$(document).on('click', '#activity-control-playlists', -> Breeze.Activities.selectPlaylist())
 		$(document).on('click', '#activity-control-play', -> Breeze.Activities.startPlaylist())
 		$(document).on('click', '#activity-control-stop', -> Breeze.Activities.stopPlaylist())
+		$(document).on('click', '#activity-add-edit-open', -> Breeze.Views.showAddEditForm())
+		$(document).on('click', '#activity-add-edit-close', -> Breeze.Views.hideAddEditForm())
 		return true

 	@displayPersonPrompt: (type, activity = {}) ->


Default metadata to empty hash

Default metadata to empty hash

--- src/package-manager.coffee
+++ src/package-manager.coffee
@@ -145,8 +145,8 @@
       return pack if pack = @getLoadedPackage(name)

       try
-        metadata = Package.loadMetadata(packagePath)
-        if metadata?.theme
+        metadata = Package.loadMetadata(packagePath) ? {}
+        if metadata.theme
           pack = new ThemePackage(packagePath, metadata)
         else
           pack = new Package(packagePath, metadata)