Refactor of BuildExpressionFromJavascriptObject

--- javascripts/lib/math/build_expression_from_javascript_object.coffee
+++ javascripts/lib/math/build_expression_from_javascript_object.coffee
@@ -17,31 +17,107 @@
         @exponentiation_builder = @opts.exponentiation_builder || components.exponentiation
         @blank_builder = @opts.blank_builder || components.blank
         @multiplication_builder = @opts.multiplication_builder || components.multiplication
+        @equals_builder = @opts.equals_builder || components.equals

-      proc_method = (object_to_convert)->
-        return @blank_builder.build() unless object_to_convert
-        if object_to_convert instanceof Array
-          @convertSubExpression(object_to_convert)
-        else
-          switch typeof(object_to_convert)
-            when "number" then @number_builder.build(value: object_to_convert)
-            when "string"
-              obj = object_to_convert
-              switch
-                when obj == "+" then @addition_builder.build()
-                when obj == "-" then @subtraction_builder.build()
-                when obj == "/" then @division_builder.build()
-                when obj == "*" then @multiplication_builder.build()
-                when @matchesNumberRegexp(obj)
-                  @numberFromString(obj)
-                else throw "STRING NOT IMPLEMENTED"
-            when "object" then @convertObject(object_to_convert)
-      process: logger().instrument(name: "Process", fn: proc_method)
+        @processor = _JSObjectExpressionProcessor.build()

+        @exponentiation_converter = _FromExponentiationObject.build(
+          @processor,
+          @exponentiation_builder)

-      matchesNumberRegexp: (str)->
-        str.search(/\d+/) != -1
+        @string_literal_converter = _FromStringLiteralObject.build(
+          "+": @addition_builder
+          "-": @subtraction_builder
+          "/": @division_builder
+          "*": @multiplication_builder
+          "=": @equals_builder
+        )
+
+        @closed_expression_converter = _FromClosedExpressionObject.build(
+          @expression_builder,
+          @processor)
+
+        @number_converter = _FromNumberObject.build(@number_builder)
+        @open_expression_converter = _FromOpenExpressionObject.build(@closed_expression_converter)
+
+        @processor.converters [
+          @closed_expression_converter
+          @open_expression_converter
+          @number_converter
+          @exponentiation_converter
+          @string_literal_converter
+          ]
+
+      process: (js_object)->
+        @processor.process(js_object)
+
+      processBuildExpression: (data)->
+        @process(data)
+
+    class_mixer BuildExpressionFromJavascriptObject
+
+    class _JSObjectExpressionProcessor
+      converters: (@js_object_converters)->
+
+      process: (js_object)->
+        for converter in @js_object_converters
+          if converter.isType(js_object)
+            return converter.convert(js_object)
+        throw "Unhandled js object: #{JSON.stringify js_object}"
+    class_mixer _JSObjectExpressionProcessor
+
+    class _FromOpenExpressionObject
+      initialize: (@expression_converter)->
+      isType: (js_object)->
+        js_object['open_expression'] != undefined
+
+      convert = (js_object)->
+        subexp = js_object['open_expression']
+        maybe_wrapped =
+          if typeof subexp == "number"
+            [subexp]
+          else if subexp == null || subexp == false
+            []
+          else if @isType(subexp) # this open expression contains another open expression
+            [subexp]
+          else subexp
+        @expression_converter.convert(maybe_wrapped).open()
+
+      convert: logger().instrument(name: "_FromOpenExpressionObject#convert", fn: convert)
+
+    class_mixer _FromOpenExpressionObject
+
+    class _FromClosedExpressionObject
+      initialize: (@expression_builder, @processor)->
+      isType: (js_object)->
+        typeof js_object == "object" && js_object instanceof Array
+
+      convert: (js_object)->
+        exp = @expression_builder.build()
+        for part in js_object
+          converted_part = @processor.process(part)
+          exp = exp.append(converted_part)
+        exp
+    class_mixer _FromClosedExpressionObject
+
+    class _FromNumberObject
+      initialize: (@number_builder)->
+
+      isType: (js_object)->
+        @isJSNumber(js_object) or @isStringNumber(js_object)
+
+      isJSNumber: (js_object)->
+        typeof js_object == "number"
+
+      isStringNumber: (js_object)->
+        typeof js_object == "string" and js_object.search(/\d+/) != -1
+
+      convert: (js_object)->
+        if @isJSNumber(js_object)
+          @number_builder.build(value: js_object)
+        else if @isStringNumber(js_object)
+          @numberFromString(js_object)

       numberFromString: (str)->
         if parsed = str.match /(\d+)(\.)(\d+)/
@@ -51,51 +127,47 @@
         else if parsed = str.match /(\d+)/
           @number_builder.build(value: parsed[1])

-      # privates
-      convertSubExpression: (parts) ->
-        exp = @expression_builder.build()
-        for x in parts
-          converted_part = @process(x)
-          exp = exp.append(converted_part)
-        exp
+    class_mixer _FromNumberObject

-      convertObject: (object)->
-        if (it = object['^'])
-          @convertExponentiation(it)
-        else if ((it = object['open_expression']) != undefined)
-          subexp = @convertImplicitSubexp(it)
-          subexp.open()
-        else
-          throw "Build Exp not recognized"
-
-      convertExponentiation: (data)->
-        base = @convertImplicitSubexp(data[0])
-        power = @convertImplicitSubexp(data[1])
+    class _FromExponentiationObject
+      initialize: (@processor, @exponentiation_builder)->
+      isType: (js_object)-> js_object['^'] instanceof Array
+      convert: (js_object)->
+        base = @convertImplicitSubexp(js_object['^'][0])
+        power = @convertImplicitSubexp(js_object['^'][1])

         @exponentiation_builder.build(
           base: base
           power: power
         )

-      convertImplicitSubexp = (subexp)->
-        processed = @process(subexp)
-        if typeof subexp == "number"
-          @expression_builder.build(expression: [processed])
-        else if subexp == null || subexp == false
-          @expression_builder.build(expression: [])
-        else if subexp instanceof Array
-          processed
-        else
-          @expression_builder.build(expression: [processed])
+      convertImplicitSubexp: (subexp)->
+        maybe_wrapped =
+          if typeof subexp == "number"
+            [subexp]
+          else if subexp == null || subexp == false
+            []
+          else
+            subexp
+        processed = @processor.process(maybe_wrapped)
+    class_mixer _FromExponentiationObject

-      convertImplicitSubexp: logger().instrument(name: "convertImplicitSubexp", fn: convertImplicitSubexp)
+    class _FromStringLiteralObject
+      initialize: (@literal_mappings)->
+        @keys = _.keys(@literal_mappings)

-    class_mixer BuildExpressionFromJavascriptObject
+      isType: (js_object)->
+        @keys.indexOf(js_object) != -1
+
+      convert: (js_object)->
+        @literal_mappings[js_object].build()
+
+    class_mixer _FromStringLiteralObject

     BuildExpressionFromJavascriptObject.buildExpression = ->
       builder = BuildExpressionFromJavascriptObject.build()
       arguments_as_array = Array.prototype.slice.call(arguments, 0)
-      converted_part = builder.process(arguments_as_array)
+      converted_part = builder.processBuildExpression(arguments_as_array)
       logger().info("returned converted from process in buildExpression", converted_part.toString(), arguments_as_array)
       converted_part


Fix test.

Fix test.

--- spec/snippet-loading-spec.coffee
+++ spec/snippet-loading-spec.coffee
@@ -233,7 +233,8 @@
         allSnippets = snippetsService.getUnparsedSnippets()
         scopedSnippet = allSnippets.find (s) ->
           s.selectorString is '.package-with-snippets-unique-scope'
-        expect(scopedSnippet).toNotBe undefined
+        expect(scopedSnippet).not.toBe undefined
+        originalConfig = atom.config.get('core.packagesWithSnippetsDisabled')

     it "never loads a package's snippets when that package is disabled in config", ->
       originalConfig = atom.config.get('core.packagesWithSnippetsDisabled')


Match anything and call home#index

Match anything and call home#index

--- app/routes.coffee
+++ app/routes.coffee
@@ -1,5 +1,2 @@
 module.exports = (match) ->
-  match '', 'home#index'
-  match 'index.html', 'home#index'
-  match 'u/6045251/shiny-wight/index.html', 'home#index'
-  match 'shiny-wight/index.html', 'home#index'
+  match '*splat', 'home#index'


Rename _pipedVm -> _pipedVmName

Rename _pipedVm -> _pipedVmName

--- client/landing/app/MainApp/filetree/controllers/findercontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findercontroller.coffee
@@ -121,7 +121,7 @@
     [vmName, path] = vm.split ":"

     vmRoots = (@appStorage.getValue 'vmRoots') or {}
-    pipedVm = @_pipedVm vmName
+    pipedVm = @_pipedVmName vmName
     path or= vmRoots[pipedVm] or "/home/#{KD.nick()}"

     if vmItem = @getVmNode vmName
@@ -172,7 +172,7 @@
     callback?()

     vmRoots = (@appStorage.getValue 'vmRoots') or {}
-    pipedVm = @_pipedVm vmName
+    pipedVm = @_pipedVmName vmName
     vmRoots[pipedVm] = path
     @appStorage.setValue 'vmRoots', vmRoots

@@ -215,11 +215,11 @@
         , yes

   isNodesHiddenFor:(vmName)->
-    pipedVm = @_pipedVm vmName
+    pipedVm = @_pipedVmName vmName
     return (@appStorage.getValue('vmsDotFileChoices') or {})[pipedVm]

   setNodesHidden:(vmName, state)->
-    pipedVm = @_pipedVm vmName
+    pipedVm = @_pipedVmName vmName
     prefs   = @appStorage.getValue('vmsDotFileChoices') or {}
     prefs[pipedVm] = state
     @appStorage.setValue 'vmsDotFileChoices', prefs
@@ -262,7 +262,7 @@
         folder.indexOf "[#{vmName}]" is 0
     iterate recentFolders, 0

-  _pipedVm:(vmName)-> vmName.replace /\./g, '|'
+  _pipedVmName:(vmName)-> vmName.replace /\./g, '|'

 class VMMountStateWidget extends JView


Dust burst out immediately on spawn

Dust burst out immediately on spawn

--- echoes/midground/dust/main.coffee
+++ echoes/midground/dust/main.coffee
@@ -46,6 +46,8 @@

     @add @particles

+    @onBeat duration: 1
+
   onBeat: (beat) ->
     targetScale = if @direction > 0 then 1.5 else 0.75


Setting heatmap max value of 3

Setting heatmap max value of 3

--- public/scripts/views/SheepHeatMapView.coffee
+++ public/scripts/views/SheepHeatMapView.coffee
@@ -47,7 +47,7 @@
   observations are added to it, add these to the HeatLayer.
   ###
   createHeatMap: (sheep) ->
-    heatmap = L.heatLayer([])
+    heatmap = L.heatLayer([], max: 3)
     heatmap.getBounds =-> new L.LatLngBounds heatmap._latlngs

     sheep.on 'add', (obs) ->


Teambuilder: Fixed hidden power for existing teams

--- client/app/js/models/team.coffee
+++ client/app/js/models/team.coffee
@@ -13,6 +13,7 @@
   initialize: (attrs={}, options={}) =>
     @owner = attrs.owner
     @set('generation', DEFAULT_GENERATION)  unless attrs.generation
+    @set('teambuilder', true)  if options.teambuilder
     @pokemon = new PokemonCollection(attrs.pokemon, team: this)
     @models = @pokemon.models
     @length = @pokemon.length


client: fix reference error

client: fix reference error

--- client/app/lib/appstorage.coffee
+++ client/app/lib/appstorage.coffee
@@ -62,7 +62,7 @@
     appId = @_applicationID
     @fetchStorage (storage) =>
       @storage = storage
-      value = getValue key, group
+      value = @getValue key, group

       callback? value ? null
     , force


- Ignore this

- Ignore this

--- client/landing/app/Applications/Activity.kdapplication/widgets/codesnippetwidget.coffee
+++ client/landing/app/Applications/Activity.kdapplication/widgets/codesnippetwidget.coffee
@@ -167,7 +167,6 @@
       @ace.setTheme()
       @ace.setSyntax "javascript"
       @ace.editor.getSession().on 'change', => @refreshEditorView()
-      @once @updateSyntaxTag 'javascript'
       @emit "codeSnip.aceLoaded"

   refreshEditorView:->


Use Token as the token header key

Use Token as the token header key

--- app/assets/javascripts/auth.coffee
+++ app/assets/javascripts/auth.coffee
@@ -13,7 +13,7 @@
   tokenKey: 'access_token'
   tokenIdKey: 'user_id'
   tokenLocation: 'authHeader'
-  tokenHeaderKey: 'AUTH-TOKEN'
+  tokenHeaderKey: 'Token'

   signInEndPoint: Dashboard.ApplicationAdapter.create().buildURL('sessions')
   signOutEndPoint: Dashboard.ApplicationAdapter.create().buildURL('sessions')


social: log group creation errors

social: log group creation errors

--- servers/lib/server/handlers/createteam.coffee
+++ servers/lib/server/handlers/createteam.coffee
@@ -74,7 +74,9 @@
         allowedDomains  : convertToArray domains # clear & convert domains into array
       , owner, (err, group) ->

-        return res.status(500).send "Couldn't create the group."  if err or not group
+        if err or not group
+          console.error 'Error while creating the group', err
+          return res.status(500).send "Couldn't create the group."

         queue = [
           # add other parallel operations here


Removed some redundant null declarations

--- app/client/game/result.coffee
+++ app/client/game/result.coffee
@@ -2,7 +2,6 @@

 # methods

-# get the current player's role
 currentPlayerRole = ->
   if currentPlayerId() is currentChallenge().challengerId
     'challenger'
@@ -11,7 +10,7 @@

 winnerRole = ->
   challenge = currentChallenge()
-  return '' unless Games.findOne(challenge.challengeeGameId).state is 'finished'
+  return unless Games.findOne(challenge.challengeeGameId).state is 'finished'

   challengeeHighscore = Highscores.findOne
     gameId: challenge.challengeeGameId
@@ -24,6 +23,7 @@
     'challenger'
   else
     'tie'
+

 # helpers

@@ -39,11 +39,11 @@

 Template.challenge.helpers
   opponent: ->
-    opponent = null
     if currentPlayerRole() is 'challengee'
       opponent = Meteor.users.findOne currentChallenge().challengerId
     else
       opponent = Meteor.users.findOne currentChallenge().challengeeId
+
     opponent.username

   answered: ->
@@ -59,8 +59,6 @@
     Games.findOne(currentChallenge().challengeeGameId).state is 'declined'

   result: ->
-    highscore = null
-
     if currentPlayerRole() is 'challenger'
       highscore = Highscores.findOne
         gameId: currentChallenge().challengeeGameId
@@ -76,6 +74,7 @@
   isWinner: ->
     winner = winnerRole()
     return unless winner
+
     if winner is 'tie'
       "alert alert-warning"
     else if winner is currentPlayerRole()
@@ -86,6 +85,7 @@
   winner: ->
     winner = winnerRole()
     return unless winner
+
     if winner is 'tie'
       "Wow, der ble uafgjort!"
     else if winner is currentPlayerRole()


"Fixed markup for the thumbnails"

"Fixed markup for the thumbnails"

--- assets/lib/plunker.coffee
+++ assets/lib/plunker.coffee
@@ -1,7 +1,8 @@

 addThumbnail = (plunk) ->
-  $li = $("

").addClass("span3").addClass("plunk").addClass("thumbnail")
-  $a = $("").attr("href", plunk.url).appendTo($li)
+  $li = $("

").addClass("span3").addClass("plunk")
+  $div = $("

").addClass("thumbnail").appendTo($li)
+  $a = $("").attr("href", plunk.url).appendTo($div)
   $img = $("")
     .attr("src", "http://placehold.it/205x154&text=Loading...")
     .attr("data-original", "http://immediatenet.com/t/l3?Size=1024x768&URL=#{plunk.url}")
@@ -10,7 +11,7 @@
     .appendTo($a)
   $caption = $("

")
     .addClass("caption")
-    .appendTo($li)
+    .appendTo($div)
   $description = $("
#{plunk.description or 'Untitled'}
")
     .attr("title", plunk.description or "Untitled")
     .addClass("description")
@@ -118,7 +119,7 @@
       json =
         description: gist.description or ""
         source:
-          name: "Github"
+          name: "gist: #{gist.id}"
           url: gist.html_url
         author:
           name: gist.user.login


Force pin color change after confirmation for real this time

--- app/assets/javascripts/main.coffee
+++ app/assets/javascripts/main.coffee
@@ -279,10 +279,13 @@
         self = this
         query.done () ->
             for k,v of self._locations
+                setPinProp = false
                 for l,j of v.businesses
                     if j.id == id
                         j.confirmed_location = true
-                        j.needToCreatePin = true
+                        setPinProp = true
+                if setPinProp
+                    j.needToCreatePin = true
             self._infoWindow.close()
             self._createMarkersForBusinesses()


No perens needed

No perens needed

--- app/assets/javascripts/peek.coffee
+++ app/assets/javascripts/peek.coffee
@@ -54,7 +54,7 @@
 # Fire the event for our own listeners.
 $(document).on 'pjax:end', (event, xhr, options) ->
   if xhr?
-    requestId = xhr.getResponseHeader('X-Request-Id')
+    requestId = xhr.getResponseHeader 'X-Request-Id'

   if peekEnabled()
     $(this).trigger 'peek:update'


Move collection event handlers to collectionEvents hash

--- src/coffee/cilantro/ui/values.coffee
+++ src/coffee/cilantro/ui/values.coffee
@@ -19,6 +19,8 @@
         template: templates.list

         collectionEvents:
+            'add': 'reloadText'
+            'remove': 'reloadText'
             'reset': 'clearText'

         ui:
@@ -30,11 +32,6 @@

         initialize: ->
             @_parseText = _.debounce(@parseText, @inputDelay)
-
-            @collection.on 'add', =>
-                @reloadText()
-            @collection.on 'remove', =>
-                @reloadText()

         clear: (event) ->
             event?.preventDefault()


Add TODO

Add TODO

--- src/coffee/export/orderexport.coffee
+++ src/coffee/export/orderexport.coffee
@@ -134,6 +134,7 @@

   _orderToXML: (order, orderXML, mappings) =>
     @logger.debug "[OrderExport] Processing order with id: '#{order.id}'"
+    # TODO use orderNumber for export and for order status synchronization (not order UUID)
     orderXML.e('OrderId').t(order.id)
     orderXML.e('OrderDate').t(order.createdAt)
     #<xs:element ref="OrderStatus" minOccurs="0"/>


fix(categoryOrderHints): don't send an action if there is no category order hint provided

--- src/coffee/sync/utils/product.coffee
+++ src/coffee/sync/utils/product.coffee
@@ -93,6 +93,8 @@
     _.each actionsBaseList(), (item) =>
       action = @_buildBaseAttributesAction(item, diff, old_obj)
       if action && action.action == "setCategoryOrderHint"
+        if _.isUndefined action.categoryOrderHints
+          return
         action.categoryId = Object.keys(action.categoryOrderHints)[0]
         action.orderHint = action.categoryOrderHints[action.categoryId]
       actions.push action if action


fix flicker frames not changing on play

fix flicker frames not changing on play

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -512,7 +512,7 @@
     @el.attr 'data-on-frame', @currFrameIdx

   showFrame: (frame_idx) ->
-    @el.find("#frame-id-#{frame_idx}").hide() for i in [0...4]
+    @el.find("#frame-id-#{i}").hide() for i in [0...4]
     @el.find("#frame-id-#{frame_idx}").show()
     @el.find("#frame-slider").val frame_idx
     @setCurrentFrameIdx(frame_idx)


Switch to kdwarf-2 group

Switch to kdwarf-2 group

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -28,7 +28,8 @@
 K2_4_SUBJECT_GROUP = "5628a593eaad4a0122000001"
 KDWARF_1_SUBJECT_GROUP = "566e95bc7af859004e000001"
 KDWARF_1_SIMULATION_GROUP = "566ecd4edeb24f0539000001"
-MAIN_SUBJECT_GROUP = KDWARF_1_SUBJECT_GROUP
+KDWARF_2_SUBJECT_GROUP = "5756cc44c832d90038000001"
+MAIN_SUBJECT_GROUP = KDWARF_2_SUBJECT_GROUP
 SIMULATION_GROUP   = KDWARF_1_SIMULATION_GROUP

 USERS_OPT_IN = ['a', 'b', 'c', 'g', 'h', 'i']


Handle parser error

Handle parser error

--- src/likes.coffee
+++ src/likes.coffee
@@ -12,6 +12,9 @@

   http.get url, (res) ->
     res.pipe parser
+
+  parser.on 'error', (er) ->
+    cb er

   parser.on 'entry', (article) ->
     articles.push article


Update contact-page.cjsx

Update contact-page.cjsx

Additional line breaks fixed so it's all same format.
(Can't wait for Alex to help me set my mac up so I do this via Emacs and not in Github directly. Whoohoo!)

--- app/pages/about/contact-page.cjsx
+++ app/pages/about/contact-page.cjsx
@@ -8,26 +8,15 @@
     content: '''
       ## Contact & Social Media

-      Most of the time, the best way to reach the Zooniverse team, or any project teams,
-      especially about any project-specific issues, is through the discussion boards.
+      Most of the time, the best way to reach the Zooniverse team, or any project teams, especially about any project-specific issues, is through the discussion boards.

-      If you need to contact the Zooniverse team about a general matter, you can also
-      send an email to the team at [contact@zooniverse.org](mailto:contact@zooniverse.org). Please understand that the
-      Zooniverse team is relatively small and very busy, so unfortunately we cannot
-      reply to all of the emails we receive.
+      If you need to contact the Zooniverse team about a general matter, you can also send an email to the team at [contact@zooniverse.org](mailto:contact@zooniverse.org). Please understand that the Zooniverse team is relatively small and very busy, so unfortunately we cannot reply to all of the emails we receive.

-      If you are interested in collaborating with the Zooniverse, for instance on a
-      custom-built project, please email [collab@zooniverse.org](mailto:collab@zooniverse.org)
-      (Note that our [Project Builder](#/lab)
-      offers an effective way to set up a new project without needing to contact the team!)
+      If you are interested in collaborating with the Zooniverse, for instance on a custom-built project, please email [collab@zooniverse.org](mailto:collab@zooniverse.org). (Note that our [Project Builder](#/lab) offers an effective way to set up a new project without needing to contact the team!)

-      For press inquires, please contact the Zooniverse directors Chris Lintott at
-      [chris@zooniverse.org](mailto:chris@zooniverse.org) or +44 (0) 7808 167288 or
-      Laura Trouille at [trouille@zooniverse.org](mailto:trouille@zooniverse.org) or +1 312 322 0820.
+      For press inquires, please contact the Zooniverse directors Chris Lintott at [chris@zooniverse.org](mailto:chris@zooniverse.org) or +44 (0) 7808 167288 or Laura Trouille at [trouille@zooniverse.org](mailto:trouille@zooniverse.org) or +1 312 322 0820.

-      If you want to keep up to date with what's going on across the Zooniverse and our
-      latest results, check out the [Daily Zooniverse](http://daily.zooniverse.org/) or the main [Zooniverse blog](http://blog.zooniverse.org/).
-      You can also follow the Zooniverse on [Twitter](http://twitter.com/the_zooniverse), [Facebook](http://facebook.com/therealzooniverse), and [Google+](https://plus.google.com/+ZooniverseOrgReal).
+      If you want to keep up to date with what's going on across the Zooniverse and our latest results, check out the [Daily Zooniverse](http://daily.zooniverse.org/) or the main [Zooniverse blog](http://blog.zooniverse.org/). You can also follow the Zooniverse on [Twitter](http://twitter.com/the_zooniverse), [Facebook](http://facebook.com/therealzooniverse), and [Google+](https://plus.google.com/+ZooniverseOrgReal).
     '''

 module.exports = React.createClass


Prevent window from displaying when just running tests

--- src/atom.coffee
+++ src/atom.coffee
@@ -84,6 +84,7 @@
       browserWindow.center()

   restoreDimensions: (defaultDimensions={width: 800, height: 600})->
+    return if @getLoadSettings().exitWhenDone
     dimensions = @getWindowState().getObject('dimensions')
     dimensions = defaultDimensions unless dimensions?.width and dimensions?.height
     @setDimensions(dimensions)


round trip encoding / decoding seems to work

--- src/base58.iced
+++ src/base58.iced
@@ -12,7 +12,7 @@
     if @alphabet.length isnt @base
       throw new Error "Encoder alphabet length must be 58 chars"
     @decode_map = {}
-    for a,i in @alphabet
+    for a,i in (new Buffer @alphabet, 'utf8')
       @decode_map[a] = i

   # encoder a buffer of binary data into a base58-string encoding
@@ -41,24 +41,32 @@
         out += Math.ceil(rem*8/@log58)
       out

-#=====================================================================
+  decode : (src) ->
+    src = new Buffer src, 'utf8'
+    bufs = while src.length
+      [dst,src] = @decode_block src
+      dst
+    Buffer.concat bufs

-class Foo
+  decode_block : (src) ->
+    res = nbv 0
+    consumed = 0
+    for c,src_p in src when (d = @decode_map[c])?
+      res = res.multiply(@base_big).add(nbv(d))
+      break if ++consumed is @out_block_len
+    res = new Buffer res.toByteArray()
+    padlen = @decoded_len(consumed) - res.length
+    pad = new Buffer (0 for i in [0...padlen])
+    [ Buffer.concat([pad, res]), src[(src_p+1)...] ]

-  decode: (str) ->
-    num = BigInteger.ZERO
-    base = BigInteger.ONE
-    i = 0
-    for c,i in str
-      break unless c is @alphabet[0]
-    start = i
-    pad = new Buffer (0 for i in [0...start])
-    for c,i in str[start...] by -1
-      unless (char_index = @lookup[c])?
-        throw new Error('Value passed is not a valid BaseX string.')
-      num = num.add base.multiply nbv char_index
-      base = base.multiply @basebn
-    Buffer.concat [pad, new Buffer(num.toByteArray()) ]
+  decoded_len : (n) ->
+    if n is @out_block_len then @in_block_len
+    else
+      nblocks = ~~(n / @out_block_len)
+      out = nblocks * @in_block_len
+      if (rem = n % @out_block_len) > 0
+        out += Math.floor(rem * @log58 / 8 )
+      out

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

@@ -67,4 +75,8 @@

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

-console.log std_encoding.encode new Buffer [0...300]+encoded = std_encoding.encode new Buffer [0...300]
+console.log encoded
+decoded = std_encoding.decode encoded
+console.log decoded
+console.log decoded.toString 'hex'


fix #222

fix #222


Fixed a bug with EDGE

Fixed a bug with EDGE

--- src/base/CUI.coffee
+++ src/base/CUI.coffee
@@ -877,7 +877,7 @@
 			ie: `/*@cc_on!@*/false || !!document.documentMode`
 			chrome: !!window.chrome and !!window.chrome.webstore
 		map.edge = not map.ie && !!window.StyleMedia
-		map.blink = (map.chrome or opera) && !!window.CSS
+		map.blink = (map.chrome or map.opera) && !!window.CSS
 		map
 	)()


Fix link typo in examples.coffee

Fix link typo in examples.coffee

--- src/examples.coffee
+++ src/examples.coffee
@@ -80,7 +80,7 @@

Thanks

This code is built on the great work of many other open-source contributers.

-
React from Facebook

+
React from Facebook

react-textarea-autosize by Audrey Popp

jQuery plugin Autosize by Jack Moore


Esthetic.

Esthetic.

--- src/fattable.coffee
+++ src/fattable.coffee
@@ -1,4 +1,4 @@
-"use strict";
+"use strict"

 cumsum = (arr)->
     cs = [ 0.0 ]
@@ -7,9 +7,6 @@
         s += x
         cs.push s
     cs
-
-isReady = false
-isReadyCallbacks = []

 bound = (x, m, M)->
     if (x < m) then m else if (x > M) then M else x
@@ -361,31 +358,32 @@
         supportedEvent = if @container.onwheel isnt undefined then "wheel" else if @container.onmousewheel isnt undefined then "mousewheel" else "DOMMouseScroll"

         getDelta = (->
-                    switch supportedEvent
-                        when "wheel"
-                            (evt)->
-                                switch evt.deltaMode
-                                    when evt.DOM_DELTA_LINE
-                                        deltaX = -50*evt.deltaX ? 0
-                                        deltaY = -50*evt.deltaY ? 0
-                                    when evt.DOM_DELTA_PIXEL
-                                        deltaX = -1*evt.deltaX ? 0
-                                        deltaY = -1*evt.deltaY ? 0
-                                [deltaX, deltaY]
-                        when "mousewheel"
-                            (evt)->
-                                deltaX = 0
-                                deltaY = 0
-                                deltaX = evt.wheelDeltaX ? 0
-                                deltaY = evt.wheelDeltaY ? evt.wheelDelta
-                                [deltaX, deltaY]
-                        when "DOMMouseScroll"
-                            (evt)->
-                                deltaX = 0
-                                deltaY = 0
-                                if evt.axis == evt.HORIZONTAL_AXI then deltaX = -50.0*evt.detail else deltaY = -50.0*evt.detail
-                                [deltaX, deltaY]
+            switch supportedEvent
+                when "wheel"
+                    (evt)->
+                        switch evt.deltaMode
+                            when evt.DOM_DELTA_LINE
+                                deltaX = -50*evt.deltaX ? 0
+                                deltaY = -50*evt.deltaY ? 0
+                            when evt.DOM_DELTA_PIXEL
+                                deltaX = -1*evt.deltaX ? 0
+                                deltaY = -1*evt.deltaY ? 0
+                        [deltaX, deltaY]
+                when "mousewheel"
+                    (evt)->
+                        deltaX = 0
+                        deltaY = 0
+                        deltaX = evt.wheelDeltaX ? 0
+                        deltaY = evt.wheelDeltaY ? evt.wheelDelta
+                        [deltaX, deltaY]
+                when "DOMMouseScroll"
+                    (evt)->
+                        deltaX = 0
+                        deltaY = 0
+                        if evt.axis == evt.HORIZONTAL_AXI then deltaX = -50.0*evt.detail else deltaY = -50.0*evt.detail
+                        [deltaX, deltaY]
         )()
+
         onMouseWheel = (evt)=>
             evt.preventDefault()
             [deltaX, deltaY] = getDelta evt


redirect session expired

redirect session expired

--- app/scripts/candidature/app.coffee
+++ app/scripts/candidature/app.coffee
@@ -10,7 +10,9 @@
     if( $rootScope.logout == Function)
       $rootScope.logout()

-    if($state.$urlRouter!=undefined && $state.$urlRouter.location.indexOf("candidature/")!=-1)
+    location = if $state.$urlRouter then $state.$urlRouter.location else if $state.router.urlRouter then $state.router.urlRouter.location else undefined
+
+    if(location.indexOf("candidature/")!=-1)
       setTimeout(() ->
         $state.go('candidature.account.login')
       , 200)


Add baseUrl Prefix to Extras

Add baseUrl Prefix to Extras

--- src/model.coffee
+++ src/model.coffee
@@ -166,7 +166,7 @@

       if _.isString config.detailUrl
         makeDetailUrl = (entry) ->
-          config.parseUrlPattern(entry, config.detailUrl)
+          config.parseUrlPattern(entry, "#{config.baseUrl}#{config.detailUrl}")
       else
         makeDetailUrl = (entry, listUrl=config.listUrl, baseUrl=config.baseUrl) ->
           if entry.id?
@@ -534,7 +534,7 @@
             if _.isFunction(val.url)
               options.url = val.url(data, config.listUrl, config.detailUrl)
             else
-              options.url = config.parseUrlPattern(data, val.url)
+              options.url = config.parseUrlPattern(data, "#{config.baseUrl}#{val.url}")

           call = $http _.extend(val, options), data
           call.then(success) if success?


smarter exports, bugfix on M(, subpattern)

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -239,8 +239,11 @@
 # Pattern matching utilities
 matchNode = (pattern, node, match) ->
   if pattern instanceof MatchCapture
-      match[pattern.name] = node
-      matchNode(pattern.subpattern, node, match) if pattern.subpattern?
+    match[pattern.name] = node
+    matchNode(pattern.subpattern, node, match) if pattern.subpattern
+
+  else if pattern instanceof AnyMatch
+    return yes

   else if pattern instanceof Base
     throw "match failed" unless node instanceof pattern.constructor
@@ -253,7 +256,9 @@
     for [p, e] in underscore.zip(pattern, node)
       matchNode(p, e, match)

-  # TODO: ok if node instanceof pattern
+  else if node instanceof pattern
+    return yes
+
   # TODO: `Several` for mapping pattern matching over array

   else
@@ -263,11 +268,11 @@
 class MatchCapture extends Base
   constructor: (@name, @subpattern) ->
   toString: -> "M(#{@name})"
-exports.M = M = (name) -> new MatchCapture(name)
+exports.M = M = (args...) -> new MatchCapture(args...)

 class AnyMatch extends Base
   toString: -> " any"
-exports.any = any = new AnyMatch
+exports.any = any = new AnyMatch()

 #### utilities

@@ -402,7 +407,7 @@
     # this is just Palantir specific
     prelude.push @makeCode '/// <reference path="../../libraries/libraries.d.ts" />\n\n'

-    # assuming AMD define
+    # AMD module define
     for node, node_i in @expressions
       node.match [
         new Call(mkVanillaID("define"), [new Value(new Arr(M("mLabels"))),
@@ -414,13 +419,29 @@
         ({mname, mLabels, mNames, bodyExprs}) =>
           mname.warn "named modules not supported; name is being ignored" if mname

-          requires = for [iport, param] in underscore.zip(mLabels, mNames)
-            "import #{param.name.compile o} = require(#{iport.compile o})"
-          bodyExprs.unshift new Literal requires.join ";\n"
-
-          # assuming no weirder control flow, and last line is what's exported
-          eport = bodyExprs.pop()
-          bodyExprs.push new Literal "export = #{eport.compile o}"
+          # imports
+          prelude.push @makeCode("\n")
+          for [iport, param] in underscore.zip(mLabels, mNames)
+            prelude = prelude.concat [
+              @makeCode("import "), param.compileToFragments(o),
+              @makeCode(" = require("), iport.compileNode(o), @makeCode(");\n")
+            ]
+          prelude.push @makeCode("\n")
+          prelude = flatten prelude
+
+          # exports
+          bodyExprs.push bodyExprs.pop().match [
+            M("eport", Value), ({eport}) =>
+              o.scope.parameter "export"  # suppress `var export`
+              new Assign(mkVanillaID("export"), eport)
+
+            M("klass", Class), ({klass}) =>
+              o.scope.parameter "export"  # suppress `var export`
+              [
+                klass
+                new Assign(mkVanillaID("export"), klass.variable)
+              ]
+          ]

           @expressions[node_i] = bodyExprs
       ]


is_truncatedの実装を、現在の開閉状態に依存しないようにした

--- app/js/project/task.js.coffee
+++ app/js/project/task.js.coffee
@@ -124,17 +124,10 @@
     else
       new_task.find('.name').html(short_task_name(org_name))

-    # 切り詰められるか判定するために、一旦閉じた状態にする
-    new_task.find('.name').removeClass('opened')
-
     if !is_trancated(new_task)
       init_open_marker(new_task)

     update_open_marker(new_task)
-
-    # 状態を元に戻す
-    if is_task_opened(new_task)
-      new_task.find('.name').addClass('opened')

     update_open_all_button() # after marker update

@@ -249,13 +242,30 @@
 is_task_opened = (elem) ->
   elem.find('.task_close').is(":visible")

+# 現在のタスク内容で、切り捨てが発生しているか？
+# 判定結果は、タスクの開閉状態に依存しない
+#
+# elemが画面内に表示されている必要がある
 is_trancated = (elem) ->
+  # 2行以上あれば必ず切り捨てられる
   name = elem.data('name')
   if limit_task_name_len(name) != name
     return true

-  name_elem = elem.find('.name')[0]
-  return name_elem.offsetWidth < name_elem.scrollWidth
+  # 1行の場合、切り詰められるか判定するために、一旦閉じた状態にする
+  name_elem = elem.find('.name')
+  opened = name_elem.hasClass('opened')
+
+  if opened
+    name_elem.removeClass('opened')
+
+  name_elem_raw = elem.find('.name')[0]
+  result = name_elem_raw.offsetWidth < name_elem_raw.scrollWidth
+
+  if opened
+    name_elem.addClass('opened')
+
+  result

 short_task_name = (name) ->
   link_url(html_escape(limit_task_name_len(name)))


Get headers the correct way

Get headers the correct way

--- app/message-controller.coffee
+++ app/message-controller.coffee
@@ -5,9 +5,9 @@
   constructor: ->

   send: (request, response) =>
-    arn = request.headers['X-SNS-ARN']
-    deviceId = request.headers['X-SNS-Device']
-    platformId = request.headers['X-SNS-Platform']
+    arn = request.header 'X-SNS-ARN'
+    deviceId = request.header 'X-SNS-Device'
+    platformId = request.header 'X-SNS-Platform'

     app = @_createApp arn, platformId
     @_addUser app, deviceId, (error, endpoint) =>


Add zh-TW to i18n

Add zh-TW to i18n

--- index.cjsx
+++ index.cjsx
@@ -9,7 +9,7 @@
 {Table, ProgressBar, Grid, Input, Col, Alert, Button, Divider} = ReactBootstrap
 {APPDATA_PATH, SERVER_HOSTNAME} = window
 window.i18n.prophet = new(require 'i18n-2')
-  locales: ['en-US', 'ja-JP', 'zh-CN']
+  locales: ['en-US', 'ja-JP', 'zh-CN', 'zh-TW']
   defaultLocale: 'zh-CN'
   directory: path.join(__dirname, 'assets', 'i18n')
   devMode: false


Made return format to return error when code is not 2xx

--- src/core/utilities/formatters.coffee
+++ src/core/utilities/formatters.coffee
@@ -17,7 +17,7 @@
 restify = require 'restify'

 module.exports = (env) ->
-
+
 	check = env.utilities.check
 	config = env.config

@@ -50,6 +50,8 @@
 					result.message = res.message
 					result.data = body if typeof body == 'object' && Object.keys(body).length
 				else
+					if res.statusCode < 200 or res.statusCode >= 300
+						result.status = 'error'
 					body = null if not body?
 					result.data = body
 				body = result
@@ -96,4 +98,4 @@
 		formatters: formatters
 		build: (e,r) -> buildReply e || r, buildJsend: true
 	}
-		+


fix bug

fix bug

--- views/index.cjsx
+++ views/index.cjsx
@@ -210,6 +210,7 @@
   saveLog: (type, log) ->
     fs.ensureDirSync(path.join(APPDATA_PATH, 'akashic-records', @nickNameId.toString(), type))
     if type is "attack"
+      date = new Date(log[0])
       year = date.getFullYear()
       month = date.getMonth() + 1
       if month < 10


Display Java stack trace on job failure.

--- src/ext/components/job-output.coffee
+++ src/ext/components/job-output.coffee
@@ -70,7 +70,10 @@
       _messages messages

     else if job.exception
-      _exception Flow.Failure _, new Flow.Error 'Job failure.', new Error job.exception
+      cause = new Error job.exception
+      if job.stacktrace
+        cause.stack = job.stacktrace
+      _exception Flow.Failure _, new Flow.Error 'Job failure.', cause

     _canView not isJobRunning job
     _canCancel isJobRunning job


add woff2 to fonts

add woff2 to fonts

--- app/templates/gulpfile.coffee
+++ app/templates/gulpfile.coffee
@@ -196,7 +196,7 @@
 #     $REV FONTS
 #*------------------------------------*/
 gulp.task "rev:fonts", () ->
-  files = ['eot', 'woff', 'ttf', 'svg'].map (curr) ->
+  files = ['eot', 'woff', 'woff2', 'ttf', 'svg'].map (curr) ->
     "#{conf.path.dev.fnt}/**/*#{curr}"

   gulp.src(files)


feat(factory) return object for CS factories

--- factory/templates/_factory.coffee
+++ factory/templates/_factory.coffee
@@ -7,15 +7,12 @@
  # @description

 ###
-class <%= upperCamel %>
-  @instance = undefined
-  @someValue = '<%= upperCamel %>'
-  constructor: ->
-    if @instance then @instance else @instance = @
-
-  @someMethod: ->
-    '<%= upperCamel %>'
-
 angular
   .module '<% if (parentModuleName) { %><%= parentModuleName %>.<% } %><%= moduleName %>'
-  .factory '<%= upperCamel %>', [<%= upperCamel %>]
+  .factory '<%= upperCamel %>', ->
+    <%= upperCamel %>Base = {}
+    <%= upperCamel %>Base.someValue = '<%= upperCamel %>'
+    <%= upperCamel %>Base.someMethod = ->
+      '<%= upperCamel %>'
+
+    <%= upperCamel %>Base


Fix typo

Fix typo

--- src/config/sprites.coffee
+++ src/config/sprites.coffee
@@ -6,7 +6,7 @@
   _LABEL: "sprites"
   NewFromTurtle: (world, args) ->
     world.authority = args
-    dict = {_LABEL: args.label(), _EXPORTS: SPRITE_EXPORTS }
+    dict = {_LABEL: args.label(), _EXPORTS: SPRITE_EXPORTS}
     child = world.add_child dict

   go: (world, args) ->


fixed ensure so it doesnt compute a cross product with right() on every call

--- src/data/pairtable.coffee
+++ src/data/pairtable.coffee
@@ -68,11 +68,12 @@

     canonicalMD = new data.Row newrSchema
     createcopy = () -> [canonicalMD.clone()]
-    #rights = for p in @partition sharedCols
-    ldistinct = @left().melt().project(mapping, no).distinct()
-    right = ldistinct.cross(@right(), 'outer', null, createcopy)
+    nrows = right.nrows()
+    rights = for p in (new data.PairTable(left.project(mapping, no).distinct(), right)).partition(sharedCols)
+      p.left().cross(p.right(), 'outer', null, createcopy)

-    #right = new data.ops.Union rights
+    right = new data.ops.Union rights
+    console.log "pairtable.ensure [#{sharedCols}] [#{restCols}] right #{nrows} -> #{right.nrows()}"
     new data.PairTable left, right


only assign open auctions to a rail

only assign open auctions to a rail

--- apps/artwork/artwork_rails.coffee
+++ apps/artwork/artwork_rails.coffee
@@ -70,10 +70,8 @@
           success: (collection, response, options) =>
             collection.remove @artwork
             artworks = Artworks.fromSale collection
-            if @artwork.related.auction_state is 'closed'
+            if @artwork.related.auction_state is 'open'
               @assignRail 'closed_auction_artworks', artworks.toJSON()
-            else
-              @assignRail 'current_auction_artworks', artworks.toJSON()
             resolve()
       else
         resolve()


sidebar/view: merge compute & sidebar props together

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/app/lib/sidebar/view.coffee
+++ client/app/lib/sidebar/view.coffee
@@ -30,7 +30,7 @@

     sharedResources = calculateSharedResources props

-    return { ownedResources, sharedResources }
+    return Object.assign {}, props, { ownedResources, sharedResources }
 })

 ConnectedContainer = computeConnector sidebarConnector Container


docShell: change description to be clearer

'rendered document' -> 'formatted document'

--- coffee/src/shells/doc.shell.coffee
+++ coffee/src/shells/doc.shell.coffee
@@ -9,7 +9,7 @@

   id: 'acorn.DocShell'
   title: 'Doc'
-  description: 'a rendered document'
+  description: 'a formatted document'
   icon: 'icon-align-justify'


only set matching info on first load

only set matching info on first load

--- app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee
+++ app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee
@@ -62,10 +62,12 @@
     else
       "show_more"
   ).property('commonNames')
-  matchedOnSelf: ( ->
-    return true if @get('controllers.search.taxonConceptQueryRe') == null
-    @get('controllers.search.taxonConceptQueryRe').test(@get('fullName'))
-  ).property('controllers.search.taxonConceptQueryRe')
+  contentObserver: ( ->
+    matchedOnSelf = true
+    unless @get('controllers.search.taxonConceptQueryRe') == null
+      matchedOnSelf = @get('controllers.search.taxonConceptQueryRe').test(@get('fullName'))
+    @set('matchedOnSelf', matchedOnSelf)
+  ).observes('content.didLoad')
   matchedOnSynonym: ( ->
     if @get('synonyms') == undefined || @get('matchedOnSelf') || @get('controllers.search.taxonConceptQueryRe') == null
       return null


Remove console.log.

Remove console.log.

--- src/coffee/stockxmlimport.coffee
+++ src/coffee/stockxmlimport.coffee
@@ -26,7 +26,6 @@
       console.log 'elasticio CSV mode'
       queryString = 'where=' + encodeURIComponent("sku=\"#{msg.body.SKU}\"")
       @initMatcher(queryString).then (existingEntry) =>
-        console.log "Query for sku '#{msg.body.SKU}' result: %j", existingEntry
         if msg.body.CHANNEL_KEY
           @ensureChannelByKey(@rest, msg.body.CHANNEL_KEY, CHANNEL_ROLES)
           .then (channel) =>


unecessary variable removed

unecessary variable removed

--- app/assets/javascripts/controllers/security_proxy_controller.js.coffee
+++ app/assets/javascripts/controllers/security_proxy_controller.js.coffee
@@ -9,6 +9,5 @@

 ### Security Proxy ###
 App.SecurityProxyController = App.EditDeleteContentController.extend
-  visibilities: ['unpublished', 'published']
   contentType: 'security_proxy'
   indexRoute: 'security_proxies'


Rewrote the removal of the 'load:iframe' event handler.

3rd party content does not notify the Set Top Box that it has loaded via postMessage, so the event listener for the 'load:iframe' event was not getting removed which then caused the handler to double fire on the next program that *did* fire the event.

--- app/assets/javascripts/network_executive/components/set_top_box.coffee
+++ app/assets/javascripts/network_executive/components/set_top_box.coffee
@@ -23,6 +23,8 @@

   establishUplink : ->
     @uplink = new EventSource( "tune_in/#{@channel}" )
+
+    @uplink.addEventListener 'message', @purgeOnIframeLoad, false

     @uplink.addEventListener 'open',    @onUplinkUp,      false
     @uplink.addEventListener 'message', @onUplinkMessage, false
@@ -71,11 +73,16 @@

       e.detail.source.postMessage payload.onLoad, '*'

-      win.removeEventListener 'load:iframe', onIframeLoad
+    @onIframeLoad = onIframeLoad

     win.addEventListener 'load:iframe', onIframeLoad, false

     @goTo payload.url

   onProgramUpdate : (payload) ->
-    @program.postMessage payload, '*'+    @program.postMessage payload, '*'
+
+  purgeOnIframeLoad : (e) =>
+    win.removeEventListener 'load:iframe', @onIframeLoad, false
+
+    @onIframeLoad = null


RetencionFormView now supports ventas

RetencionFormView now supports ventas

--- app/assets/javascripts/views/retenciones/retencion_form_view.js.coffee
+++ app/assets/javascripts/views/retenciones/retencion_form_view.js.coffee
@@ -1,14 +1,23 @@
 Bandango.RetencionFormView = Bandango.ModelBackedView.extend Bandango.RetencionFuenteOnFormMixin,
   tagName: "div"
   templateName: "retenciones/form"
-  compraBinding: "controller.model"
+  controllerModelBinding: "controller.model"
   attributes: [ "numeroAutorizacion",
                 "numeroSerieEstablecimiento",
                 "numeroSeriePuntoEmision",
                 "numeroSerieSecuencial",
                 "fechaEmision",
                 "conceptoRetencionFuente",
-                "compra" ]
+                "compra",
+                "venta" ]
+
+  compra: (->
+    @get("controllerModel") unless @get("controllerModel.isVenta")
+  ).property("controllerModel")
+
+  venta: (->
+    @get("controllerModel") if @get("controllerModel.isVenta")
+  ).property("controllerModel")

   newConceptoRetencion: (conceptoRetencionFuente) ->
     @_super conceptoRetencionFuente


updating reading plan to interact with select topics modal

--- src/components/plan/reading.cjsx
+++ src/components/plan/reading.cjsx
@@ -1,15 +1,86 @@
 React = require 'react'
+_ = require 'underscore'
 BS = require 'react-bootstrap'
 Router = require 'react-router'
 Datepicker = (require 'react-widgets').DateTimePicker

 {TaskPlanStore, TaskPlanActions} = require '../../flux/task-plan'

-SelectReadings = React.createClass
+SectionTopic = React.createClass
+  toggleSection:->
+    @props.toggleSection(@props.section)
+
+  render: ->
+    isActive = 'info' if @props.active
+    <BS.ListGroupItem
+      key={@props.section.id}
+      bsStyle= {isActive}
+      onClick={@toggleSection}>{@props.section.number}. {@props.section.title}</BS.ListGroupItem>
+
+SelectTopics = React.createClass
   mixins: [BS.OverlayMixin],
-  getInitialState: -> {
-    isModalOpen: false
-  }
+  getInitialState: -> { isModalOpen: false }
+
+  getInitialState: ->
+    {
+      chapters: [
+        {
+          title: "Kinematics",
+          number: "1",
+          id: 123,
+          children: [{
+            title: "Kinematics in 1 dim",
+            number: "1.1",
+            id: 234
+          }, {
+            title: "Kinematics in 2 dim",
+            number: "1.2",
+            id: 235
+          }, {
+            title: "Kinematics in 3 dim",
+            number: "1.3",
+            id: 236
+          }],
+        },
+        {
+          title: "Mechanics",
+          number: "2",
+          id: 124,
+          children: [{
+            title: "Mechanics in 1 dim",
+            number: "2.1",
+            id: 237
+          }, {
+            title: "Mechanics in 2 dim",
+            number: "2.2",
+            id: 238
+          }, {
+            title: "Mechanics in 3 dim",
+            number: "2.3",
+            id: 239
+          }],
+
+        },
+        {
+          title: "Thermodynamics",
+          number: "3",
+          id: 125,
+          children: [{
+            title: "Thermodynamics in 1 dim",
+            number: "3.1",
+            id: 240
+          }, {
+            title: "Thermodynamics in 2 dim",
+            number: "3.2",
+            id: 241
+          }, {
+            title: "Thermodynamics in 3 dim",
+            number: "3.3",
+            id: 242
+          }]
+        }
+      ]
+    }

   handleToggle: ->
     @setState({
@@ -22,19 +93,37 @@
   render: ->
     <BS.Button onClick={@handleToggle} bsStyle="primary">Edit Readings</BS.Button>

+  toggleSection: (section) ->
+    if (TaskPlanStore.hasTopic(@props.planId, section.id))
+      TaskPlanActions.removeTopic(@props.planId, section.id)
+    else
+      TaskPlanActions.addTopic(@props.planId, section.id)
+
+  renderSections: (section) ->
+    active = TaskPlanStore.hasTopic(@props.planId, section.id)
+    <SectionTopic active={active} section={section} toggleSection={@toggleSection}/>
+
+  renderChapterPanels: (chapter, i) ->
+    sections = _.map(chapter.children, _.bind(@renderSections, this))
+    header =
{chapter.number}. {chapter.title}

+
+    <BS.Panel key={chapter.id} header={header} eventKey={chapter.id}>
+      <BS.ListGroup>
+        {sections}
+      </BS.ListGroup>
+    </BS.Panel>
+
   renderOverlay: ->
     if !@state.isModalOpen
       return
+
+    chapters = _.map(@state.chapters, _.bind(@renderChapterPanels, this))

     <BS.Modal backdrop={true} onRequestHide=@doneWithSelection>

-

-
List

-
of

-
chapters

-
and

-
sections

-

+        <BS.Accordion>
+          {chapters}
+        </BS.Accordion>

         <BS.Button onClick={@handleToggle}>Close</BS.Button>
@@ -45,29 +134,39 @@
   mixins: [Router.State]

   getInitialState: ->
-    {id: @getParams().id}
+    if (@getParams().id)
+      return {id: @getParams().id}
+    else
+      TaskPlanActions.create()
+      return {id: TaskPlanStore.getCreateKey()}

-  componentWillMount: ->
-    # Fetch the task if it has not been loaded yet
-    TaskPlanStore.addChangeListener(@update)
-
-  componentWillUnmount: ->
-    TaskPlanStore.removeChangeListener(@update)
+  componentWillMount: -> TaskPlanStore.addChangeListener(@update)
+  componentWillUnmount: -> TaskPlanStore.removeChangeListener(@update)

   update: ->
-    @setState({})
+    @setState({
+      id: @state.id,
+      topics: TaskPlanStore.getTopics(@state.id)
+    })

   setDueAt: (value) ->
     TaskPlanActions.updateDueAt(@state.id, value)

   setTitle: (value) ->
     TaskPlanActions.updateTitle(@state.id, value)
+
+  savePlan: ->
+    TaskPlanActions.save(@state.id)
+
+  renderTopics: (topic) ->
+
{topic}

   render: ->
     id = @getParams().id
     footer = <BS.Button bsStyle="primary">Publish</BS.Button>
     headerText = if id then 'Edit Reading' else 'Add Reading'
     dueDate = if @state.due_at then @state.due_at else @props.due_at
+    topics = TaskPlanStore.getTopics(@state.id)

     <BS.Panel bsStyle="default" className="create-reading" footer={footer}>

{headerText}

@@ -88,8 +187,11 @@

         Select Readings
-        <SelectReadings/>
+        <SelectTopics planId={@state.id} selected={topics}/>

+

+        {_.map(topics, @renderTopics)}
+

     </BS.Panel>

 module.exports = ReadingPlan


domain: WIP on purchases

domain: WIP on purchases

--- client/landing/app/Applications/Environments.kdapplication/views/domains/domainbuyform.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/domains/domainbuyform.coffee
@@ -12,7 +12,7 @@
                       .setClass 'domain-list'

     listView = @availableDomainsList.getListView()
-    listView.on 'BuyButtonClicked', (item)->
+    listView.on 'BuyButtonClicked', (item) =>
       {price, domain} = item.getData()
       year  =  item.yearBox.getValue()
       price = (year * price).toFixed 2
@@ -20,8 +20,13 @@
         domain      : domain
         confirmForm : new DomainBuyConfirmForm { domain, year, price }

-      modal.on 'PaymentConfirmed', (data) ->
-        data; debugger
+      modal.on 'PaymentConfirmed', ({ paymentMethodId }) =>
+        @buyDomain { domain, year, price, paymentMethodId }
+
+  buyDomain: (options) ->
+    { JPaymentCharge } = KD.remote.api
+
+    JPaymentCharge.charge options, -> debugger

   viewAppended:->
     tldList = []


Add timeout in attestation

Add timeout in attestation

--- app/src/controllers/onboarding/device/onboarding_device_connecting_view_controller.coffee
+++ app/src/controllers/onboarding/device/onboarding_device_connecting_view_controller.coffee
@@ -2,15 +2,16 @@

   defaultParams:
     animateIntro: no
-
   view:
     currentAction: "#current_action"
+  timer: null

   onAfterRender: ->
     super
-    do @_listenEvents
+    @_listenEvents()
     @view.spinner = ledger.spinners.createLargeSpinner(@select('div.greyed-container')[0])
     @view.currentAction.text(t 'onboarding.device.connecting.is_connecting')
+    @_launchAttestation()

   openSupport: ->
     window.open t 'application.support_url'
@@ -21,15 +22,8 @@
     ledger.app.off 'dongle:forged'
     ledger.app.off 'dongle:communication_error'

-  _hideContent: (hidden, animated = yes) ->
-    @view.contentContainer.children().each (index, node) =>
-      node = $(node)
-      if hidden == yes
-        node.fadeOut(if animated then 250 else 0)
-      else
-        node.fadeIn(if animated then 250 else 0)
-
-  navigateContinue: ->
+  _navigateContinue: ->
+    @_stopTimer()
     ledger.app.wallet?.isFirmwareUpdateAvailable (isAvailable) =>
       if isAvailable
         ledger.app.router.go '/onboarding/device/update'
@@ -40,7 +34,8 @@
           else
             ledger.app.router.go '/onboarding/management/welcome'

-  navigateError: ->
+  _navigateForged: ->
+    @_stopTimer()
     ledger.app.wallet?.isDongleBetaCertified (__, error) =>
       if error?
         ledger.app.router.go '/onboarding/device/forged'
@@ -50,11 +45,26 @@
             ledger.app.setExecutionMode(ledger.app.Modes.FirmwareUpdate)
             ledger.app.router.go '/update/index', {hidePreviousButton: yes}
           else
-            @navigateContinue()
+            @_navigateContinue()
+
+  _navigateError: ->
+    @_stopTimer()
+    ledger.app.router.go '/onboarding/device/failed'

   _listenEvents: ->
+    ledger.app.once 'dongle:connected', => @_navigateContinue()
+    ledger.app.once 'dongle:forged', => @_navigateForged()
+    ledger.app.once 'dongle:communication_error', => @_navigateError()
+
+  _stopTimer: ->
+    if @timer?
+      clearTimeout @timer
+      @timer = null
+
+  _launchAttestation: ->
     if ledger.app.wallet?
       ledger.app.performDongleAttestation()
-    ledger.app.once 'dongle:connected', => do @navigateContinue
-    ledger.app.once 'dongle:forged', => do @navigateError
-    ledger.app.once 'dongle:communication_error', => ledger.app.router.go '/onboarding/device/failed'+    @timer = setTimeout =>
+      # attestation timed out
+      @_navigateError()
+    , 30000


books list - left dropdown in

books list - left dropdown in

--- public/dreamcatcher/controllers/entries/newedit_entry_controller.coffee
+++ public/dreamcatcher/controllers/entries/newedit_entry_controller.coffee
@@ -101,7 +101,10 @@
     $('#books-list-button').removeClass('book bookSpine')
     if el.val() is 'new'
       $('input.newBook-input', el.parent()).val('').show().focus()
-      $('#books-list-button').hide()
+      $('#books-list-button').css {
+        'width': '28px'
+      }
+      $('.ui-selectmenu-status', el.parent()).hide()
     else
       $('input.newBook-input', el.parent()).hide()
       $('.ui-selectmenu-status', el.parent()).show()


Workspace: Minor code cleanup for chat pane.

--- client/landing/app/CommonViews/workspace/collaborativeworkspace.coffee
+++ client/landing/app/CommonViews/workspace/collaborativeworkspace.coffee
@@ -7,13 +7,11 @@
     @createLoader()
     @fetchUsers()
     @createUserListContainer()
-    @createChat()
+    @createChat()  if @getOptions().enableChat
     @bindRemoteEvents()

   createChat: ->
-    return unless @getOptions().enableChat
-    @container.addSubView @chatView = new ChatPane
-      delegate: this
+    @container.addSubView @chatView = new ChatPane delegate: this
     @chatView.hide()

   createRemoteInstance: ->


Fix https://github.com/atom/electron/issues/3565 by adding a typeof

--- atom/browser/lib/rpc-server.coffee
+++ atom/browser/lib/rpc-server.coffee
@@ -107,7 +107,7 @@
 # style function and the caller didn't pass a callback.
 callFunction = (event, func, caller, args) ->
   funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
-  funcPassedCallback = args[args.length - 1] is 'function'
+  funcPassedCallback = typeof args[args.length - 1] is 'function'

   try
     if funcMarkedAsync and not funcPassedCallback


Keep using protocol-relative urls

Keep using protocol-relative urls

--- src/hull.coffee
+++ src/hull.coffee
@@ -40,7 +40,7 @@
   # Fail right now if we don't have the required setup
   if config.orgUrl and config.appId
     # Auto add protocol if we dont have one of http://, https://, //
-    config.orgUrl ="https://#{config.orgUrl}" unless config.orgUrl.match(/^(http[s]?:)?\/\//)
+    config.orgUrl ="//#{config.orgUrl}" unless config.orgUrl.match(/^(http[s]?:)?\/\//)
     dfd.resolve()
   else
     dfd.reject(new Error "#{msg} We couldn't find `orgUrl` in the config object you passed to `Hull.init`\n #{readMore}") unless config.orgUrl


:racehorse: Avoid repeated array allocation in ::getDecorations

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -886,7 +886,7 @@
   getDecorations: (propertyFilter) ->
     allDecorations = []
     for markerId, decorations of @decorationsByMarkerId
-      allDecorations = allDecorations.concat(decorations) if decorations?
+      allDecorations.push(decorations...) if decorations?
     if propertyFilter?
       allDecorations = allDecorations.filter (decoration) ->
         for key, value of propertyFilter


Remove wrong comment

Remove wrong comment

--- src/foundation-player.dev.coffee
+++ src/foundation-player.dev.coffee
@@ -131,7 +131,6 @@
         @playPause() if @canPlayCurrent
     # Update Play/Pause
     updateButtonPlay: ->
-      # TODO: Refactor to switch/when
       @$play.toggleClass(@options.classPlayWait,
         !@canPlayCurrent && !@audioError)
       @$play.toggleClass(@options.classPlayPaused,


Adds some debugging, cleans up array slicing

--- src/hubot-untappd-friends.coffee
+++ src/hubot-untappd-friends.coffee
@@ -73,18 +73,22 @@
   # Check Errors
   checkUntappdErrors = (err, obj, msg) ->
     if err
+      robot.logger.error err
       msg.send err
       return false
     if obj.meta.error_detail
+      robot.logger.error obj
       msg.send "#{obj.meta.code}: #{obj.meta.error_detail}"
       return false
     true

   checkHTTPErrors = (err, res, body, msg) ->
     if err
+      robot.logger.error err
       msg.send err
       return false
     if res.statusCode != 200
+      robot.logger.error res
       obj = JSON.parse(body)
       msg.send "#{res.statusCode}: #{obj.meta.error_detail}"
       return false
@@ -95,6 +99,7 @@
   getFriendFeed = (msg) ->
     untappd.friendFeed (err, obj) ->
       return unless checkUntappdErrors err, obj, msg
+      robot.logger.debug obj.response.checkins
       for checkin in obj.response.checkins.items
         time_ago = moment(new Date(checkin.created_at)).fromNow()
         if checkin.venue.venue_name
@@ -109,9 +114,9 @@
     unless username
       msg.send 'Must provide a username to ask about.'
       return
-
     untappd.userFeed (err, obj) ->
       return unless checkUntappdErrors err, obj, msg
+      robot.logger.debug obj.response.checkins
       if err
         msg.send "Could not retrieve recent checkins for #{username}."
         return
@@ -129,21 +134,18 @@
     unless searchterm
       msg.send 'Must provide a brewery name to ask about.'
       return
-
-    count = count_to_return
     untappd.searchBrewery (err, obj) ->
       return unless checkUntappdErrors err, obj, msg
-
-      for result in obj.response.brewery.items
-        if count < 0
-          continue
+      robot.logger.debug obj.response.beers
+      if obj.response.brewery.items.length == 0
+        return msg.send "No breweries matched '#{searchterm}'"
+      for result in obj.response.brewery.items[0...count_to_return]
         out_msg = result.brewery.brewery_name
         if (result.brewery.location.brewery_city != "")
           out_msg += " ("+result.brewery.location.brewery_city + ", "+result.brewery.location.brewery_state+")"
         out_msg += " - " + result.brewery.beer_count + " beers (ID: #"+result.brewery.brewery_id+")"

         msg.send out_msg
-        count--
     , searchterm

   ##
@@ -152,21 +154,17 @@
     unless searchterm
       msg.send 'Must provide a beer name to ask about.'
       return
-
-    count = count_to_return
     untappd.searchBeer (err, obj) ->
       return unless checkUntappdErrors err, obj, msg
-
-      for result in obj.response.beers.items
-        if count < 0
-          continue
-
+      robot.logger.debug obj.response.beers
+      if obj.response.beers.items.length == 0
+        return msg.send "No beers matched '#{searchterm}'"
+      for result in obj.response.beers.items[0...count_to_return]
         if result.beer.beer_description
           msg.send "#{result.beer.beer_name} (#{result.beer.beer_style} - #{result.beer.beer_abv}%) by #{result.brewery.brewery_name} - #{result.beer.beer_description}"
         else
           msg.send "#{result.beer.beer_name} (#{result.beer.beer_style} - #{result.beer.beer_abv}%) by #{result.brewery.brewery_name}"

-        count--
     , searchterm

   ##
@@ -176,6 +174,7 @@
     msg.http(url)
       .get() (err, res, body) ->
         return unless checkHTTPErrors err, res, body, msg
+        robot.logger.debug body
         result = JSON.parse(body)
         msg.send "1) Add #{result.response.user.user_name} as a friend - #{result.response.user.untappd_url}\n2) Type `#{robot.name} untappd approve`"

@@ -186,8 +185,8 @@
     msg.http(url)
       .get() (err, res, body) ->
         return unless checkHTTPErrors err, res, body, msg
+        robot.logger.debug body
         result = JSON.parse(body)
-
         if result.response.items.length > 0
           friends = []
           for friend in result.response.items
@@ -201,7 +200,7 @@
   approveRequests = (msg) ->
     untappd.pendingFriends (err, obj) ->
       return unless checkUntappdErrors err, obj, msg
-
+      robot.logger.debug obj
       if obj.response.items.length > 0
         for result in obj.response.items
           untappd.acceptFriends (err, obj) ->


temp(streaming): Never consume changes to drafts

--- src/flux/inbox-api.coffee
+++ src/flux/inbox-api.coffee
@@ -195,6 +195,8 @@
     # For some reason, we occasionally get a delta with:
     # delta.object = 'message', delta.attributes.object = 'draft'
     if classname is "draft" or model?.object is "draft"
+      # TODO NEVER ACCEPT DRAFT CHANGES BECAUSE THE SERVER GETS DELETE HAPPY
+      return Promise.reject()
       Message = require './models/message'
       return @_shouldAcceptModelIfNewer(Message, model)


Remove Utils.nextTick() to fix tests.

Remove Utils.nextTick() to fix tests.

--- background_scripts/commands.coffee
+++ background_scripts/commands.coffee
@@ -114,23 +114,21 @@
           delete currentMapping[key][prop] for prop in ["keySequence", "description"]
     chrome.storage.local.set normalModeKeyStateMapping: keyStateMapping

-  # Build the "helpPageData" data structure which the help page needs and place it in Chrome storage.  We do
-  # this on the "nextTick" because there's not need for it to be done synchronously.
+  # Build the "helpPageData" data structure which the help page needs and place it in Chrome storage.
   prepareHelpPageData: ->
-    Utils.nextTick =>
-      commandToKey = {}
-      for own key, registryEntry of @keyToCommandRegistry
-        (commandToKey[registryEntry.command] ?= []).push key
-      commandGroups = {}
-      for own group, commands of @commandGroups
-        commandGroups[group] = []
-        for command in commands
-          commandGroups[group].push
-            command: command
-            description: @availableCommands[command].description
-            keys: commandToKey[command] ? []
-            advanced: command in @advancedCommands
-      chrome.storage.local.set helpPageData: commandGroups
+    commandToKey = {}
+    for own key, registryEntry of @keyToCommandRegistry
+      (commandToKey[registryEntry.command] ?= []).push key
+    commandGroups = {}
+    for own group, commands of @commandGroups
+      commandGroups[group] = []
+      for command in commands
+        commandGroups[group].push
+          command: command
+          description: @availableCommands[command].description
+          keys: commandToKey[command] ? []
+          advanced: command in @advancedCommands
+    chrome.storage.local.set helpPageData: commandGroups

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


Remove unneeded event handler

Remove unneeded event handler

--- src/hubot-perforce.coffee
+++ src/hubot-perforce.coffee
@@ -41,8 +41,8 @@
       else
         robot.emit 'perforce:change', change

-  robot.on 'perforce:change', (change) ->
-    robot.logger.warning "Perforce Change: #{inspect change}"
+  # robot.on 'perforce:change', (change) ->
+  #   robot.logger.warning "Perforce Change: #{inspect change}"

   p4 = new P4()
   p4.charset  = Options.charset


fixed typo variable name

fixed typo variable name

--- src/typetalk.coffee
+++ src/typetalk.coffee
@@ -76,10 +76,10 @@
                            headers:
                              'Authorization'         : "Bearer #{@accessToken}"
                              'User-Agent'            : "#{Package.name} v#{Package.version}"
-      conneted = false
+      connected = false

       ws.on 'open', () =>
-        conneted = true
+        connected = true
         setInterval =>
           ws.ping 'ping'
         , 1000 * 60 * 10


improved notification system #69

improved notification system #69

--- src/lib/background.coffee
+++ src/lib/background.coffee
@@ -412,9 +412,9 @@
       # Oops! Something went wrong so we should probably let the user know.
       runner.finish
         message: i18n.get if error instanceof URIError
-          'copy_fail_uri'
+          'result_bad_uri_description'
         else
-          'copy_fail_error'
+          'result_bad_error_description'
         success: no
   runner.pushPacked null, addAdditionalData, ->
     [tab, data, ->
@@ -466,13 +466,20 @@
       # Ensure that the user is notified if they have attempted to copy an
       # empty string to the system clipboard.
       if result.success and not result.contents
-        result.message = i18n.get 'copy_fail_empty'
+        result.message = i18n.get 'result_bad_empty_description',
+          result.template.title
         result.success = no
       if result.success
+        ext.notification.title       = i18n.get 'result_good_title'
+        ext.notification.titleStyle  = 'color: #050'
+        ext.notification.description = result.message ?
+          i18n.get 'result_good_description', result.template.title
         ext.copy result.contents
       else
-        ext.message = result.message
-        ext.status  = no
+        ext.notification.title       = i18n.get 'result_bad_title'
+        ext.notification.titleStyle  = 'color: #A00'
+        ext.notification.description = result.message ?
+          i18n.get 'result_bad_description', result.template.title
         showNotification()
       if result.template?
         updateTemplateUsage result.template.key
@@ -1216,19 +1223,22 @@
   # Public variables
   # ----------------

-  # Override message displayed in notifications.
-  # This should be reset to an empty string after every copy request.
-  message: ''
+  # Information specifying what should be displaying in the notification.
+  # This should be reset after every copy request.
+  notification:
+    description:      ''
+    descriptionStyle: ''
+    html:             ''
+    icon:             utils.url '../images/icon_48.png'
+    iconStyle:        ''
+    title:            ''
+    titleStyle:       ''

   # Pre-prepared HTML for the popup to be populated using.
   # This should be updated whenever templates are changed/updated in any way as
   # this is generated to improve performance and load times of the popup frame.
   popupHtml: ''

-  # Indicate whether or not the current copy request was a success.
-  # This should be reset to `false` after every copy request.
-  status: no
-
   # Local copy of templates being used, ordered to match that specified by the
   # user.
   templates: []
@@ -1243,13 +1253,10 @@
   # All successful copy requests should, at some point, call this function.
   # If `str` is empty the contents of the system clipboard will not change.
   copy: (str, hidden) ->
-    result  = no
     sandbox = $('#sandbox').val(str).select()
-    result  = document.execCommand 'copy'
+    document.execCommand 'copy'
     sandbox.val ''
-    unless hidden
-      @status = result
-      showNotification()
+    showNotification() unless hidden

   # Attempt to retrieve the key of the template with the specified `name`.
   # Since only the names of predefined templates are known, return a newly
@@ -1337,12 +1344,19 @@
   queryUrlShortener: (filter, singular = yes) ->
     utils.query SHORTENERS, singular, filter

-  # Reset the message and status associated with the current copy request.
+  # Reset the notification information associated with the current copy
+  # request.
   # This should be called when a copy request is completed regardless of its
   # outcome.
   reset: ->
-    @message = ''
-    @status  = no
+    @notification =
+      description:      ''
+      descriptionStyle: ''
+      html:             ''
+      icon:             utils.url '../images/icon_48.png'
+      iconStyle:        ''
+      title:            ''
+      titleStyle:       ''

   # Update the context menu items to reflect the currently enabled templates.
   # If the context menu option has been disabled by the user, just remove all


Removed unnecessary view code

Removed unnecessary view code

--- src/modules/todo/TodoView.coffee
+++ src/modules/todo/TodoView.coffee
@@ -10,29 +10,27 @@
 			m "div", do ->
 				return []
 				.concat m.component Nav
-				.concat m "div",
-					m ".pt-page", { key: m.route(), config: anim },
-						m "article.card.row.two-third", do ->
+				.concat m ".pt-page", { key: m.route(), config: anim },
+					m "article.card.row.two-third", do ->
+						return []
+						.concat m "header",
+							m "h2", "Todo"
+						.concat m "div.content", do ->
 							return []
-							.concat m "header",
-								m "h2", "Todo"
-							.concat m "div.content", do ->
-								return []
-								.concat m "input",
-									onchange: m.withAttr "value", vm.description
-									value: vm.description()
-								.concat m "button.row", onclick: vm.add, "Add"
-								.concat m "div",
-									vm.list.map (task, index) ->
-										decor = if task.done() then "line-through" else "none"
-										style = style: textDecoration: decor
-										return m "div.row.one",
-											m "label", do ->
-												return []
-												.concat m "input[type=checkbox]",
-													onclick: m.withAttr "checked", task.done
-													checked: task.done()
-												.concat m "span.checkable", style, task.description()
+							.concat m "input",
+								onchange: m.withAttr "value", vm.description
+								value: vm.description()
+							.concat m "button.row", onclick: vm.add, "Add"
+							.concat m "div", vm.list.map (task, index) ->
+								decor = if task.done() then "line-through" else "none"
+								style = style: textDecoration: decor
+								return m "div.row.one",
+									m "label", do ->
+										return []
+										.concat m "input[type=checkbox]",
+											onclick: m.withAttr "checked", task.done
+											checked: task.done()
+										.concat m "span.checkable", style, task.description()

 TodoView = infect.func Klass


KDView: removed a development only method

--- src/core/view.coffee
+++ src/core/view.coffee
@@ -98,7 +98,6 @@
     @subViews         = []

     @defaultInit options,data
-    @devHacks()

   defaultInit:(options, data)->

@@ -910,17 +909,3 @@

   activateKeyView: ->
     @emit? 'KDViewBecameKeyView'
-
-  # development only
-  devHacks:->
-
-    @on "click", (event)=>
-      return unless event
-      if event.metaKey and event.altKey and event.ctrlKey
-        log @getData()
-        event.stopPropagation?()
-        event.preventDefault?()
-        return false
-      else if event.altKey and (event.metaKey or event.ctrlKey)
-        log this
-        return false


improve code clarity

improve code clarity

--- src/cozymodel.coffee
+++ src/cozymodel.coffee
@@ -170,9 +170,13 @@
         docType = @getDocType()
         {map, reduce} = request

+        # transforms all functions in anonymous functions
+        # function named(a, b){...} --> function (a, b){...}
+        # function (a, b){...} --> function (a, b){...}
         if reduce? and typeof reduce is 'function'
             reduce = reduce.toString()
-            reduce = "function #{reduce.slice reduce.indexOf '('}"
+            reduceArgsAndBody = reduce.slice reduce.indexOf '('
+            reduce = "function #{reduceArgsAndBody}"

         view =
             reduce: reduce


Remove countdown rendering script

Remove countdown rendering script

--- assets/javascripts/app.coffee
+++ assets/javascripts/app.coffee
@@ -66,36 +66,6 @@
 $(".nav-list a").click (e) ->
   toggleCurrentSection $(e.target).attr("href").substring(1)

-# Render countdown ring
-start = new Date("November 29, 2013 14:40:00")
-now = new Date().getTime()
-end = new Date("February 02, 2014 00:00:00")
-ratio = (now - start) / (end - start)
-
-days = [100 * ratio, 100 - 100 * ratio]
-
-width = 350
-height = 300
-radius = Math.max(width, height) / 2
-colors = ["#333333", "#33CC99"]
-pie = d3.layout.pie().sort(null)
-arc = d3.svg.arc().innerRadius(radius - 65).outerRadius(radius - 50)
-svg = d3.select("#countdown").append("svg")
-  .attr("id", "countdown-graph")
-  .attr("width", width)
-  .attr("height", height)
-  .append("g")
-  .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
-
-path = svg.selectAll("path")
-  .data(pie(days))
-  .enter()
-  .append("path")
-  .attr("fill", (d, i) -> colors[i])
-  .attr("d", arc)
-
-d3.select(".days").text(Math.ceil((end - now) / (24 * 60 * 60 * 1000)))
-
 d3.select("#scroll-button").on "click", ->
   navPos = getOffsetTop(d3.select("#nav")[0][0])
   scrollTo(navPos)


formatting the elasticsearch output as code

--- src/scripts/elasticsearch.coffee
+++ src/scripts/elasticsearch.coffee
@@ -35,13 +35,10 @@
     if cluster_url == "" || cluster_url == undefined
       msg.send("Do not recognise the cluster alias: #{alias}")
     else
-      msg.http("#{cluster_url}/_cluster/health")
+      msg.http("#{cluster_url}/_cluster/health?pretty=true")
         .get() (err, res, body) ->
           json = JSON.parse(body)
-          cluster_name = json['cluster']
-          status = json['status']
-          number_of_nodes = json['number_of_nodes']
-          msg.send "Cluster: #{cluster_url} \nStatus: #{status} \n Nodes: #{number_of_nodes}"
+          msg.send("/code #{json}")

   catNodes = (msg, alias) ->
     cluster_url = _esAliases[alias]
@@ -103,7 +100,7 @@
       json = JSON.stringify(data)
       msg.http("#{cluster_url}/_cluster/settings")
         .put(json) (err, res, body) ->
-          msg.send(body)
+          msg.send("/code #{body}")

   enableAllocation = (msg, alias) ->
     cluster_url = _esAliases[alias]
@@ -122,7 +119,7 @@
       json = JSON.stringify(data)
       msg.http("#{cluster_url}/_cluster/settings")
         .put(json) (err, res, body) ->
-          msg.send(body)
+          msg.send("/code #{body}")

   showClusterSettings = (msg, alias) ->
     cluster_url = _esAliases[alias]


Add 'do something' to 'something random'

--- src/scripts/hubot-factoid.coffee
+++ src/scripts/hubot-factoid.coffee
@@ -101,11 +101,11 @@

   robot.factoid = new FactoidHandler

-  robot.respond /something random$/, (msg) =>
+  robot.respond /(?:do something|something random)$/, (msg) =>
     factoid = do robot.factoid.random
     robot.factoid.output msg, factoid

-  robot.hear /^something random$/, (msg) =>
+  robot.hear /^(?:do something|something random)$/, (msg) =>
     factoid = do robot.factoid.random
     robot.factoid.output msg, factoid


Rename Workspace::openSingletonSync changeFocus option to activatePane

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -95,8 +95,10 @@

   # Public: Synchronously open an editor for the given URI or activate an existing
   # editor in any pane if one already exists.
-  openSingletonSync: (uri, {changeFocus, initialLine, split}={}) ->
-    changeFocus ?= true
+  openSingletonSync: (uri, options={}) ->
+    {initialLine, split} = options
+    # TODO: Remove deprecated changeFocus option
+    activatePane = options.activatePane ? options.changeFocus ? true
     uri = atom.project.relativize(uri)

     if pane = @paneContainer.paneForUri(uri)
@@ -112,7 +114,7 @@
       editor = atom.project.openSync(uri, {initialLine})

     pane.activateItem(editor)
-    pane.activate() if changeFocus
+    pane.activate() if activatePane
     editor

   # Public: Reopens the last-closed item uri if it hasn't already been reopened.


Ensure correct transitionend(?)

Ensure correct transitionend(?)

--- resources/assets/coffee/_classes/nav.coffee
+++ resources/assets/coffee/_classes/nav.coffee
@@ -164,7 +164,9 @@
             submenu.classList.add 'hidden'

         if menu.classList.contains 'js-nav-switch--animated'
-          $(menu).one 'transitionend', @autoFocus
+          $(menu)
+            .off 'transitionend', @autoFocus
+            .one 'transitionend', @autoFocus
         else
           Timeout.set 0, => @autoFocus null, menu


only enable save button when text is different than current one

--- imports/ui/menus/AppControls.cjsx
+++ imports/ui/menus/AppControls.cjsx
@@ -20,9 +20,10 @@
     @setState showRemoveAppOverlay: false

   render: ->
+    saveButtonHandler = if @props.saveButtonDisabled then null else @props.onSaveApp
     <span>
       <Menu pad='medium'>
-        <Button onClick={@props.onSaveApp} align='start' plain=true label='Save' icon={<Icons.Base.Save />}></Button>
+        <Button onClick={saveButtonHandler} align='start' plain=true label='Save' icon={<Icons.Base.Save />}></Button>
         <Button onClick={@showRemoveLayer} align='start' plain=true label='Remove' icon={<Icons.Base.Trash />}></Button>
         <Box pad='medium'></Box>
         <Button onClick={@props.onStartApp} align='start' plain=true label='Start' icon={<Icons.Base.Play />}></Button>


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/point.coffee
+++ src/point.coffee
@@ -46,7 +46,8 @@
     ###*

     ###
-    clamp:
+    clamp: ->
+
     ###*
     Creates a copy of this point.


移除了qqapi对存储的依赖

移除了qqapi对存储的依赖

--- src/qqapi.coffee
+++ src/qqapi.coffee
@@ -1,17 +1,15 @@
-https = require "https"
-http  = require 'http'
-crypto = require 'crypto'
-querystring  = require 'querystring'
-Url = require('url')
+###
+  QQAPI 包含获取好友，群信息，发送消息，长轮询
+  - 使用前需要设置 cookies()
+###
+
+
+
 all_cookies = []
-defaults    = {}
 fs = require 'fs'
 jsons = JSON.stringify
 client = require './httpclient'

-md5 = (str) ->
-    md5sum = crypto.createHash 'md5'
-    md5sum.update(str).digest('hex')

 # TODO: logger 分级控制
 log   = console.log
@@ -21,26 +19,6 @@
         all_cookies = cookie
         client.global_cookies(all_cookies)
     return all_cookies
-
-exports.defaults = (key,value)->
-    if key and value
-        defaults[key] = value
-    else if key
-        defaults[key]
-    else
-        defaults
-
-exports.defaults_save = ->
-    defaults.cookie = all_cookies
-    fs.writeFileSync 'tmp/store.json' ,  jsons(defaults)
-
-exports.defaults_read = ->
-    try
-        defaults = JSON.parse( fs.readFileSync  'tmp/store.json' )
-        all_cookies  = defaults.cookie
-        client.global_cookies(all_cookies)
-    catch error
-        log error

 # 长轮训，默认一分钟


Add questPath option to docs

Add questPath option to docs

--- src/quest.coffee
+++ src/quest.coffee
@@ -65,7 +65,8 @@
   # * `db`: {String} Name of the database.
   # * `user`: {String} Database user.
   # * `pass`: {String} Database password.
-  # * `time`: {Boolean} Set to false to not print execution time of each quury.
+  # * `time`: {Boolean} Set to false to not print execution time of each query.
+  # * `questPath`: {String} path to this quest.
   # * `name`: {String} Quest name (same as passed on the command line).
   # * `opts`: {Object} Parsed command line args for the quest.
   constructor: (host, db, user, pass, @questPath, @time, @opts) ->


Move private helpers to after exports

Move private helpers to after exports

--- src/range.coffee
+++ src/range.coffee
@@ -7,9 +7,9 @@
 xpath = require('./xpath')

 # https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
-ELEMENT_NODE = 1
 TEXT_NODE = 3

+# Public interface.

 normalizeBoundaries = (range) ->
   {startContainer, startOffset, endContainer, endOffset} = range
@@ -344,6 +344,18 @@
     }

+# Export the above interface.
+module.exports = {
+  BrowserRange
+  NormalizedRange
+  SerializedRange
+  normalizeBoundaries
+  splitBoundaries
+}
+
+
+# Private helpers.
+
 # Return true if the given predicate is true for every Node of the tree.
 # The predicate function is invoked once for each Node in the tree.
 # An optional third argument specifies a traversal order and should be a
@@ -457,13 +469,3 @@
   while node? and not contains(node, other)
     node = node.parentNode
   return node
-
-
-# Export the public module interface.
-module.exports = {
-  BrowserRange
-  NormalizedRange
-  SerializedRange
-  normalizeBoundaries
-  splitBoundaries
-}


Removed Generic Extension

Removed Generic Extension

This way it works with both coffee and js

--- bin/kdhelp.coffee
+++ bin/kdhelp.coffee
@@ -94,7 +94,7 @@
 suggest = (commands=[], guilty='', threshold=3) ->
   alt_commands  = fs.readdirSync commands.join path.sep
   for potential in alt_commands
-    potential = path.basename potential, '.coffee'
+    potential = potential.split('.')[0] # Remove ext
     if potential is 'index' then continue # Don't suggest the index file lol
     if new Levenshtein(guilty, potential).distance <= threshold
       return potential


Integrate CSS into gulp develop

Integrate CSS into gulp develop

--- bokehjs/gulp/tasks/develop.coffee
+++ bokehjs/gulp/tasks/develop.coffee
@@ -9,6 +9,7 @@

 gulp.task "develop:watch", ["develop"], ->
   gulp.watch "#{paths.buildDir.js}/*.js", ["develop:install-js"]
+  gulp.watch "#{paths.buildDir.css}/*css", ["develop:install-js"]

 outputLine = (line) ->
   prefix = gutil.colors.cyan "setup.py:"


Try to remove scaffolding

Try to remove scaffolding

--- test/appveyor.coffee
+++ test/appveyor.coffee
@@ -21,10 +21,7 @@
   uri.headers =
     'Content-Type': 'application/json'
     'Content-Length': data.length
-  console.log 'POST', api, uri, data
   q = http.request uri, ->
-  q.on 'error', ->
-    console.error 'HTTP error!'
   q.end data

 events =


Stray console.log

Stray console.log

--- test/bw/moves.coffee
+++ test/bw/moves.coffee
@@ -4700,7 +4700,6 @@

       @p2.isImmune(@battle, "Ground").should.be.true
       @battle.performMove(@id1, smackDown)
-      console.log @p2.has(Attachment.SmackDown)
       @p2.isImmune(@battle, "Ground").should.be.false

     it "stops Fly", ->


don't bomb out if a name isn't set, just skip it

--- src/robot.coffee
+++ src/robot.coffee
@@ -200,7 +200,8 @@
     result = null
     lowerName = name.toLowerCase()
     for k of (@brain.data.users or { })
-      if @brain.data.users[k]['name'].toLowerCase() is lowerName
+      userName = @brain.data.users[k]['name']
+      if userName? and userName.toLowerCase() is lowerName
         result = @brain.data.users[k]
     result


Add a more helpful message when issue is not found

--- src/jira.coffee
+++ src/jira.coffee
@@ -307,6 +307,7 @@

       fetch("#{jiraUrl}/rest/api/2/issue/#{ticket}")
       .then (json) ->
+        throw "<#{jiraUrl}/browse/#{ticket}|#{ticket}> does not exist" unless json
         id = json.id
         jira = buildJiraAttachment json
         attachments.push jira
@@ -347,6 +348,7 @@
     .catch (error) ->
       send msg, message
       send msg, "*Error:* #{error}"
+      robot.logger.error error.stack

   handleTransitionRequest = (msg, includeAttachment=yes) ->
     msg.finish()


Cleanup route comments

Cleanup route comments

--- www/js/routes.coffee
+++ www/js/routes.coffee
@@ -50,7 +50,7 @@
     checkinShow: ->
       return

-    # The famous "Explore" view, where users can see what's in the area; from
+    # The "Explore" view, where users can see what's in the area; from
     # popular venues to coffee to trending.
     explore: (section) ->
       appView.currentView = new VenueViews.Explore
@@ -66,6 +66,10 @@
           replace: true
           trigger: true

+    # The login/intro screen view, shown on first-run of the app when no
+    # user authentication info is available. Shouldn't be accessible to auth'd
+    # users, so we check for authorization and redirect to the timeline view
+    # if it exists.
     userLogin: ->
       # Don't allow authorized users to access the login page.
       if window.GLOBALS.Users.getSelf()


formattingggggggggg

formattingggggggggg

--- xarkon-server.coffee
+++ xarkon-server.coffee
@@ -96,7 +96,7 @@
 hasEngine = []
 Engine = gcomponent
   compInit: ->
-    @thrustDir = v.create 0,0
+    @thrustDir = v.create 0, 0
   lookup: hasEngine
   thrust: 9
   warp: 1
@@ -140,10 +140,10 @@
     #repel:   1 << 7

   commandFuncs:
-    up:    -> @addThrustDir(Game.directions.up)
-    down:  -> @addThrustDir(Game.directions.down)
-    left:  -> @addThrustDir(Game.directions.left)
-    right: -> @addThrustDir(Game.directions.right)
+    up:    -> @addThrustDir Game.directions.up
+    down:  -> @addThrustDir Game.directions.down
+    left:  -> @addThrustDir Game.directions.left
+    right: -> @addThrustDir Game.directions.right
     slow:  -> @warp = 0.5; @df = 0.8
     fast:  -> @warp = 2.5; @df = 0.87

@@ -152,12 +152,12 @@
   compInit: ->
     @sessionId = null # this needs to be set later
     @client = null # this needs to be set later
-    @shortId = {top: 1}
-    @shortId[@id] = String.fromCharCode(1) # @id was set by CMan's generated init
+    @shortId = top: 1
+    @shortId[@id] = String.fromCharCode 1  # @id was set by CMan's generated init
   setClient: (client)->
     [@client, @sessionId] = [client, client.sessionId]
   send: (msg)->
-    @client.send(msg)
+    @client.send msg
   setShortId: (id)->
     unless @shortId[id]?
       @shortId[id] = String.fromCharCode ++@shortId.top


Temporarily disabling key debug logs and removing debug variable

--- src/keys.coffee
+++ src/keys.coffee
@@ -9,7 +9,6 @@

 Kona.Keys =
-  name: "kona.keys"
   # Contains info on keys on their associated handler(s)
   # Ex format:
   #   65: [ <function>, <function> ]
@@ -32,14 +31,14 @@
   # Usage: Kona.keys.bind 'a', -> console.log "You pressed a!"
   bind: (key, handler) ->
     key = key.replace(/\s/g,'') # Strip any whitespace from key selector
-    Kona.debug "binding on key: '#{key}' (normalized to code: #{Kona.Keys._map[key] || key.toUpperCase().charCodeAt(0)})"
+    # Kona.debug "binding on key: '#{key}' (normalized to code: #{Kona.Keys._map[key] || key.toUpperCase().charCodeAt(0)})"

     # Convert to keycode
     key = @_map[key] || key.toUpperCase().charCodeAt(0)

     # Store handler
     if !@_handlers[key]?
-      Kona.debug "  key #{key} not found in existing handlers, setting to []\n"
+      # Kona.debug "  key #{key} not found in existing handlers, setting to []\n"
       @_handlers[key] = []

     @_handlers[key].push(handler)
@@ -48,8 +47,8 @@
   # Respond to keydown event and call associated handler
   dispatch: (event) ->
     key = event.keyCode # TODO: normalize (event.which ?)
-    Kona.debug "\ndispatching key: #{key}"
-    Kona.debug "  no handler found, ABORT" if !@_handlers[key]?
+    # Kona.debug "\ndispatching key: #{key}"
+    # Kona.debug "  no handler found, ABORT" if !@_handlers[key]?

     # Abort if we're in a data input element or no matching handlers found
     return if @reject(event) || !@_handlers[key]?
@@ -63,7 +62,7 @@
   reject: (event) ->
     # Ignore keypresses from elements that take keyboard data input
     tagName = event.target.tagName
-    Kona.debug "  data input - REJECT" if _.include(['INPUT', 'SELECT', 'TEXTAREA'], tagName)
+    # Kona.debug "  data input - REJECT" if _.include(['INPUT', 'SELECT', 'TEXTAREA'], tagName)
     _.include(['INPUT', 'SELECT', 'TEXTAREA'], tagName)


remove invisible character on normalization

--- src/line.coffee
+++ src/line.coffee
@@ -36,6 +36,7 @@
   @normalizeHtml: (root) ->
     return if root.childNodes.length == 1 && root.firstChild.tagName == 'BR'
     this.applyRules(root)
+    this.removeNoBreak(root)
     this.removeRedundant(root)
     # TODO need wrapText before and after for these cases:
     # Before: TestWhat -> TestWhat
@@ -48,10 +49,16 @@
         root = root.firstChild
       root.appendChild(root.ownerDocument.createElement('br'))

+  @removeNoBreak: (root) ->
+    Tandem.Utils.traversePreorder(root, 0, (node) =>
+      if node.nodeType == node.TEXT_NODE
+        node.textContent = node.textContent.split(Tandem.Constants.NOBREAK_SPACE).join('')
+      return node
+    )
+
   @removeRedundant: (root) ->
     tandemKey = '_tandemAttributes' + Math.floor(Math.random() * 100000000)
     root[tandemKey] = {}
-
     isRedudant = (node) ->
       if node.nodeType == node.ELEMENT_NODE && Tandem.Utils.canModify(node)
         if Tandem.Utils.getNodeLength(node) == 0
@@ -67,7 +74,6 @@
           if node.previousSibling == null && node.nextSibling == null && !TandemLine.isLineNode(node.parentNode) && node.parentNode.tagName != 'LI'
             return true
       return false
-
     Tandem.Utils.traversePreorder(root, 0, (node) =>
       if isRedudant(node)
         node = Tandem.Utils.unwrap(node)


Change background to white

Change background to white

--- src/main.coffee
+++ src/main.coffee
@@ -1,9 +1,9 @@
 preload = ->
   game.load.image 'alive', 'dist/assets/alive.jpg'
-  game.load.image 'dead', 'dist/assets/dead.jpg'

 create = ->
-  game.add.sprite 0, 0, 'dead'
+  game.stage.backgroundColor = 0xFFFFFF
+  game.add.sprite 0, 0, 'alive'

 update = ->


fixed the fix of something that wasn't broken

--- src/main.coffee
+++ src/main.coffee
@@ -13,7 +13,7 @@
   hello: ->
     textarea = $('#source textarea')

-    outputarea = $('#output .output')
+    outputarea = $('#output')

     showHideCodeButton = $('button')
     showHideCodeButton.text(hideCodeText)


fix event

fix event

--- client/app/views/konnector.coffee
+++ client/app/views/konnector.coffee
@@ -78,7 +78,7 @@
             @$("##{slug}-first-import").hide()
         @$("##{slug}-first-import-date").hide()
         @$("##{slug}-import-date").datepicker({minDate: 1, dateFormat: "dd-mm-yy" })
-        @$("##{slug}-first-import-link").click =>
+        @$("##{slug}-first-import-link").click (event) =>
             event.preventDefault()
             @$("##{slug}-first-import-date").show()
             @$("##{slug}-first-import-text").hide()


implement leapfrogging for `$window()`

implement leapfrogging for `$window()`

--- src/main.coffee
+++ src/main.coffee
@@ -390,17 +390,22 @@
 @$window = ( settings ) ->
   ### Moving window over data items in stream. Turns stream of values into stream of
   lists each `width` elements long. ###
-  defaults  = { width: 3, fallback: null, }
-  settings  = assign {}, defaults, settings
+  defaults                = { width: 3, fallback: null, }
+  settings                = assign {}, defaults, settings
   validate.pipestreams_$window_settings settings
   if settings.width is 1
+    if settings.leapfrog?
+      return @$ { leapfrog: settings.leapfrog, }, ( d, send ) => send [ d, ]
     return @$ ( d, send ) => send [ d, ]
   #.........................................................................................................
-  last      = Symbol 'last'
-  had_value = false
-  fallback  = settings.fallback
-  buffer    = ( fallback for _ in [ 1 .. settings.width ] )
-  return @$ { last, }, ( d, send ) =>
+  last                    = Symbol 'last'
+  had_value               = false
+  fallback                = settings.fallback
+  buffer                  = ( fallback for _ in [ 1 .. settings.width ] )
+  remit_settings          = { last, }
+  remit_settings.leapfrog = settings.leapfrog if settings.leapfrog?
+  #.........................................................................................................
+  return @$ remit_settings, ( d, send ) =>
     if d is last
       if had_value
         for _ in [ 1 ... settings.width ]


Do not show html tags contained in errors

--- client/app/views/konnector.coffee
+++ client/app/views/konnector.coffee
@@ -87,6 +87,7 @@

     # Show error widget and fill it with given message.
     showErrors: (msg) ->
+        msg = msg.replace /<[^>]*>/ig, ''
         @$('.error .message').html msg
         @$('.error').show()


Remove unused logger, so Signal actually works

--- src/main.coffee
+++ src/main.coffee
@@ -4,7 +4,7 @@
 	'store'
 	'invariant'
 	'signals'
-], (dispatcher, actionManager, Store, invariant, logger, {Signal}) ->
+], (dispatcher, actionManager, Store, invariant, {Signal}) ->

 	return {
 		dispatcher


Remove unused params

Remove unused params

--- src/main.coffee
+++ src/main.coffee
@@ -29,8 +29,6 @@
       {name: 'bootstrapScript', param: @bootstrapScript},
       {name: 'resourcePath', param: @resourcePath},
     ]
-    params.push {name: 'devMode', param: 1} if @isDev
-    params.push {name: 'exitWhenDone', param: 1} if @exitWhenDone

     @setNodePaths()
     @openWithParams(params)


More fix for null result

More fix for null result

--- client/components/TableRow.coffee
+++ client/components/TableRow.coffee
@@ -97,6 +97,8 @@
             return "none"

 TotalResult = (props) ->
+    if not props.result
+        return "??"
     style = globalStyles.mainTable_td
     title = ""
     if not props.header


Remove dev path hacks

Remove dev path hacks

--- src/slack.coffee
+++ src/slack.coffee
@@ -1,4 +1,4 @@
-{Robot, Adapter, TextMessage, EnterMessage, LeaveMessage} = require '../../hubot/node_modules/hubot'
+{Robot, Adapter, TextMessage, EnterMessage, LeaveMessage} = require 'hubot'

 SlackClient = require 'slack-client'
 Util = require 'util'


fixed feedlyconsole.css path, commented out styles.css

--- coffeescript/feedlyconsole.coffee
+++ coffeescript/feedlyconsole.coffee
@@ -413,15 +413,15 @@
       observer.disconnect()
       file = "feedlyconsole.html"
       _console.debug "[feedlyconsole] injecting %s.", file
-      insertCSSLink "stylesheets/styles.css"
-
+      #insertCSSLink "stylesheets/styles.css"
       #insertCSSLink("stylesheets/source-code-pro.css");
       insertCSSLink "stylesheets/jquery-ui.css"
-      insertCSSLink "feedlyconsole.css"
+      insertCSSLink "stylesheets/feedlyconsole.css"
       feedlyconsole = $("<div/>",
         id: "feedlyconsole"
       ).load(chrome.extension.getURL(file), ->
-        _console.log "[feedlyconsole] loaded %s %O readline.attach %O.", file, $("#feedlyconsole"), this
+        _console.log "[feedlyconsole] loaded %s %O readline.attach %O.",
+        file, $("#feedlyconsole"), this
         Josh.config.readline.attach $("#shell-panel").get(0)
         initializeUI()
       )


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -23,7 +23,7 @@
         if data.easing.isString?()
           easingFunction = Easing[data.easing](data.start, data.end)
         else
-          easingFunction
+          easingFunction = data.e

         I[property] = f((t - data.startTime) / data.duration)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -27,12 +27,12 @@

     easing = properties.easing || "linear"
     delete properties.easing
-
+
     for property, target of properties
       I.activeTweens[property] =
         end: target
         start: I[property]
-        easing: "linear"
+        easing: easing
         duration: duration
         startTime: I.age
         endTime: I.age + duration


stop snapshot

stop snapshot

--- src/utils.coffee
+++ src/utils.coffee
@@ -90,7 +90,7 @@
       try
         heapdump = require 'heapdump'
         process.chdir '/tmp'
-        heapdump.writeSnapshot()
+#        heapdump.writeSnapshot()
         process.chdir cwd
       catch e
         exports.debug e


Update articles schema - change "feed" to "feedId"

--- imports/schemas/article.coffee
+++ imports/schemas/article.coffee
@@ -1,4 +1,4 @@
-articleSchema = new SimpleSchema(
+articleSchema = new SimpleSchema
   _id:
     type: String
     optional: true
@@ -34,8 +34,8 @@
   deletedDate:
     type: Date
     optional: true
-  feed:
+  feedId:
     type: String
     optional: true
-)
+
 module.exports = articleSchema


Re-enable admin/subscription destruction

--- app/assets/javascripts/app/controllers/admin/subscriptions.js.coffee
+++ app/assets/javascripts/app/controllers/admin/subscriptions.js.coffee
@@ -250,6 +250,7 @@
     if confirm(I18n.t('common.are_you_sure'))
       Subscription.one 'refresh', =>
         @destroy_with_notifications @subscription
+      Subscription.fetch(id: @id)

   view_members: (e) ->
     e.preventDefault()


Fixing this binding on catch

Fixing this binding on catch

--- src/video.coffee
+++ src/video.coffee
@@ -80,7 +80,7 @@
 			# Control the video element, handling the case that the browser denied
 			# the playback
 			if @playing
-			then @$refs.video.play()?.catch (e) ->
+			then @$refs.video.play()?.catch (e) =>
 				console.error e.message
 				console.error "Vue Visual: try setting `muted` to true"
 				@playing = false