Documentation engine

Documentation engine

--- evilbot.coffee
+++ evilbot.coffee
@@ -113,6 +113,10 @@
 hear = (pattern, callback) ->
   handlers.push [ pattern, callback ]

+descriptions = {}
+desc = (phrase, functionality) ->
+  descriptions[phrase] = functionality
+

 #
 # robot heart
@@ -138,8 +142,16 @@
   message.say "I am learning to love."

 hear /help/, (message) ->
-  message.say "I listen for '@#{username} image me PHRASE' and '@#{username} wiki me PHRASE' and '@#{username} weather in PLACE'"
+  message.say "I listen for the following…", ->
+    for phrase, functionality of descriptions
+      console.log(typeof(functionality))
+      if functionality
+        output =  phrase + ": " + functionality
+      else
+        output = phrase
+      message.say output

+desc 'weather in PLACE'
 hear /weather in (.+)/i, (message) ->
   place = message.match[1]
   url   = "http://www.google.com/ig/api?weather=#{escape place}"
@@ -154,6 +166,7 @@
     catch e
       console.log "Weather error: " + e

+desc 'wiki me PHRASE', 'returns a wikipedia page for PHRASE'
 hear /wiki me (.*)/i, (message) ->
   term = escape(message.match[1])
   url  = "http://en.wikipedia.org/w/api.php?action=opensearch&search=#{term}&format=json"
@@ -167,6 +180,7 @@
     catch e
       console.log "Wiki error: " + e

+desc 'image me PHRASE'
 hear /image me (.*)/i, (message) ->
   phrase = escape(message.match[1])
   url = "http://ajax.googleapis.com/ajax/services/search/images?v=1.0&rsz=8&safe=active&q=#{phrase}"


Add a comment help line for #2.

Add a comment help line for #2.

--- src/github-pages.coffee
+++ src/github-pages.coffee
@@ -18,6 +18,7 @@
 #   hubot pages custom_404 [repo] - fetch whether there's a custom 404 page
 #   hubot pages latest [repo] - fetch latest build
 #   hubot pages builds [repo] - fetch the latest 30 builds
+#   hubot pages version - display the gem versions currently running on GitHub Pages
 #
 # Notes:
 #   Per the GitHub API, you must be the owner of the repo in question.


call with context

call with context

--- src/chaplin/views/view.coffee
+++ src/chaplin/views/view.coffee
@@ -245,7 +245,7 @@
     return @_delegateEvents events if events
     # Call _delegateEvents for all superclasses’ `events`.
     for classEvents in utils.getAllPropertyVersions this, 'events'
-      classEvents = classEvents() if typeof classEvents is 'function'
+      classEvents = classEvents.call this if typeof classEvents is 'function'
       @_delegateEvents classEvents
     return


Update legacy methods to match new groups and options object;

--- lib/toolbar.coffee
+++ lib/toolbar.coffee
@@ -32,19 +32,33 @@
       addButton: @toolbarView.addButton.bind(@toolbarView)
       addSpacer: @toolbarView.addSpacer.bind(@toolbarView)

-  prependButton: (args...) ->
+  prependButton: (icon, callback, tooltip, iconset, data) ->
     Grim ?= require 'grim'
     Grim.deprecate 'Use version ^0.1.0 of the tool-bar Service API.'
-    return @toolbarView.addButton(args...)
-  prependSpacer: (args...) ->
+    @toolbarView.group = 'legacy'
+    @toolbarView.addButton
+      icon: icon
+      callback: callback
+      tooltip: tooltip
+      iconset: iconset
+      data: data
+  prependSpacer: () ->
     Grim ?= require 'grim'
     Grim.deprecate 'Use version ^0.1.0 of the tool-bar Service API.'
-    return @toolbarView.addSpacer(args...)
-  appendButton: (args...) ->
+    @toolbarView.group = 'legacy'
+    @toolbarView.addSpacer()
+  appendButton: (icon, callback, tooltip, iconset, data) ->
     Grim ?= require 'grim'
     Grim.deprecate 'Use version ^0.1.0 of the tool-bar Service API.'
-    return @toolbarView.addButton(args...)
-  appendSpacer: (args...) ->
+    @toolbarView.group = 'legacy'
+    @toolbarView.addButton
+      icon: icon
+      callback: callback
+      tooltip: tooltip
+      iconset: iconset
+      data: data
+  appendSpacer: () ->
     Grim ?= require 'grim'
     Grim.deprecate 'Use version ^0.1.0 of the tool-bar Service API.'
-    return @toolbarView.addSpacer(args...)
+    @toolbarView.group = 'legacy'
+    @toolbarView.addSpacer()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/level_state.coffee
+++ src/level_state.coffee
@@ -1,3 +1,12 @@
+###*
+Creates an oscillator function with the given parameters.
+
+@name Oscillator
+@constructor
+@param {Number} amplitude How much to scale the oscillator function value
+@param {Number} period How fast the osciallator function repeats
+@param {Number} offset How much to offset the created osciallator function. Useful for translating between sin and cosine functions.
+###
 LevelState = (I={}) ->
   Object.reverseMerge I,
     duration: 10


add more debug

add more debug

--- lib/watcher.coffee
+++ lib/watcher.coffee
@@ -1,10 +1,11 @@
 { EventEmitter2 } = require 'eventemitter2'
-d = (require 'debug') 'watcher'
+d = (require 'debug') 'refactor:watcher'

 module.exports =
 class Watcher extends EventEmitter2

   constructor: (@moduleManager, @editor) ->
+    d 'constructor'
     super()
     #@editor.on 'grammar-changed', @verifyGrammar

@@ -16,6 +17,7 @@
     @moduleManager.on 'changed', @verifyGrammar

   destruct: =>
+    d 'destruct'
     @removeAllListeners()
     @deactivate()
     #@editor.off 'grammar-changed', @verifyGrammar
@@ -26,6 +28,7 @@
     delete @module

   onDestroyed: =>
+    d 'onDestroyed'
     return unless @eventDestroyed
     @emit 'destroyed', @

@@ -61,6 +64,7 @@
     @parse()

   deactivate: ->
+    d 'deactivate'
     # Stop listening
     @cursorMoved = false

@@ -103,6 +107,7 @@
     @eventCursorMoved = on

   onParseEnd: (errors) =>
+    d 'onParseEnd'
     if errors?
       @createErrors errors
     else
@@ -126,12 +131,14 @@
       marker

   destroyReferences: ->
+    d 'destroyReferences'
     return unless @referenceMarkers?
     for marker in @referenceMarkers
       marker.destroy()
     delete @referenceMarkers

   createReferences: ->
+    d 'createReferences'
     ranges = @ripper.find @editor.getSelectedBufferRange().start
     return unless ranges? and ranges.length > 0
     @referenceMarkers = for range in ranges
@@ -182,6 +189,7 @@
     true

   abort: =>
+    d 'abort'
     # When this editor isn't active, do nothing.
     return unless @isActive() and @renamingCursor? and @renamingMarkers?

@@ -201,6 +209,7 @@
     @done()

   done: ->
+    d 'done'
     # When this editor isn't active, returns false for aborting keyboard binding.
     return false unless @isActive() and @renamingCursor? and @renamingMarkers?


added support for analytics to options page along with some bug fixes

--- src/lib/options.coffee
+++ src/lib/options.coffee
@@ -56,6 +56,7 @@

 # Update the options page with the values from the current settings.
 load = ->
+  $('#analytics').attr    'checked', 'checked' if store.get 'analytics'
   anchor = store.get 'anchor'
   $('#anchorTarget').attr 'checked', 'checked' if anchor.target
   $('#anchorTitle').attr  'checked', 'checked' if anchor.title
@@ -118,10 +119,19 @@

 # Bind the event handlers required for persisting general changes.
 loadSaveEvents = ->
+  $('#analytics').change ->
+    store.set 'analytics', analytics = $(this).is ':checked'
+    if analytics
+      utils.addAnalytics()
+      chrome.extension.getBackgroundPage().utils.addAnalytics()
+    else
+      utils.removeAnalytics()
+      chrome.extension.getBackgroundPage().utils.removeAnalytics()
   bindSaveEvent '#anchorTarget, #anchorTitle', 'change', 'anchor', ->
     @is ':checked'
   $('#contextMenu').change ->
     store.set 'contextMenu', $(this).is ':checked'
+    ext.updateContextMenu()
   $('#shortcuts').change ->
     store.set 'shortcuts', $(this).is ':checked'

@@ -842,7 +852,7 @@
   init: ->
     i18n.init
       footer:
-        opt_footer: new Date().format 'Y'
+        opt_footer: "#{new Date().getFullYear()}"
     # Bind tab selection event to all tabs.
     $('[tabify]').click ->
       $this = $ this
@@ -850,7 +860,10 @@
         $this.siblings().removeClass 'selected'
         $this.addClass 'selected'
         $($this.attr 'tabify').show().siblings('.tab').hide()
-        store.set 'options_active_tab', $this.attr 'id'
+        id = $this.attr 'id'
+        store.set 'options_active_tab', id
+        id = id.match(/(\S*)_nav$/)[1]
+        # TODO: Analytics event tracking.
     # Reflect the persisted tab.
     store.init 'options_active_tab', 'general_nav'
     $("##{store.get 'options_active_tab'}").click()
@@ -868,7 +881,7 @@
     # settings storing OAuth information for the [Google URL
     # Shortener](http://goo.gl).
     googl = ext.queryUrlShortener (shortener) ->
-      shortener.name is 'goo.gl'
+      shortener.name is 'googl'
     $('#googlDeauthorize_btn').click ->
       store.remove key for key in googl.oauthKeys
       $(this).hide()


clean code

clean code

--- lib/watcher.coffee
+++ lib/watcher.coffee
@@ -115,8 +115,8 @@
     delete @errorMarkers

   createErrors: (errors) =>
-    @errorMarkers = for { location, range, message } in errors
     d 'create errors'
+    @errorMarkers = for { range, message } in errors
       marker = @editor.markBufferRange range
       d 'marker', range, marker
       @editor.decorateMarker marker, type: 'highlight', class: 'refactor-error'
@@ -216,9 +216,7 @@
     # Start highlighting life cycle.
     d 'done and reparse'
     @parse()
-    @eventBufferChanged = off
     @eventBufferChanged = on
-    @eventCursorMoved = off
     @eventCursorMoved = on

     # Returns true not to abort keyboard binding.


decreased scatterplot mark size

decreased scatterplot mark size

--- src/coffee/bokeh_views.coffee
+++ src/coffee/bokeh_views.coffee
@@ -14,12 +14,12 @@
     @plot_model = options.plot_model
     @plot_view = options.plot_view
   addPolygon: (x,y) ->
-    @plot_view.ctx.fillRect(x,y,5,5)
+    @plot_view.ctx.fillRect(x,y,2,2)

   addCircle: (x,y) ->
     @plot_view.ctx.beginPath()

-    @plot_view.ctx.arc(x, y, 5, 0, Math.PI*2)
+    @plot_view.ctx.arc(x, y, 2, 0, Math.PI*2)
     @plot_view.ctx.closePath()
     @plot_view.ctx.fill()
     @plot_view.ctx.stroke()


lookup: reject promise on errors (inline lookup data case)

--- src/coffee/transformer.coffee
+++ src/coffee/transformer.coffee
@@ -134,7 +134,7 @@
     if @_disabled or util.nonEmpty(value)
       Q(value)
     else
-      Q.reject new Error("Required Value is empty.")
+      Q.reject new Error("Required value is empty.")

 class UpperCaseTransformer extends ValueTransformer
   @create: (transformers, options) ->
@@ -244,17 +244,17 @@
         @_values = @_headers = values = null
         this
     else
-      # TODO reject promis if columnidx returns an error
-      @_setColumnIdx()
-      @_buildLookupMap()
-      Q(this)
+      Q().then =>
+        @_setColumnIdx()
+        @_buildLookupMap()
+        this

   _setColumnIdx: ->
     @_keyIdx = if _.isString @_keyCol then @_headers.indexOf(@_keyCol) else @_keyCol
     @_valueIdx = if _.isString @_valueCol then @_headers.indexOf(@_valueCol) else @_valueCol

     if @_keyIdx < 0 or @_valueIdx < 0
-      new Error("Something is wrong in lookup config: key '#{@_keyCol}' or value '#{@_valueCol}' column not found by name!.")
+      throw new Error("Something is wrong in lookup config: key '#{@_keyCol}' or value '#{@_valueCol}' column not found by name!.")

   _buildLookupMap: ->
     # create a property map with first occurrence of key (first to stay compatible with the previous _.find based implementation)


fix score rounding

fix score rounding

--- src/helpers/task.coffee
+++ src/helpers/task.coffee
@@ -33,14 +33,14 @@
   getHumanUnacceptedScore: (task) ->
     score = Math.round((
       task.correct_on_time_exercise_count / task.exercise_count
-      ) * 100 ) / 100
-    "#{score * 100}%"
+      ) * 100 )
+    "#{score}%"

   getHumanScoreWithLateWork: (task) ->
     score = Math.round((
       task.correct_exercise_count / task.exercise_count
-      ) * 100) / 100
-    "#{score * 100}%"
+      ) * 100 )
+    "#{score}%"

   getCompletedSteps: (task) ->
     task.completed_on_time_step_count + task.completed_accepted_late_step_count


if EP is given, ignore everything rest

if EP is given, ignore everything rest

--- library/membrane/bower.coffee
+++ library/membrane/bower.coffee
@@ -160,13 +160,14 @@
         locate = (f) -> _.findKey paths, resides(f)
         resides = (f) -> (x) -> f is x or try f in x
         for file in files then do (paths, file) ->
+            bowering = finder null, locate(file)
+            entry = bowering?.entry or undefined
+            assert formatted = "#{file}/#{entry}"
+            context.scripts.push formatted if entry
+            return unless _.isEmpty entry?.toString()
             ext = (e) -> path.extname(file) is e
             context.scripts.push file if ext ".js"
             context.sheets.push file if ext ".css"
-            bowering = finder null, locate(file)
-            entry = bowering?.entry or new String
-            return if _.isEmpty entry.toString()
-            context.scripts.push "#{file}/#{entry}"

     # This server side method is called on the context prior to the
     # context being compiled and flushed down to the client site. The


Fix minor logic mistake

Fix minor logic mistake

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -68,7 +68,7 @@
     # the kernel boots up. With no arguments it launches the stack.
     # This is a convenient way of running additions config routines.
     @configure: (explain, routine) ->
-        if arguments.length is 0 and _.isArray @$configure
+        if arguments.length is 0
             level = (e) -> logger.info "Configuring: %s", e
             fix = (o) -> (a...) -> level o.explain; o.routine a...
             return async.series _.map(@$configure, fix)


:fire: DRY up error handling

:fire: DRY up error handling

--- src/hook-manager.coffee
+++ src/hook-manager.coffee
@@ -46,13 +46,7 @@
           @message.reply reply

     catch e
-      @robot.logger.error util.inspect(e)
-      @message.reply """
-        I encountered an error while adding the GitHub event hook to #{user}/#{repo}
-
-        #{e.message}
-        #{e.stack}
-        """
+      @handleError(e, "adding the GitHub event hook to #{user}/#{repo}")

   # Public: List the web hooks installed on the GitHub repository identified by the `user` and
   # `repo` names.
@@ -64,6 +58,7 @@
       @buildClient(user, repo)
         .get() (error, response, body) =>
           throw error if error
+          throw response if response.statusCode < 200 or response.statusCode >= 300
           @robot.logger.info util.inspect(body)

           reply = switch
@@ -76,13 +71,7 @@
           @message.reply reply

     catch e
-      @robot.logger.error util.inspect(e)
-      @message.reply """
-        I encountered an error while listing the GitHub event hooks on #{user}/#{repo}
-
-        #{e.message}
-        #{e.stack}
-        """
+      @handleError(e, "listing the GitHub event hooks on #{user}/#{repo}")

   # Private: Builds the URL to use for querying the web hook API.
   #
@@ -150,4 +139,21 @@

     output.join("\n")

+  # Private: Handles the error by reporting it with the given message.
+  #
+  # * `error` {Object} describing the error.
+  # * `message` {String} describing what was being done when the error occurred.
+  handleError: (error, message) ->
+    @robot.logger.error util.inspect(error)
+
+    if error.statusCode
+      @message.reply "Server returned: #{error.statusCode} #{error.statusMessage}"
+    else
+      @message.reply """
+        I encountered an error while #{message}
+
+        #{error.message}
+        #{error.stack}
+        """
+
 module.exports = HookManager


copy fix

copy fix

--- client/home/lib/myteam/components/hometeamsendinvites/uploadcsvmodal.coffee
+++ client/home/lib/myteam/components/hometeamsendinvites/uploadcsvmodal.coffee
@@ -186,7 +186,7 @@
       cssClass: 'success-state-label'
       partial: '''
         <p>
-            In your files, we have found…
+            In your file, we have found…
         </p>
       '''


[client][app][activity] simplified logic

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -294,10 +294,9 @@

   fetchCachedActivity:(options = {}, callback)->
     if KD.config.useNeo4j
-      if options.to
-        options.timestamp = options.to
-
+      options.timestamp or= options.to
       options.groupName = KD.getSingleton("groupsController").getCurrentGroup()?.slug or "koding"
+
       KD.remote.api.CStatusActivity.fetchPublicActivityFeed options, (err, result)=>
         result.overview.reverse() if result?.overview
         return callback err, result


translating comments

translating comments

--- src/jquery.atwho.coffee
+++ src/jquery.atwho.coffee
@@ -27,16 +27,17 @@
     TAB: 9
     ENTER: 13

-  # Controller 用于处理渲染数据的一组方法.
-  #为了方便开发者可以自定义插件的部分功能而独立出来.
+  # Functions set for handling and rendering the data.
+  # Others developers can override these methods to tweak At.js such as matcher.
+  # We can override them in `callbacks` settings.
   #
   # @mixin
   #
   # 以下所有方法的调用上下文都是 Controller. 并且按照文档显示的顺序调用
+  # The context of these functions is `$.atwho.Controller` object and they are called in this sequences:
   #
-  # 也就是这个顺序 [data_refactor, matcher, filter, remote_filter, sorter, tpl_evl, highlighter, selector]
+  # [data_refactor, matcher, filter, remote_filter, sorter, tpl_evl, highlighter, selector]
   #
-  # 以默认配置的方式 Mixin 到 Controller 里.
   DEFAULT_CALLBACKS =

     # 用于插件最开始时对设置的数据进行重构.


sweep stuff under the rug

sweep stuff under the rug

--- demo.coffee
+++ demo.coffee
@@ -1,69 +0,0 @@
-
-{Parser, serialise} = require './csx'
-
-start = new Date()
-ast = new Parser().parse '''
-
-<Car doors=4 safety={getSafetyRating()*2} crackedWindscreen = "yep" insurance={ insurancehas() ? 'cool': 'ahh noooo'} data-yolo='swag\\' checked check=me_out />
-
-'''
-"""
-# @jsx React.DOM
-
-<Person name={window.isLoggedIn ? window.name : ''} />
-
-<Person name={window.isLoggedIn
-? window.name
-: \'\'} />
-
-
-<Person name={window.isLoggedIn
-? window.name
-: \'\'}>
-{
-
-  for n in a
-

-      asf
-
{ n+1 }

-

-}
-
-</Person>
-
-<Person name={window.isLoggedIn ? window.name : \'\'}
-loltags='on new line' />
-
-HelloWorld = React.createClass({
-  render: () ->
-    return (
-

-        Hello, <input type="text" placeholder="Your name here" />!
-        It is {this.props.date.toTimeString()}
-

-    );
-});
-
-setInterval(() ->
-  React.renderComponent(
-    <HelloWorld date="{new Date()}" />,
-    document.getElementById('example')
-  );
-, 500);
-
-React.createClass
-  render: ->
-    return
-      {<Profile>click{Math.random(),<Selfclosing coolattr />}</Profile> for i in [start...finish]}
-
-
-
-"""
-console.log 'AST:'
-console.log JSON.stringify(ast, null, 4)
-console.log 'Transformed CSX:'
-console.log serialise ast
-
-end = new Date()
-
-console.log "done in #{end - start}ms"


Fix setValue, render in ListEditor

Fix setValue, render in ListEditor

Closes #3

--- src/editors/extra/list.coffee
+++ src/editors/extra/list.coffee
@@ -52,7 +52,12 @@
       else
         if !@Editor.isAsync
           @addItem()
+      #Save a copy of the pre-exising element, if exists
+      domReferencedElement = @el
       @setElement $el
+      #In case of there was a pre-existing element already placed in the DOM, then update it
+      if domReferencedElement
+        $(domReferencedElement).replaceWith @el
       @$el.attr 'id', @id
       @$el.attr 'name', @key
       if @hasFocus
@@ -148,6 +153,7 @@
       #Filter empty items
       _.without values, undefined, ''
     setValue: (value) ->
+      @items = []
       @value = value
       @render()
       return


Hash session name to prevent guessing

Hash session name to prevent guessing

--- lib/firepad.coffee
+++ lib/firepad.coffee
@@ -1,4 +1,7 @@
+
+Crypto = require 'crypto'
 {View, EditorView} = require 'atom'
+
 Firebase = require 'firebase'
 Firepad = require './firepad-lib'

@@ -47,11 +50,12 @@

   confirm: ->
     shareId = @miniEditor.getText()
+    hash = Crypto.createHash('sha256').update(shareId).digest('base64');
     @detach()
-    @ref = new Firebase('https://atom-firepad.firebaseio.com').child(shareId);
+    @ref = new Firebase('https://atom-firepad.firebaseio.com').child(hash);
     @pad = Firepad.fromAtom @ref, atom.workspace.getActiveEditor(), {sv_: Firebase.ServerValue.TIMESTAMP}
     @view = new ShareView()
-    @view.show(shareId)
+    @view.show()

   unshare: ->
     @pad.dispose()


Added more supplementary signs to `de.cson`

* supplementary_disabled
* supplementary_glaze
* supplementary_both_directions

--- dev/de.cson
+++ dev/de.cson
@@ -103,6 +103,24 @@
     { type: 'content-4', color: 'black', content: 'frei', transform: 'translate(0,45%) scale(.8)'}
   ]

+supplementary_disabled:
+  category: 'supplementary'
+  name: 'for disabled people'
+  elements: [
+    { type: 'square-rounded', color: 'black', transform: 'scale(1,.5)'}
+    { type: 'square-rounded', color: 'white', transform: 'scale(.95, .45)'}
+    { type: 'disabled-p', color: 'black', transform: 'scale(.6)'}
+  ]
+
+supplementary_glaze:
+  category: 'supplementary'
+  name: 'for disabled people'
+  elements: [
+    { type: 'square-rounded', color: 'black', transform: 'scale(1,.5)'}
+    { type: 'square-rounded', color: 'white', transform: 'scale(.95, .45)'}
+    { type: 'snowflake', color: 'black', transform: 'scale(.8)'}
+  ]
+
 supplementary_left_pointing:
   category: 'supplementary'
   name: 'left pointing'
@@ -110,6 +128,16 @@
     { type: 'square-rounded', color: 'black', transform: 'scale(1,.5)'}
     { type: 'square-rounded', color: 'white', transform: 'scale(.95, .45)'}
     { type: 'DE-arrow-up', color: 'black', transform: 'scale(.6) rotate(-90deg)'}
+  ]
+
+supplementary_both_directions:
+  category: 'supplementary'
+  name: 'both directions'
+  elements: [
+    { type: 'square-rounded', color: 'black', transform: 'scale(1,.5)'}
+    { type: 'square-rounded', color: 'white', transform: 'scale(.95, .45)'}
+    { type: 'DE-arrow-up', color: 'black', transform: 'translate(-15%,0) scale(.5) rotate(180deg)'}
+    { type: 'DE-arrow-up', color: 'black', transform: 'translate(15%,0) scale(.5)'}
   ]

 supplementary_pedestrians_use_opposite_sidewalk:


Update US signs metadata

Update US signs metadata

--- dev/us.cson
+++ dev/us.cson
@@ -37,8 +37,8 @@
     { type: 'diamond-bg', value: 'yellow' }
     { type: 'traffic-l-bg', valued: 'black' }
     { type: 'traffic-l-g', valued: 'green' }
+    { type: 'traffic-l-y', valued: 'yellow' }
     { type: 'traffic-l-r', valued: 'red' }
-    { type: 'traffic-l-y', valued: 'yellow' }
   ]

 regulatory_no_parking:
@@ -160,7 +160,7 @@
   name: 'side road perpendicular right'
   elements: [
     { type: 'diamond-bg', value: 'yellow' }
-    { type: 'side-road-p-r', value: 'yellow' }
+    { type: 'side-road-p-r', value: 'black' }
   ]

 regulatory_no_trucks:
@@ -177,7 +177,7 @@
   category: 'warning'
   name: 'turn right'
   elements: [
-    { type: 'diamong-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'yellow' }
     { type: 'turn-90-r', value: 'black' }
   ]

@@ -185,15 +185,15 @@
   category: 'warning'
   name: 'turn left'
   elements: [
-    { type: 'diamong-bg', value: 'yellow' }
-    { type: 'turn-90-u', value: 'black' }
+    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'turn-90-l', value: 'black' }
   ]

 warning_fire_station:
   category: 'warning'
   name: 'fire station'
   elements: [
-    { type: 'diamong-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'yellow' }
     { type: 'fire-station', value: 'black' }
   ]

@@ -201,7 +201,7 @@
   category: 'warning'
   name: 'bicycles'
   elements: [
-    { type: 'diamong-bg', value: 'yellow' }
+    { type: 'diamond-bg', value: 'yellow' }
     { type: 'bicycle fit', value: 'black' }
   ]

@@ -288,7 +288,7 @@

 warning_slippery:
   category: 'warning'
-  name: 'slipper'
+  name: 'slippery'
   elements: [
     { type: 'diamond-bg', value: 'yellow' }
     { type: 'slippery', value: 'black' }
@@ -414,7 +414,7 @@

 warning_workers_in_road_ahead:
   category: 'warning'
-  name: 'workers_in_road_ahead'
+  name: 'workers in road ahead'
   elements: [
     { type: 'diamond-bg', value: 'yellow' }
     { type: 'roadworks', value: 'black' }
@@ -474,8 +474,32 @@
   elements: [
     { type: 'circle-bg', value: 'white' }
     { type: 'circle-o', value: 'red' }
-    { type: 'arrow-up', value: 'black' }
-    { type: 'circle-line-l', value: 'red' }
+    { type: 'arrow-straight', value: 'black' }
+    { type: 'circle-line-l', value: 'red' }
+  ]
+
+warning_added_lane_from_entering_roadway:
+  category: 'warning'
+  name: 'added lane from entering roadway'
+  elements: [
+    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'added-lane-entering-roadway', value: 'black' }
+  ]
+
+warning_flaggers_in_road_ahead:
+  category: 'warning'
+  name: 'flaggers in road ahead'
+  elements: [
+    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'flaggers', value: 'black' }
+  ]
+
+warning_skewed_railroads_crossing:
+  category: 'warning'
+  name: 'skewed railroads crossing'
+  elements: [
+    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'skewed-railroads', value: 'black' }
   ]

 warning_trucks_rollover:
@@ -486,44 +510,12 @@
     { type: 'trucks-rollover', value: 'black' }
   ]

-warning_added_lane_from_entering_roadway:
-  category: 'warning'
-  name: 'added lane from entering roadway'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'added-lane-entering-roadway', value: 'black' }
-  ]
-
-warning_flaggers_in_road_ahead:
-  category: 'warning'
-  name: 'flaggers in road ahead'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'flaggers', value: 'black' }
-  ]
-
-warning_skewed_railroads_crossing:
-  category: 'warning'
-  name: 'skewed railroads crossing'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'skewed-railroads', value: 'black' }
-  ]
-
-warning_trucks_rollover:
-  category: 'warning'
-  name: 'trucks rollover'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'truck-rollover', value: 'black' }
-  ]
-
 warning_lightground_railroad_crossing:
   category: 'warning'
-  name: 'light rail crossing'
-  elements: [
-    { type: 'diamond-bg', value: 'yellow' }
-    { type: 'lightground-rail-crossing', value: 'black' }
+  name: 'lightground railroad crossing'
+  elements: [
+    { type: 'diamond-bg', value: 'yellow' }
+    { type: 'lightground-railroad-crossing', value: 'black' }
   ]

 regulatory_national_network_lane:
@@ -540,7 +532,7 @@
   name: 'motorcycle crossing'
   elements: [
     { type: 'diamond-bg', value: 'yellow' }
-    { type: 'motorcycle', value: 'black' }
+    { type: 'motorbike', value: 'black' }
   ]

 warning_railroad:
@@ -567,7 +559,6 @@
   name: 'truck rollover with speed'
   elements: [
     { type: 'diamond-bg', value: 'yellow' }
-    { type: 'truck-rollover', value: 'black' }
     { type: 'truck-rollover-speed', value: 'black' }
   ]

@@ -610,5 +601,5 @@
   name: 'single 2 reverse curve'
   elements: [
     { type: 'diamond-bg', value: 'yellow' }
-    { type: 's-2-reverse-curve', value: 'black' }
-  ]
+    { type: 'single-2-reverse-curve', value: 'black' }
+  ]


removing unnecessary call

removing unnecessary call

--- src/mixins/list.coffee
+++ src/mixins/list.coffee
@@ -35,7 +35,6 @@
     @listenTo @collection, "sync", @showLoading.bind(@, false)

     @listenTo @, "render:post", =>
-      @showLoading()
       @addAll()

     @listenTo @, "close", (e) =>


Use child_process.spawn

Use child_process.spawn

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -31,10 +31,10 @@
   # Everything past this point relates to CLI helpers as loosly demoed out in:
   #   https://gist.github.com/steelbrain/43d9c38208bf9f2964ab

-  exec: (command, options = {stream: 'stdout'}) ->
+  exec: (command, args = [], options = {stream: 'stdout'}) ->
     throw new Error "Nothing to execute." if not arguments.length
     return new Promise (resolve, reject) ->
-      process = child_process.exec(command, options)
+      process = child_process.spawn(command, args, options)
       options.stream = 'stdout' if not options.stream
       data = []
       process.stdout.on 'data', (d) -> data.push(d.toString()) if options.stream == 'stdout'
@@ -47,13 +47,13 @@

   # This should only be used if the linter is only working with files in their
   #   base directory. Else wise they should use `Helpers#exec`.
-  execFilePath: (command, filePath, options = {}) ->
+  execFilePath: (command, args = [], filePath, options = {}) ->
     throw new Error "Nothing to execute." if not arguments.length
     throw new Error "No File Path to work with." if not filePath
     return new Promise (resolve, reject) ->
       options.cwd = path.dirname(filePath) if not options.cwd
-      command = "#{command} #{filePath}"
-      resolve(Helpers.exec(command, options))
+      args.push(filePath)
+      resolve(Helpers.exec(command, args, options))

   # Due to what we are attempting to do, the only viable solution right now is
   #   XRegExp.


Remove tourbus data from original element when destroying tour.

--- src/modules/bus.coffee
+++ src/modules/bus.coffee
@@ -115,6 +115,7 @@
     @legs = []
     delete @constructor._busses[@id]
     @_teardownEvents()
+    @$original.removeData('tourbus')
     @$el.remove()

   _configureElement: ->


set  for client connections, and add label to JSON errors

--- lib/jsonify.coffee
+++ lib/jsonify.coffee
@@ -3,6 +3,10 @@
 module.exports = (options) ->

   (socket) ->
+    # NOTE:
+    #  net.Server's 'connection' event provides the new socket to the listener
+    #  net.Socket's 'connect' event's `this` *is* the socket
+    socket ?= this

     # build json duplex stream for this connection
     json = jsonify()
@@ -36,10 +40,10 @@
       process.nextTick -> socket.emit 'jsonify', json, socket

     # handle common error responses
-    jsonError = (error) -> console.error 'JSON Error:', error.message
+    jsonError = (which, error) -> console.error "JSON Error[#{which}]:", error.message
     # for both in+out
-    json.in.on 'error', jsonError
-    json.out.on 'error', jsonError
+    json.in.on 'error', jsonError.bind null, 'IN'
+    json.out.on 'error', jsonError.bind null, 'OUT'

     socket.on 'error', (error) ->
       console.error 'Connection error:',error.message


more fixes

more fixes

--- scripts/slugs.coffee
+++ scripts/slugs.coffee
@@ -43,7 +43,7 @@
       "bam-green-eggs-and-h": "green-eggs-and-ham"
       "node-group-tbd": "xyzzy"
       "tmp": "walbril"
-      "software-niagara-tea": "software-niagarateam"
+      "software-niagara-tea": "software-niagara"
       "swhite": "pimps-love"
       "front-end-developers": "fed-brazil"
       "cold-brew-rocket-fue": "brew-rocket-fuel"
@@ -65,16 +65,16 @@
       "streamsters-union612": "streamsters-612"
       "voxelperfect": "band-jamming"
       "alsw": "machinarium"
-      "me-the-intern": "me-and-the-interns"
+      "me-the-interns": "me-and-the-interns"
       "imsowitty": "axias"
       "gus-gorman-for-presi": "gus-gorman-for-prez"
       "tem-lazors": "camarinhas"
       "juggabots": "cool-ladies-gif"
-      "klandestino": "klandestino"
+      "klandestino-ab": "klandestino"
       "jedi-knights": "throw-42"
       "node-rt": "nko-analytics"
       "restort": "the-tickeros"
-      "tmp-1": "hundred-ten"
+      "tmp-1": "fifty-five"
       "turbo-team": "nodespots"
       "parmenides": "heraclitus"
       "andrew-in-demton": "time-ghost"
@@ -98,6 +98,7 @@
       "rde": "rome-team"
       "team-neo": "cornerstone-sys"
       "its-always-been-brok": "always-broken"
+      "figure-it-out-guys": "makeshift"

     if team.name == "ヽ( ´¬`)ノ" #special that there was no slug previously


Get rid of setup

Get rid of setup

--- drop.coffee
+++ drop.coffee
@@ -121,11 +121,6 @@
             options.attachSecond = attachSplit[1]

         $target.data 'drop', options
-        $target.drop 'setup'
-
-    setup: ->
-        $target = $ @
-        options = $target.data().drop

         $target.drop 'setupElements'
         $target.drop 'setupEvents'


Parse relative M properly

Parse relative M properly

--- src/path-parser.coffee
+++ src/path-parser.coffee
@@ -30,7 +30,10 @@

   # make relative points absolute based on currentPoint
   makeAbsolute = (array) ->
-    (val + currentPoint[i % 2] for val, i in array)
+    if currentPoint?
+      (val + currentPoint[i % 2] for val, i in array)
+    else
+      array

   # Create a node and add it to the list. When the last node is the same as the
   # first, and the path is closed, we do not create the node.
@@ -68,10 +71,16 @@
     switch command.type
       when 'M', 'm'
         # Move to
-        params = command.parameters
-        params = makeAbsolute(params) if command.type == 'm'
-        currentPoint = params
-        addNewSubpath(currentPoint)
+        hasMoved = false
+        setSize = 2
+        isRelative = command.type == 'm'
+        iterateOverParameterSets command, setSize, isRelative, (paramSet) ->
+          if hasMoved
+            createNode(paramSet, i)
+          else
+            hasMoved = true
+            currentPoint = paramSet
+            addNewSubpath(currentPoint)

       when 'L', 'l'
         # Line to


Fix a symlink search bug

Fix a symlink search bug

--- src/path-scanner.coffee
+++ src/path-scanner.coffee
@@ -99,6 +99,8 @@
     stat = fs.lstatSync(filePath)

     if @options.follow and stat.isSymbolicLink()
+      if fs.realpathSync(filePath).search(@rootPath) is 0
+        return null
       try
         stat = fs.statSync(filePath)
       catch e


Replace this with @

Replace this with @

--- src/flux/learning-guide.coffee
+++ src/flux/learning-guide.coffee
@@ -56,8 +56,8 @@
   loaded: (obj, id, {roleId}) ->
     @_asyncStatus[id] ||= {}
     @_asyncStatus[id][roleId] = 'LOADED'
-    this._local[id]   ||= {}
-    this._local[id][roleId] = obj
+    @_local[id]   ||= {}
+    @_local[id][roleId] = obj
     @emitChange()

   load: (id, {roleId}) ->


Improved human text.

Improved human text.

--- app/assets/javascripts/app/controllers/_ui_element/ticket_selector.js.coffee
+++ app/assets/javascripts/app/controllers/_ui_element/ticket_selector.js.coffee
@@ -84,9 +84,10 @@
     )

     # build inital params
-    if !_.isEmpty(params.condition)
+    if !_.isEmpty(params[attribute.name])
+
       selectorExists = false
-      for groupAndAttribute, meta of params.condition
+      for groupAndAttribute, meta of params[attribute.name]
         if groupAndAttribute isnt 'attribute'
           selectorExists = true
           operator = meta.operator
@@ -268,18 +269,11 @@

       # get stored params
       if meta && objectAttribute[1]
-        selectorExists = true
         operator = meta.operator
         value = meta.value
         model = toCamelCase(objectAttribute[0])
-        modelAttribute = objectAttribute[1]
-
         config = elements[attribute]

-        if modelAttribute.substr(modelAttribute.length-4,4) is '_ids'
-          modelAttribute = modelAttribute.substr(0, modelAttribute.length-4)
-        if modelAttribute.substr(modelAttribute.length-3,3) is '_id'
-          modelAttribute = modelAttribute.substr(0, modelAttribute.length-3)
         valueHuman = []
         if _.isArray(value)
           for data in value
@@ -287,7 +281,10 @@
             valueHuman.push r
         else
           valueHuman.push @humanTextLookup(config, value)
-        rules.push "#{App.i18n.translateContent('Where')} #{App.i18n.translateContent(model)} -> #{App.i18n.translateContent(toCamelCase(modelAttribute))} #{App.i18n.translateContent(operator)} #{valueHuman}."
+
+        if valueHuman.join
+          valueHuman = valueHuman.join(', ')
+        rules.push "#{App.i18n.translateContent('Where')} #{App.i18n.translateContent(model)} -> #{App.i18n.translateContent(config.display)} #{App.i18n.translateContent(operator)} #{valueHuman}."

     return [none] if _.isEmpty(rules)
     rules


Teamwork: Implemented README modal for FacebookTeamwork.

--- client/app/Applications/Teamwork.kdapplication/Views/facebookteamwork.coffee
+++ client/app/Applications/Teamwork.kdapplication/Views/facebookteamwork.coffee
@@ -154,3 +154,11 @@
         </body>
       </html>
     """
+
+  showHintModal: ->
+    editor = @getActivePanel().getPaneByName "editor"
+    file   = editor.getActivePaneFileData()
+    readme = FSHelper.createFileFromPath "#{file.parentPath}/README.md"
+    readme.fetchContents (err, content) =>
+      return  unless content
+      @getDelegate().showMarkdownModal content


add autoFetch to the content migration issues list

fixes ADMIN-627

test plan:
- do an import that generates more than 10 errors
  - an example import file is attached to the jira ticket
- with a tall browser window:
  - expand the list of issues. Issues should be fetched while there is
    room in the browser window, or until all issues have been fetched.

Change-Id: I908572f06f5a988afd5c301343d21a426acfb9ab
Reviewed-on: https://gerrit.instructure.com/138502
Tested-by: Jenkins
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
QA-Review: Deepeeca Soundarrajan <5bcd4b623f00b7fc2942cd1c65c245b30a48a61f@instructure.com>
Product-Review: Jon Willesen <0321efbc0acf6204eb6035acb1d418838b450d08@instructure.com>

--- app/coffeescripts/views/content_migrations/ProgressingContentMigrationView.coffee
+++ app/coffeescripts/views/content_migrations/ProgressingContentMigrationView.coffee
@@ -96,6 +96,7 @@
                          collection: @issues
                          itemView: ContentMigrationIssueView
                          template: progressingIssuesTemplate
+                         autoFetch: true
       @$migrationIssues.html issuesCollectionView.render().el

       progressStatus = new ProgressStatusView


removing commented lines

removing commented lines

--- shared/syncer.coffee
+++ shared/syncer.coffee
@@ -58,8 +58,6 @@
   ret = _.extend {}, params,
     locale:       app.State.get('locale')
     currency:     app.State.get('currency')
-  # oauth_token = app.SessionManager.get('access_token')
-  # ret.oauth_token = oauth_token if oauth_token?

   # So, by default Backbone sends all of the model's
   # attributes if we don't pass any in explicitly.


use window.AudioContext if you have it

use window.AudioContext if you have it

--- src/scripts/viz.coffee
+++ src/scripts/viz.coffee
@@ -1,6 +1,7 @@

 w = window
 requestFrame = w.requestAnimationFrame or w.mozRequestAnimationFrame or w.webkitRequestAnimationFrame or w.oRequestAnimationFrame
+AudioContext = window.AudioContext or window.webkitAudioContext
 noop = ->

 class Repeater
@@ -40,7 +41,7 @@
       throw "No <canvas> element found inside ##{id}"

     @canvasContext = @canvas.getContext '2d'
-    audioContext = new webkitAudioContext
+    audioContext = new AudioContext
     @analyser = audioContext.createAnalyser()

     # Wire the audio into the analyser


minor debugging improvement

minor debugging improvement

--- lib/request.coffee
+++ lib/request.coffee
@@ -31,6 +31,7 @@
     args.push(cb)

     # Check we have have the correct number of params
+    throw ['callback_missing',    "The #{action} action is missing the callback argument"]        if method.length == 0
     throw ['params_missing',      "The #{action} action expects params but none were sent"]       if method.length > args.length
     throw ['params_not_required', "The #{action} action was sent params but can't receive them"]  if method.length < args.length


Fixed deprecated warnings in server.iced

--- src/server/server.iced
+++ src/server/server.iced
@@ -25,7 +25,7 @@
 app.use bodyParser.json()
 app.use bodyParser.urlencoded extended: true
 app.use cookieParser "TODO: replace me with some more random string"
-app.use session { secret: "TODO: replace me again with more randomness", key: "session", cookie: { maxAge: 86400000 } } # <- 1d
+app.use session { resave: true, saveUninitialized: true, secret: "TODO: replace me again with more randomness", key: "session", cookie: { maxAge: 86400000 } } # <- 1d
 app.use passport.initialize()
 app.use passport.session()


Destroy ref markers before parse, and create ref markers after parse

--- lib/watcher.coffee
+++ lib/watcher.coffee
@@ -84,6 +84,7 @@

   parse: =>
     @editorView.off 'cursor:moved', @onCursorMoved
+    @destroyReferenceMarkers()
     @destroyErrorMarkers()
     text = @editor.buffer.getText()
     if text isnt @cachedText
@@ -101,7 +102,7 @@
   onParseEnd: (errors) =>
     if errors?
       @createErrorMarkers errors
-    @updateReferences()
+    @createReferenceMarkers @ripper.find @editor.getSelectedBufferRange().start
     @editorView.off 'cursor:moved', @onCursorMoved
     @editorView.on 'cursor:moved', @onCursorMoved

@@ -119,11 +120,6 @@
       @editor.decorateMarker marker, type: 'highlight', class: 'refactor-error'
       @editor.decorateMarker marker, type: 'gutter', class: 'refactor-error'
       marker
-
-  updateReferences: =>
-    @destroyReferenceMarkers()
-    ranges = @ripper.find @editor.getSelectedBufferRange().start
-    @createReferenceMarkers ranges

   destroyReferenceMarkers: ->
     return unless @markers?
@@ -198,7 +194,11 @@

   onCursorMoved: =>
     clearTimeout @cursorMovedTimeoutId
-    @cursorMovedTimeoutId = setTimeout @updateReferences, 0
+    @cursorMovedTimeoutId = setTimeout @onCursorMovedAfter, 0
+
+  onCursorMovedAfter: =>
+    @destroyReferenceMarkers()
+    @createReferenceMarkers @ripper.find @editor.getSelectedBufferRange().start

   ###


logging removed

logging removed

--- client/landing/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeBin.coffee
+++ client/landing/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeBin.coffee
@@ -85,7 +85,6 @@
         @codeBinResultView.show()
         @resultBanner.hide()
         @codeBinCloseButton.show()
-        log @getData()
         @codeBinResultView.emit "CodeBinSourceHasChanges", @getData()


enhancement: don't add dual figures to library

--- scripts-src/application.coffee
+++ scripts-src/application.coffee
@@ -433,7 +433,7 @@
             if result=Cells.analyze(pattern, rule, maxSteps)
               if result.period?
                 if result.dx isnt 0 or result.dy isnt 0
-                  @library.put result
+                  @library.put result, @gol.rule
             null
           try
             reseed_period = parseInt E("catcher-reseed-period").value, 10
@@ -520,7 +520,7 @@

       analysisResultToLibrary: ->
         if @analysis_result?
-          @library.put @analysis_result
+          @library.put @analysis_result, @gol.rule

       copyToBuffer: ->
         @analysis_result = null
@@ -1009,9 +1009,21 @@
       {@library_body} = dom.vars
       @div.appendChild dom.finalize()

-    put: (result)->
+    put: (result, rule)->
       return unless result?
       rle = Cells.to_rle result.cells
+
+      unless rle of @key2result
+        if result.dx!=0 or result.dy!=0
+          [dual_pattern, dx1, dy1] = Cells.getDualSpaceship result.cells, rule, result.dx, result.dy
+          if dual_pattern?
+            dual_rle = Cells.to_rle dual_pattern
+            if dual_rle of @key2result
+              result.cells = dual_pattern
+              result.dx = dx1
+              result.dy = dy1
+              rle = dual_rle
+
       record = (
           result: result
           count: 1
@@ -1031,8 +1043,8 @@
       return (rle of @key2result)
     hasDual: (result, rule)->
       if result.dx?
-        rle = Cells.getDualSpaceship result.cells, rule, result.dx, result.dy
-        rle of @key2result
+        [dual_pattern, dx1, dy1] = Cells.getDualSpaceship result.cells, rule, result.dx, result.dy
+        (Cells.to_rle dual_pattern) of @key2result
       else
         false


Flesh out .isModified implementation

Flesh out .isModified implementation

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -430,7 +430,11 @@
   # If the buffer is unsaved, always returns `true` unless the buffer is empty.
   #
   # Returns a {Boolean}.
-  isModified: -> @buffer.isModified()
+  isModified: ->
+    if @file?.existsSync()
+      @buffer.isModified()
+    else
+      @buffer.getLength() > 0

   # Public: Determine if the in-memory contents of the buffer conflict with the
   # on-disk contents of its associated file.


WIP Update ::finishLoading to pass changes to emitDidChangeTextEvent

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -1778,7 +1778,7 @@
       @emitDidChangeEvent(changeEvent)
       markerSnapshot = @createMarkerSnapshot()
       @history.groupChangesSinceCheckpoint(checkpoint, {markerSnapshot: markerSnapshot, deleteCheckpoint: true})
-      @emitDidChangeTextEvent(patch)
+      @emitDidChangeTextEvent(patch.getChanges())
       @emitMarkerChangeEvents(markerSnapshot)
       @emitModifiedStatusChanged(@isModified())


Remove link to private method

Remove link to private method

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -42,7 +42,8 @@
   # Public: Create a new buffer with the given params.
   #
   # params - A {String} of text or an {Object} with the following keys:
-  #   :load - A {Boolean}, `true` to call {.load} during initialization.
+  #   :load - A {Boolean}, `true` to asynchronously load the buffer from disk
+  #           after initialization.
   #   :text - The initial {String} text of the buffer.
   constructor: (params) ->
     text = params if typeof params is 'string'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_effect.coffee
+++ src/text_effect.coffee
@@ -20,9 +20,7 @@
 ###

 ###*
-Updates the position of the text based on the effect velocity. Updates the
-alpha based on the elapsed time since the effect creation. If rotationalVelocity
-is provided then the text rotation is updated as well.
+Game

 @name update
 @methodOf TextEffect#


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_effect.coffee
+++ src/text_effect.coffee
@@ -5,7 +5,7 @@
 returned immediately. Even though it has a draw method it will not
 draw anything to the screen until the image has been loaded.

-@name Text
+@name TextEffect
 @constructor
 ###
 TextEffect = (I={}) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/text_screen.coffee
+++ src/text_screen.coffee
@@ -24,6 +24,7 @@
     @methodOf TextScreen#
     @param {PixieCanvas} canvas The canvas to draw on
     @param {String} text The text to draw
+    @param {}
     ###
     centerText: (canvas, text, options={}) ->
       font = options.font || I.font


Update AST requirements

Update AST requirements

--- spec/compiler.coffee
+++ spec/compiler.coffee
@@ -37,14 +37,12 @@
         '#box2'
       ],
       vars: [
-        ['get', 'grid-height']
-        ['get', 'width', ['$', '#box2']]
+        ['get', 'grid-height', 'grid-height']
+        ['get', '#box2[width]','width', ['$id', '#box2']]
       ],
       constraints: [
         ['lte', [
-          'multiply', ['get', 'grid-height'], ['get', 'width', [
-            '$', '#box2'
-          ]]
+          'multiply', ['get', 'grid-height'], ['get', '#box2[width]']
         ], ['number', 2]]
         ['eq', ['number', 2], ['number', 3]]
         ['lt', ['number', 3], ['number', 4]]
@@ -83,14 +81,11 @@
         '#box'
       ]
       vars: [
-        ['get', 'width', [
-          '$', '#box']]
+        ['get', '#box[width]', 'width', ['$id', '#box']]
         ['get', 'grid-height']
       ]
       constraints: [
-        ['stay', ['get', 'width', [
-          '$', '#box']
-        ], ['get', 'grid-height']]
+        ['stay', ['get', '#box[width]'], ['get', 'grid-height']]
       ]
     result = null
     it 'should be able to produce a result', ->


update to latest JIRA API

update to latest JIRA API

On JIRA 5.1, the previous code gave the following error:
ERROR SyntaxError: Unexpected token <

--- src/scripts/jira-issues.coffee
+++ src/scripts/jira-issues.coffee
@@ -18,7 +18,7 @@
   jiraUrl = "https://" + jiraDomain
   http = require 'https'

-  http.get {host: jiraDomain, path: "/rest/api/2.0.alpha1/project"}, (res) ->
+  http.get {host: jiraDomain, path: "/rest/api/latest/project"}, (res) ->
     data = ''
     res.on 'data', (chunk) ->
       data += chunk.toString()
@@ -36,11 +36,11 @@
             cache.shift() until cache.length is 0 or cache[0].expires >= now
           if cache.length == 0 or (item for item in cache when item.issue is issue).length == 0
             cache.push({issue: issue, expires: now + 120000})
-            msg.http(jiraUrl + "/rest/api/2.0.alpha1/issue/" + issue)
+            msg.http(jiraUrl + "/rest/api/latest/issue/" + issue)
               .get() (err, res, body) ->
                 try
                   key = JSON.parse(body).key
-                  msg.send "[" + key + "] " + JSON.parse(body).fields.summary.value
+                  msg.send "[" + key + "] " + JSON.parse(body).fields.summary
                   urlRegex = new RegExp(jiraUrl + "[^\\s]*" + key)
                   if not msg.message.text.match(urlRegex)
                     msg.send jiraUrl + "/browse/" + key


Elaborate a couple tests

Elaborate a couple tests

--- spec/git-spec.coffee
+++ spec/git-spec.coffee
@@ -6,13 +6,13 @@

 describe "Git-Plus git module", ->
   describe "git.getRepo", ->
-    it "returns a promise", ->
+    it "returns a promise resolving to repository", ->
       waitsForPromise ->
         git.getRepo().then (repo) ->
           expect(repo.getWorkingDirectory()).toContain 'git-plus'

   describe "git.dir", ->
-    it "returns a promise", ->
+    it "returns a promise resolving to absolute path of repo", ->
       waitsForPromise ->
         git.dir().then (dir) ->
           expect(dir).toContain 'git-plus'


Add command to restart Spotify client.

Add command to restart Spotify client.

--- src/scripts/spot.coffee
+++ src/scripts/spot.coffee
@@ -23,6 +23,7 @@
 #   hubot say <message> - Tells hubot to read a message aloud.
 #   hubot find <song> - See if Spotify knows about a song without attempting to play it.
 #   hubot airplay <Apple TV> - Tell Spot to broadcast to the specified Apple TV.
+#   hubot spot - Start or restart the Spotify client.
 #
 # Author:
 #   mcminton
@@ -107,4 +108,8 @@
   robot.respond /airplay (.*)/i, (message) ->
     params = {atv: message.match[1]}
     spotRequest message, '/airplay', 'put', params, (err, res, body) ->
-      message.send("#{body} :mega:")+      message.send("#{body} :mega:")
+
+  robot.respond /spot/i, (message) ->
+    spotRequest message, '/airplay', 'put', {}, (err, res, body) ->
+      message.send(body)


Vor der Darstellung der Route wird die alte Route gelöscht.

--- src/main/coffee/script.coffee
+++ src/main/coffee/script.coffee
@@ -138,6 +138,7 @@
     $("#directions").html("

" + directions.join("

") + "

")

   drawDirections = (directions) ->
+    directionsLayer.removeAllFeatures()
     sourceNode = directions[0].nodes[0]
     sourcePoint = new OpenLayers.Geometry.Point(sourceNode.longitude, sourceNode.latitude)
       .transform(EPSG4326Projection, map.getProjectionObject())
@@ -165,7 +166,6 @@
       }
     )
     directionsLayer.addFeatures([sourceFeature, targetFeature])
-    map.zoomToExtent(directionsLayer.getDataExtent())

   enable = (elementId) ->
     $("##{ elementId }").prop("disabled", false)
@@ -193,7 +193,6 @@
               }
             )
         nodesLayer.addFeatures(features)
-        map.zoomToExtent(nodesLayer.getDataExtent())

   retrieveDirections = () ->
     destination = $("#destination").val()
@@ -210,7 +209,6 @@
     $.get "ways",
       (ways) ->
         addWaysToLayer(ways, waysLayer)
-        map.zoomToExtent(waysLayer.getDataExtent())

   setNode = (input) ->
     id = nodesLayer.selectedFeatures.length > 0 and nodesLayer.selectedFeatures[0].attributes.node.id


fix receiver parsing to allow non-pointers

--- grammar.coffee
+++ grammar.coffee
@@ -277,7 +277,7 @@
     method_decl: -> seq(
       keyword("func"),
       @receiver, @method_name, choice(@function, @signature))
-    receiver: -> seq("(", optional(@_identifier), optional("*", @base_type_name), ")")
+    receiver: -> seq("(", optional(@_identifier), optional("*"), @base_type_name, ")")
     base_type_name: -> @_identifier

     labeled_stmt: -> seq(@label, ":", @statement)


Do not send findMistake results to stats

--- server/cron/sendMetrics.coffee
+++ server/cron/sendMetrics.coffee
@@ -10,7 +10,8 @@
         ps: {ps: 1}
     metrics = {}
     for key, query of queries
-        query["total"] = 1
+        query.total = 1
+        query.findMistake = null
         query.activated = true
         for group, _ of GROUPS
             query["userList"] = group


[neo4j] fixed invalid date exception

[neo4j] fixed invalid date exception

--- server/lib/server/index.coffee
+++ server/lib/server/index.coffee
@@ -99,10 +99,8 @@
 _fetchActivitiesByTimestamp = (req, res)->
   graph = new Graph neo4j
   #calculate the current and next timestamp
-  timestamp = req.params?.timestamp
-  if not timestamp
-    timestamp = new Date
-
+
+  timestamp = if req.params?.timestamp? then parseInt(req.params.timestamp, 10) else new Date
   startDate = new Date timestamp
   #20*60*1000 = 1200000
   endDate = new Date(startDate.getTime() + 1200000);
@@ -112,7 +110,7 @@
     GraphDecorator.decorateSingle rawResponse, (decorated)->
       res.send decorated

-app.get "/-/cache/apps", (req, res)->
+app.get "/-/cache/latest", (req, res)->
   _fetchActivitiesByTimestamp req, res

 app.get "/-/cache/before/:timestamp", (req, res)->


Fix for resources model

Fix for resources model

This whole file should be considered for deprecation - not sure anyone
uses this any more

--- server/models/resources.coffee
+++ server/models/resources.coffee
@@ -16,11 +16,10 @@
       resourceType =
         name: val.name
         systemId: systemId
-      crud.update resourceType
+      crud.update val._id
       , resourceType
-      , {upsert: true}
       , cb

   exports = common.extend {}, crud
   exports.registerTypes = registerTypes
-  exports+  exports


auto pin mode

auto pin mode

--- grovepi.coffee
+++ grovepi.coffee
@@ -27,11 +27,7 @@
 		output: 1
 	}

-	getCmd = (id) ->
-		for cmd, cmdId of CMD
-			if cmdId is id
-				break
-				cmd
+	getCmd = (id) -> cmd  if cmdId is id  for cmdId, cmd  of CMD

 	constructor: (@address, @id) ->


Enable private message test suite

Enable private message test suite

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -35,7 +35,7 @@
   ]

   [
-    # { name: 'messages privatemessage' }
+    { name: 'messages privatemessage' }
     { name: 'account accountsettings' }
     { name: 'activity postwith' }
   ]


Added a couple of comments to improve code readability

--- priceInfo.coffee
+++ priceInfo.coffee
@@ -41,12 +41,14 @@
 	iconDiv = "

"
 	priceRDiv = price 'priceR', 1, 64

+	# horizontally centers the box according to its content relative to the product
 	positionBox = (product) ->
 		box = product.data 'infobox'
 		pos = product.position()
 		box.css 'left', pos.left + (product.width() - box.width())/2
 		box.css 'top', pos.top + product.height()
 		box.fadeIn 'fast'
+	# shows the box. Called as event handler on mouseover
 	showInfoBox = ->
 		product = $(this)
 		box = product.data 'infobox'
@@ -67,45 +69,67 @@
 			$('form input', box).change changeAmount
 			product.data 'infobox', box
 		positionBox product
+	# hides the box. Called as event handler on mouseout
 	hideInfoBox = ->
 		product = $(this)
 		product.data('infobox').fadeOut 'fast' unless product.data 'pinned'
+	# pin the box when the user clicks the product
 	pinInfoBox = ->
+		# only one box can be pinned simultaneously
 		if pinnedBox
 			if pinnedBox isnt this
+				# close the currently opened box
 				box = pinnedBox
 				pinInfoBox.apply box
 				hideInfoBox.apply box
 				pinnedBox = this
 			else
+				# the last box will be unpinned
 				pinnedBox = null
 		else
+			# there's no other box opened right now
 			pinnedBox = this
 		product = $(this)
+		# invert pinned-state
 		pinned = not product.data 'pinned'
 		product.data('pinned', pinned)
 		infobox = product.data 'infobox'
+		# show more information while the box is pinned, hide a placeholder
 		$('.toggle', infobox).toggle()
+		# there's more content, so the position needs to be adjusted
 		positionBox product
+	# the user changed something in the form. Called as event handler by the radio buttons and the number box
 	changeAmount = ->
 		form = $(this).closest 'form'
 		product = form.parent().data('product')
 		ninput = $('input[type=number]', form)
 		amount = ninput.val()
+		# hide the results when the user sets 0
 		unless +amount
+			# add the "click me"-hint
 			form.siblings('.siminfo').addClass 'toggle'
+			# hide result
 			form.siblings('.price').hide()
+			# reset highlight
 			product.css 'background-color', 'transparent'
+			# we don't need to calculate anything then
 			return
+		# hide the "click me"-hint
 		form.siblings('.siminfo').removeClass 'toggle'
+		# either + for sell or - for buy
 		mode = $('input:radio:checked', form).val()
+		# contains amount and tax needed for price calculations
 		pdata = product.data('pdata')
 		# enough in stock?
 		if mode is '-' and pdata.amount < amount
+			# set to the highest possible value
 			amount = pdata.amount
 			ninput.val amount
+		# calculate price by combining the sign with the amount (both strings) and casting to a number
 		price = getPrice +(mode+amount), pdata.amount, pdata.tax
+		# output below the form
 		form.siblings('.price').show().text priceFormat price
+		# highlight the product
 		product.css 'background-color', 'yellow'

 	return $('
' + priceLDiv + iconDiv + priceRDiv + '
')


fix missing proxy in alpinist module

fix missing proxy in alpinist module

 On branch master
	modified:   alpinist.coffee

--- alpinist.coffee
+++ alpinist.coffee
@@ -1,5 +1,7 @@
 serverutil = require './lib/serverutil'
 modStack   = require './lib/third_party/stack/stack'
+
+exports.ProxyProcessor = serverutil.ProxyProcessor

 manager = new serverutil.Manager()


use empty object as default

use empty object as default

--- shared/src/helpers/task.coffee
+++ shared/src/helpers/task.coffee
@@ -62,7 +62,7 @@
   "#{settingKey}#{TYPE_SEPARATOR}#{taskType}"

 isPlacedHere = (settingKey, step) ->
-  settings = UiSettings.get(settingKey)
+  settings = UiSettings.get(settingKey) or {}
   settings = settings.placement or settings
   step.task_id is settings.taskId and step.id is settings.stepId


sending all events to particles

sending all events to particles

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -38,4 +38,5 @@
   every: (period, fn) ->
     I.everyEvents.push
       fn: fn
-      every: period+      every: period
+


Clampable#clampToBounds

Clampable#clampToBounds

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -11,7 +11,7 @@

   ###*
   @name clampToBounds
-  @methodOf Clamp
+  @methodOf Clampable#
   ###
   clampToBounds: (bounds) ->
     bounds ||= Rectangle x: 0, y: 0, width: App.width, height: App.height


make require style consistent

make require style consistent

--- src/cli/index.coffee
+++ src/cli/index.coffee
@@ -37,10 +37,10 @@
 options = optimist.argv

 if options['update-selenium']
-  (require 'selenium-download').update BIN_PATH, ->
+  require('selenium-download').update BIN_PATH, ->
     process.exit(0)
 else if options['force-update']
-  (require 'selenium-download').forceUpdate BIN_PATH, ->
+  require('selenium-download').forceUpdate BIN_PATH, ->
     process.exit(0)
 else if options.help
   console.log optimist.help()


Add mocha context snippet

Add mocha context snippet

--- Atom/snippets.cson
+++ Atom/snippets.cson
@@ -22,3 +22,10 @@
         $1
       })
     """
+  'Mocha Context':
+    'prefix': 'context'
+    'body': """
+      context('$1', function() {
+        $2
+      })
+    """


Add -vv option to enable silly logging from cli

--- src/cli/index.coffee
+++ src/cli/index.coffee
@@ -62,7 +62,10 @@
     process.exit 0

   if argv.verbose
-    logger.transports.cli.level = 'verbose'
+    if '-vv' in process.argv
+      logger.transports.cli.level = 'silly'
+    else
+      logger.transports.cli.level = 'verbose'

   if argv.quiet
     logger.transports.cli.quiet = true


handle uploads with post to server

handle uploads with post to server

--- source/javascripts/dante/tooltip.js.coffee
+++ source/javascripts/dante/tooltip.js.coffee
@@ -34,8 +34,8 @@

   insertTemplate: ()->
     "

-

-

+

+

@@ -142,7 +142,6 @@

   displayAndUploadImages: (file)->
     @displayCachedImage file
-    @uploadFile file

   imageSelect: (ev)->
     $selectFile = $('<input type="file" multiple="multiple">').click()
@@ -168,9 +167,13 @@
       img_tag.height = i.height
       img_tag.width  = i.width
       unless i.width is 0 || i.height is 0
-        $('img.graf-image').parent(".aspectRatioPlaceholder").css
+        utils.log "UPLOADED SHOW FROM CACHE"
+
+        replaced_node.find(".aspectRatioPlaceholder").css
           'max-width': i.width
           'max-height': i.height
+
+        @uploadFile file, replaced_node

     reader.readAsDataURL(file)

@@ -193,7 +196,10 @@
         @displayAndUploadImages(file)
       i++

-  uploadFile: (file)=>
+  uploadFile: (file, node)=>
+    n = node
+    handleUp = (jqxhr)=>
+      @uploadCompleted jqxhr, n

     $.ajax
       type: "post"
@@ -204,9 +210,12 @@
         xhr
       cache: false
       contentType: false
-      complete: (jqxhr) =>
-        @uploadCompleted jqxhr
+
+      success: (response) =>
+        handleUp(response)
         return
+      error: (jqxhr)=>
+        utils.log("ERROR: got error uploading file #{jqxhr.responseText}")

       processData: false
       data: @formatData(file)
@@ -223,8 +232,9 @@
       utils.log "complete"
       utils.log complete

-  uploadCompleted: (jqxhr)=>
-    utils.log jqxhr
+  uploadCompleted: (url, node)=>
+    node.find("img").attr("src", url)
+    #return false

   ## EMBED
   displayEmbedPlaceHolder: ()->


Teamwork: Minor MR fix, code styling.

Teamwork: Minor MR fix, code styling.

--- client/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -68,9 +68,7 @@
       @emit "WorkspaceSyncedWithRemote"

   bindRemoteEvents: ->
-    if @amIHost() then @syncWorkspace()
-    else
-      @requestPingFromHost()
+    if @amIHost() then @syncWorkspace() else @requestPingFromHost()

     @usersRef.on "child_added", (snapshot) =>
       @fetchUsers()


Use modern signal/slot mechanism

Use modern signal/slot mechanism

--- client/Framework/components/tabs/KDTabViewController.coffee
+++ client/Framework/components/tabs/KDTabViewController.coffee
@@ -70,7 +70,7 @@
       false

   removePane:(pane)->
-    pane.handleEvent type : "KDTabPaneDestroy"
+    pane.emit "KDTabPaneDestroy"
     index = @getPaneIndex pane
     isActivePane = @getActivePane() is pane
     @panes.splice(index,1)


Client: Activity: Feed: Added getMarkUserIMenuItem  method to set menu item by isOwnerExempt state

--- client/activity/lib/components/messageitemmenu/index.coffee
+++ client/activity/lib/components/messageitemmenu/index.coffee
@@ -164,26 +164,26 @@
     ]

-  getAdminMenuItems: ->
-
-    { message } = @props
+  getMarkUserMenuItem: ->
+
     markUserMenuItem =
       key: 'markuserastroll',
       title: 'Mark User as Troll',
       onClick: @bound 'showMarkUserAsTrollPromptModal'

-    getMessageOwner message.toJS(), (err, owner) =>
-
-      return showErrorNotification err  if err
-
-      if owner.isExempt
-        markUserMenuItem =
-          key: 'unmarkuserastroll',
-          title: 'Unmark User as Troll',
-          onClick: @bound 'unMarkUserAsTroll'
+    if @state.isOwnerExempt
+      markUserMenuItem =
+        key: 'unmarkuserastroll',
+        title: 'Unmark User as Troll',
+        onClick: @bound 'unMarkUserAsTroll'
+
+    return markUserMenuItem
+
+
+  getAdminMenuItems: ->

     adminMenuItems = [
-      markUserMenuItem
+      @getMarkUserMenuItem()
       {
         title   : 'Block User'
         key     : 'blockuser'


Remove onReady to prevent additional trip to server

--- client/controllers/curatorInbox/curatorSourceDetails.coffee
+++ client/controllers/curatorInbox/curatorSourceDetails.coffee
@@ -69,17 +69,16 @@
           $title.tooltip('hide').attr('data-original-title', '')
         else
           $title.attr('data-original-title', title)
-      @subscribe 'ArticleIncidentReports', source.url,
-        onReady: ->
-          if source.enhancements?.dateOfDiagnosis
+      @subscribe 'ArticleIncidentReports', source.url
+      if source.enhancements?.dateOfDiagnosis
+        instance.incidentsLoaded.set(true)
+      else
+        Meteor.call 'getArticleEnhancementsAndUpdate', source, (error, enhancements) =>
+          if error
+            notify('error', error.reason)
+          else
+            source.enhancements = enhancements
             instance.incidentsLoaded.set(true)
-          else
-            Meteor.call 'getArticleEnhancementsAndUpdate', source, (error, enhancements) =>
-              if error
-                notify('error', error.reason)
-              else
-                source.enhancements = enhancements
-                instance.incidentsLoaded.set(true)

 Template.curatorSourceDetails.onDestroyed ->
   $(window).off('resize')


Fix credits console logging

Fix credits console logging


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/collision.coffee
+++ src/collision.coffee
@@ -221,7 +221,7 @@
             xw: target.width/2
             yw: target.height/2
         else
-          error ""
+          error "Bounds object"
           return

       xw = target.xw


removed playground file

removed playground file

--- coffee/test.coffee
+++ coffee/test.coffee
@@ -1,30 +0,0 @@
-class App
-    name: 'myApp'
-    # titlebar: new Titlebar
-
-    constructor: ->
-        @init()
-
-    init: ->
-        console.log ['app init', @]
-        @titlebar = new Titlebar(@)
-
-    beep: ->
-        console.log 'beep'
-
-
-class Titlebar
-
-    constructor: (@app) ->
-        console.log ['titlebar init', @]
-        @dom()
-        @events()
-
-    dom: ->
-        @$el = document.querySelector 'body'
-
-    events: ->
-        console.log 'events', @$el
-        @$el.addEventListener 'click', (e) => @app.beep()
-
-app = window.app = new App


make time show as nanoseconds when it's too little to show as seconds

--- benchmark/benchmarks.coffee
+++ benchmark/benchmarks.coffee
@@ -91,18 +91,26 @@

     if info.old?
       oldTimeNum = info.old.seconds + (info.old.nanos / 1e9)
-      oldTime    = chalk.magenta @format padSize, oldTimeNum
       oldRateNum = info.old.repeat / oldTimeNum
       oldRate    = chalk.blue @format padSize, oldRateNum
+      oldTime    =
+        if info.old.seconds is 0 and info.old.nanos < 1e6
+          chalk.cyan pad padSize, format(info.old.nanos) + ' n'
+        else
+          chalk.magenta @format padSize, @time oldTimeNum, info.old.seconds, info.old.nanos

     else
       oldTime = '         N/A'
       oldRate = '         N/A'

     newTimeNum = info.elapsed[0] + (info.elapsed[1] / 1e9)
-    newTime    = chalk.magenta @format padSize, newTimeNum
     newRateNum = info.repeat / newTimeNum
     newRate    = chalk.blue @format padSize, newRateNum
+    newTime    =
+      if info.elapsed[0] is 0 and info.elapsed[1] < 1e6
+        chalk.cyan pad padSize, format(info.elapsed[1]) + ' n'
+      else
+        chalk.magenta @format padSize, newTimeNum

     if info.old?
       change = Math.round(((newRateNum - oldRateNum) / oldRateNum) * 100)


revise output format calulcations, use 'old' instead of 'original'

--- benchmark/benchmarks.coffee
+++ benchmark/benchmarks.coffee
@@ -10,7 +10,7 @@

   run: (options) ->

-    original = options.original
+    old    = options.old
     repeat = options.repeat ? 1
     report = options.report is true
     store  = options.store is true
@@ -31,7 +31,8 @@
       benchmark.setup()

       # pre-run for optimization
-      benchmark.run Math.max 1, Math.floor repeat * 0.25 # TODO: support asynchronous ...
+      prerun = if repeat is 1 then 1 else Math.max 100, Math.floor repeat * 0.25
+      benchmark.run prerun # TODO: support asynchronous ...

       start = process.hrtime()

@@ -39,7 +40,7 @@

       elapsed = process.hrtime start

-      info = { benchmark, repeat, elapsed, result, original:original.info[index] }
+      info = { benchmark, repeat, elapsed, result, old:old.info[index] }
       if report then @reportResult info
       if store  then @storeResult info

@@ -56,41 +57,50 @@
     string[0 ... index]

   reportHeader: ->
-    h1 = chalk.blue pad(12, 'old rate')
-    h2 = ' |' + chalk.blue pad 12, 'new rate'
+    padSize = 12
+    h1 = chalk.blue pad(padSize, 'old ops/sec')
+    h2 = ' |' + chalk.blue pad padSize, 'new ops/sec'
     h3 = ' |' + pad 10, 'change'
-    h4 = ' |' + chalk.magenta pad 12, 'old secs'
-    h5 = ' |' + chalk.magenta pad 12, 'new secs'
+    h4 = ' |' + chalk.magenta pad padSize, 'old seconds'
+    h5 = ' |' + chalk.magenta pad padSize, 'new seconds'
     h6 = ' |' + chalk.bold ' label'
     console.log h1 + h2 + h3 + h4 + h5 + h6
-    console.log '--------------------------------------------------------------------'
+    console.log '----------------------------------------------------------------------------------------------'

-  reportResult: ({benchmark, repeat, elapsed, original}) ->
+  reportResult: (info) ->
+    # info = {benchmark, repeat, elapsed, old}
+    padSize = 12

-    originalSecs = original.seconds + (original.nanos / 1e9)
-    newSecs      = elapsed[0] + (elapsed[1] / 1e9)
+    if info.old?
+      oldTimeNum = info.old.seconds + (info.old.nanos / 1e9)
+      oldTime    = chalk.magenta @format padSize, oldTimeNum
+      oldRateNum = info.old.repeat / oldTimeNum
+      oldRate    = chalk.blue @format padSize, oldRateNum

-    originalRate = original.repeat / originalSecs
-    newRate      = repeat / newSecs
+    else
+      oldTime = '         N/A'
+      oldRate = '         N/A'

-    secs0 = chalk.magenta @format 12, originalSecs
-    rate0 = chalk.blue @format 12, originalRate
+    newTimeNum = info.elapsed[0] + (info.elapsed[1] / 1e9)
+    newTime    = chalk.magenta @format padSize, newTimeNum
+    newRateNum = info.repeat / newTimeNum
+    newRate    = chalk.blue @format padSize, newRateNum

-    secs1 = chalk.magenta @format 12, newSecs
-    rate1 = chalk.blue @format 12, newRate
+    if info.old?
+      change = Math.round(((newRateNum - oldRateNum) / oldRateNum) * 100)
+      color =
+        if change > 0.01 then chalk.green
+        else if change < -0.01 then chalk.red
+        else chalk.black
+      change = color(@format 9, change.toFixed 0) + '%'

-    change = Math.round(((newRate - originalRate) / originalRate) * 100)
-    color =
-      if change > 0.01 then chalk.green
-      else if change < -0.01 then chalk.red
-      else chalk.black
-    change = color(@format 9, change.toFixed 0) + '%'
+    else change = '      N/A '

-    label = chalk.bold benchmark.label
+    label = chalk.bold info.benchmark.label

-
-    line = rate0 + ' |' + rate1 + ' |' + change + ' |' + secs0 + ' |' + secs1 + ' |  ' + label
-    console.log line
+    console.log """
+    #{oldRate} |#{newRate} |#{change} |#{oldTime} |#{newTime} |  #{label}
+    """

   storeResult: ({benchmark, repeat, elapsed}) ->


Fix bug. Trash is allowed for anonymous user too.

--- app/client/js/storage.coffee
+++ app/client/js/storage.coffee
@@ -37,9 +37,9 @@
   ###
   load: (route, params) ->
     switch route
-      when @routes.about, @routes.home, @routes.newSong
+      when @routes.about, @routes.home, @routes.newSong, @routes.trash
         @ok()
-      when @routes.me, @routes.trash
+      when @routes.me
         return @notFound() if !@userStore.isLogged()
         @ok()
       when @routes.mySong, @routes.editSong


revpi-core-3.coffee: Set Yocto version to Warrior

Signed-off-by: Florin Sarbu <3a837a37a2ac9072a088641ec330e0e5d5b86f4e@balena.io>

--- revpi-core-3.coffee
+++ revpi-core-3.coffee
@@ -35,7 +35,7 @@
 		machine: 'revpi-core-3'
 		image: 'resin-image'
 		fstype: 'resinos-img'
-		version: 'yocto-thud'
+		version: 'yocto-warrior'
 		deployArtifact: 'resin-image-revpi-core-3.resinos-img'
 		compressed: true


Grid model update

Grid model update


:herb::cry: Updated in browser at strd6.github.io/editor

--- test/google_spreadsheet.coffee
+++ test/google_spreadsheet.coffee
@@ -2,8 +2,12 @@

 describe "Google Spreadsheet wrapper", ->
   it "loads spreadsheet from a given key", (done) ->
-    Spreadsheet.load "0ArtCBkZR37MmdFJqbjloVEp1OFZLWDJ6M29OcXQ1WkE", (data) ->
-      console.log data
-      assert data.name is "Abilities"
-      assert data.entries.length > 0
+    Spreadsheet.load "0ArtCBkZR37MmdFJqbjloVEp1OFZLWDJ6M29OcXQ1WkE", (data) ->
+      assert data.Abilities
+      assert data.Characters
+      assert data.Passives
+      assert data.Progressions
+      assert data.TerrainFeatures
+
+      assert(data.Abilities.length > 0)
       done()


Adding tests for remote CSS links, JS links starting with //

--- test/development.coffee
+++ test/development.coffee
@@ -106,6 +106,8 @@
   test.equals css('style.css'), cssTag
   test.equals css('style'), cssTag
   test.equals css('../style'), "<link rel='stylesheet' href='/style.css'>"
+  test.equals css('http://raw.github.com/necolas/normalize.css/master/normalize.css'), "<link rel='stylesheet' href='http://raw.github.com/necolas/normalize.css/master/normalize.css'>"
+  test.equals css('//raw.github.com/necolas/normalize.css/master/normalize.css'), "<link rel='stylesheet' href='//raw.github.com/necolas/normalize.css/master/normalize.css'>"
   test.done()

 exports['js helper function provides correct src'] = (test) ->
@@ -114,6 +116,7 @@
   test.equals js('script.js'), jsTag
   test.equals js('script'), jsTag
   test.equals js('http://code.jquery.com/jquery-1.6.2'), "<script src='http://code.jquery.com/jquery-1.6.2.js'></script>"
+  test.equals js('//code.jquery.com/jquery-1.6.2'), "<script src='//code.jquery.com/jquery-1.6.2.js'></script>"
   test.done()

 exports['Script files can `require` (in non-production mode)'] = (test) ->


fully integrated mongoskin

fully integrated mongoskin

--- routes/pages.coffee
+++ routes/pages.coffee
@@ -3,21 +3,22 @@
 #
 mongo = require "mongoskin"
 BSON = mongo.BSONPure
+collectionName = "pages"

 if process.env.MONGOHQ_URL
-  connection_string = process.env.MONGOHQ_URL
+  connectionString = process.env.MONGOHQ_URL
 else
-  connection_string = "mongodb://localhost:27017/nodelove"
+  connectionString = "mongodb://localhost:27017/nodelove"

-db = mongo.db(connection_string + "?auto_reconnect",
+db = mongo.db(connectionString + "?auto_reconnect",
   safe: false
 )

 db.open (err, db) ->
   unless err
     console.log "Connected to 'nodelove' database"
-    db.collection "pages", (err, collection) ->
-      if err
+    db.collection(collectionName).find().toArray (err, items) ->
+      unless items.length
         populateDB()

 #
@@ -35,24 +36,23 @@
   catch err
     lookup["slug"] = id

-  db.collection "pages", (err, collection) ->
-    collection.findOne lookup, (err, item) ->
-      res.send error: "A DB error has occurred"  if err
-      if item
-        res.send item
-      else
-        res.send 404
+  db.collection(collectionName).findOne lookup, (err, item) ->
+    if err
+      res.send error: "A DB error has occurred"
+    if item
+      res.send item
+    else
+      res.send 404

 # Find all pages
 exports.findAll = (req, res) ->
-  db.collection "pages", (err, collection) ->
-    collection.find().toArray (err, items) ->
-      if err
-        res.send error: "A DB error has occurred"
-      if items
-        res.send items
-      else
-        res.send 404
+  db.collection(collectionName).find().toArray (err, items) ->
+    if err
+      res.send error: "A DB error has occurred"
+    if items
+      res.send items
+    else
+      res.send 404

 #
 # Render main layout
@@ -94,8 +94,11 @@
     showHero: false
   ]

-  db.collection "pages", (err, collection) ->
-    collection.insert pages,
-      safe: true
-    , (err, result) ->
+  db.collection(collectionName).insert pages,
+    safe: true
+  , (err, result) ->
+    if err
+      console.log "A DB error has occurred"
+    else
+      console.log "The DB had been populated!"


removed unnecessary variable declarations

--- routes/pages.coffee
+++ routes/pages.coffee
@@ -4,8 +4,6 @@
 mongo = require "mongoskin"
 BSON = mongo.BSONPure

-server = undefined
-db = undefined
 if process.env.MONGOHQ_URL
   connection_string = process.env.MONGOHQ_URL
 else


Couple minor tweaks

Couple minor tweaks

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -14,8 +14,7 @@
 ClassificationSummary = require './classification-summary'
 LocationInformation = require './location-information'

-$ = window.$
-$window = $(window)
+$ = window.jQuery
 $body = $('body')

 IMAGE_WIDTH = 720
@@ -72,12 +71,13 @@
     @el.on StackOfPages::activateEvent, @activate

   activate: =>
+    # have to wait until home page animation is done
     setTimeout =>
       @tutorial.attach()
     , 500

   onUserChange: (e, user) =>
-    if user?.project.tutorial_done
+    if user?.project?.tutorial_done
       Subject.next()
     else
       selectTutorialSubject()
@@ -95,9 +95,9 @@

     @surface.disable()

-    loadImage subject.location.standard, (@currentSubjectImage) =>
+    loadImage subject.location.standard, ({ src }) =>
       @loader.fadeOut { queue: false }
-      @surface.image.attr { src: @currentSubjectImage.src }
+      @surface.image.attr { src: src }

       @subjectButton.removeClass 'disabled'


prevent some subjects from triggering as training

--- app/controllers/classifier.coffee
+++ app/controllers/classifier.coffee
@@ -302,7 +302,7 @@
     @el.find('.subject').first().addClass('current')

     # Check if training subject
-    if subject.metadata.training?
+    if subject.group_id is @simulationGroup
       @isTrainingSubject = true

       # Set up offscreen canvas and cache the context


Test case for accepting object arguments

--- test/spec/overload.spec.coffee
+++ test/spec/overload.spec.coffee
@@ -46,4 +46,9 @@
     it "should accept regexp arguments", ->
         expect( ->
             overloadableFunc.overload /\./, ->
-        ).not.toThrow()+        ).not.toThrow()
+
+    it "should accept object arguments", ->
+        expect( ->
+            overloadableFunc.overload {}, ->
+        ).not.toThrow()


Audition by send notification. Show hint on no login

--- index.cjsx
+++ index.cjsx
@@ -45,6 +45,7 @@
   version: '0.2.0'
   reactClass: React.createClass
     getInitialState: ->
+      isLogin: false
       notifySecretary: config.get('plugin.secretary.ship', 0)
       fleetSecretary: null
       ships: []
@@ -68,6 +69,7 @@
           for ship in body.api_mst_shipgraph
             shipgraph[ship.api_id] = ship
           @setState
+            isLogin: true
             ships: ships
             shipgraph: shipgraph
         when '/kcsapi/api_port/port', '/kcsapi/api_get_member/deck', '/kcsapi/api_req_hensei/change'
@@ -113,17 +115,16 @@
         @updateNotifyConfig(@state.fleetSecretary)

     handleAudition: (type) ->
-      audio = null
       switch type
         when 'construction'
-          audio = config.get('poi.notify.construction.audio')
+          notify "Notification sound audition",
+            type: 'construction'
         when 'expedition'
-          audio = config.get('poi.notify.expedition.audio')
+          notify "Notification sound audition",
+            type: 'expedition'
         when 'repair'
-          audio = config.get('poi.notify.repair.audio')
-      if audio
-        sound = new Audio(audio)
-        sound.play()
+          notify "Notification sound audition",
+            type: 'repair'

     render: ->

@@ -134,14 +135,21 @@

         <Grid>
           <Col xs=12>
-            <Input type="select" value={@state.notifySecretary} onChange={@handleShipChange}>
-              <option key={0} value={0}>当前秘书舰</option>
-              {
-                for ship, i in @state.ships
-                  continue unless ship?.api_sortno
-                  <option key={i} value={ship.api_id}>No.{zerofill(ship.api_sortno)} {ship.api_name}</option>
-              }
-            </Input>
+          {
+            if @state.isLogin
+              options = []
+              options.push <option key={0} value={0}>当前秘书舰</option>
+              for ship, i in @state.ships
+                continue unless ship?.api_sortno
+                options.push <option key={i} value={ship.api_id}>No.{zerofill(ship.api_sortno)} {ship.api_name}</option>
+              <Input type="select" value={@state.notifySecretary} onChange={@handleShipChange}>
+                {options}
+              </Input>
+            else
+              <Input type="select" value={0} disabled>
+                <option key={0} value={0}>请进入游戏</option>
+              </Input>
+          }
           </Col>
           <Col xs=12>

当前秘书舰：{ if @state.fleetSecretary then window.$ships[@state.fleetSecretary]?.api_name else "未知" }


Change default subtitle file location

Change default subtitle file location

--- index.cjsx
+++ index.cjsx
@@ -10,7 +10,8 @@
 subtitles = {}
 timeoutHandle = 0
 REMOTE_HOST = 'http://api.kcwiki.moe/subtitles/diff'
-subtitlesFile = path.join APPDATA_PATH, 'poi-plugin-subtitle', 'subtitles.json'
+subtitlesFile = path.join APPDATA_PATH, 'plugins', 'node_modules', 'poi-plugin-subtitle', 'i18n', 'zh-CN.json'
+subtitlesFile_zhTW = path.join APPDATA_PATH, 'plugins', 'node_modules', 'poi-plugin-subtitle', 'i18n', 'zh-CN.json'
 subtitlesFileBackup = path.join __dirname, 'subtitles.json'
 voiceKey = [604825,607300,613847,615318,624009,631856,635451,637218,640529,643036,652687,658008,662481,669598,675545,685034,687703,696444,702593,703894,711191,714166,720579,728970,738675,740918,743009,747240,750347,759846,764051,770064,773457,779858,786843,790526,799973,803260,808441,816028,825381,827516,832463,837868,843091,852548,858315,867580,875771,879698,882759,885564,888837,896168]
 convertFilename = (shipId, voiceId) ->
@@ -46,7 +47,7 @@
 			else
 				subtitles[shipIdOrSth] = {} unless subtitles[shipIdOrSth]
 				subtitles[shipIdOrSth][voiceId] = text for voiceId, text of value
-		err = yield fs.writeFileAsync subtitlesFile, JSON.stringify(subtitles)
+		err = yield fs.writeFileAsync subtitlesFile, JSON.stringify(subtitles, null, '\t')
 		throw err if err
 	catch e
 		if e instanceof Error


Bump to version 3.6.2

Bump to version 3.6.2

--- index.cjsx
+++ index.cjsx
@@ -382,7 +382,7 @@
   priority: 1
   displayName: <FontAwesome key={0} name='compass' />{' ' + __("Prophet")}
   description: __ "Sortie Prophet"
-  version: '3.0.0'
+  version: '3.6.2'
   author: 'Chiba'
   link: 'https://github.com/Chibaheit'
   reactClass: React.createClass


the options, overridden through res.heckOptions

--- heck.coffee
+++ heck.coffee
@@ -4,6 +4,7 @@
 plates = require 'plates'
 util = require 'util'
 errs = require 'errs'
+

 # An `error-page` handler, because `templar` wasn't working.
 errorTemplate = (req, res, data) ->
@@ -28,10 +29,19 @@

#{JSON.stringify data, null, '  '}

"
       res.end (plates.bind plate.toString(), data, map)

+
 # The defaults for `error-page` module options.
-errorOptions =
+heckOptions =
   debug: if process.env.NODE_ENV is 'development' then true else false
   "*": errorTemplate
+
+
+# Use this middleware before any errors happen, to override `heckOptions`.
+module.exports.connect = (opts) ->
+  (req, res, next) ->
+    res.heckOptions = opts
+    next()
+

 # Pass to `vfs-http-handler` or call directly.
 module.exports.handler = (req, res, err, code) ->
@@ -39,8 +49,8 @@
   err = errs.create err unless util.isError err
   console.error err.stack || err

-  # The error-page options can be overridden.
-  opts = merge errorOptions, req.errorHandlerOptions ? {}
+  # The configurable error-page options.
+  opts = merge heckOptions, res.heckOptions ? {}

   # The status code and error message.
   message = err.stack.message || err.message || err
@@ -63,9 +73,3 @@
   res.error = new ErrorPage req, res, opts
   res.error status, message

-
-module.exports.connect = (opts) ->
-  (req, res, next) ->
-    req.errorHandlerOptions = opts
-    next()
-


Re-add moderation children open/closed class

--- app/talk/lib/moderation.cjsx
+++ app/talk/lib/moderation.cjsx
@@ -47,7 +47,7 @@
                 <button onClick={@toggleModeration}>
                    Moderator Controls
                 </button>
-

+

                   {
                     if @state.open
                       @props.children


removed commented out code

removed commented out code

--- apps/fair_info/routes.coffee
+++ apps/fair_info/routes.coffee
@@ -23,20 +23,6 @@
   .catch (error) ->
     next()
   .done()
-
-# fetchArticle = (articleParam, template, req, res, next) ->
-#   @article = new Article
-#   @article.parse = (response) ->
-#     response.results[0]
-
-#   @article.fetch
-#     data:
-#       "#{articleParam}": res.locals.sd.FAIR._id
-#       published: true
-#     error: next
-#     success: ->
-#       res.locals.sd.ARTICLE = @article.toJSON()
-#       res.render(template, { embedVideo: embedVideo, resize: resize })

 @index = (req, res) ->
   res.render("index")


fix only digit directive to work in firefox

--- app/directives/only-digits.coffee
+++ app/directives/only-digits.coffee
@@ -5,5 +5,6 @@
   restrict: 'A'
   link: (scope, el, attrs) ->
     el.bind 'keypress', (e) ->
-      unless _.includes(_.range(48, 57), e.keyCode)
+      acceptableKeyCodes = _.range(48,57).concat([0, 8])
+      unless _.includes(acceptableKeyCodes, e.which)
         e.preventDefault()


Add a test for "Never"

Add a test for "Never"

--- test/unit/model/dataset.coffee
+++ test/unit/model/dataset.coffee
@@ -253,7 +253,7 @@
       it 'saves the status', ->
         @saveSpy.calledOnce.should.be.true

-  context "when statusUpdatedHuman() is called", ->
+  context "when dateset.statusUpdatedHuman is called", ->
     before ->
       @dataset = new Cu.Model.Dataset
         name: 'updateHumanTest'
@@ -266,12 +266,21 @@
           # status.updated is sufficiently old to test for
           # https://github.com/scraperwiki/custard/issues/364
           updated: "2013-04-12T11:00:57.847Z"
+      @never = new Cu.Model.Dataset
+        name: 'neverTest'
+        box: 'box24243'
+        tool: 'tool'
+        displayName: 'Never Test'

     it "returns a human readable date", ->
       humanDate = @dataset.statusUpdatedHuman()
       should.equal typeof humanDate, 'string'
       humanDate.should.not.be.empty
       humanDate.should.include "ago"
+
+    it """returns "Never" when there is no status""", ->
+      humanDate = @never.statusUpdatedHuman()
+      should.equal humanDate, "Never"

   context 'when dataset.findToBeDeleted is called', ->
     it 'returns datasets with toBeDeleted in the past', (done) ->


:white_check_mark: Add stub test for paths setting change


promise -> fn

promise -> fn

--- spec/notifications-spec.coffee
+++ spec/notifications-spec.coffee
@@ -448,8 +448,8 @@
       }
       settings.success(response)

-window.waitsForPromise = (promise) ->
-  promise = promise()
+window.waitsForPromise = (fn) ->
+  promise = fn()
   window.waitsFor 5000, (moveOn) ->
     promise.then(moveOn)
     promise.catch (error) ->


Test Russ support for constrained parameters and special characters in parameters

--- test/RouterTest.coffee
+++ test/RouterTest.coffee
@@ -14,7 +14,7 @@
             app.use shell.router shell: app
         app.cmd 'test simple', (req, res) ->
             next()
-    'Test param': (next) ->
+    'Test param # string': (next) ->
         app = shell
             workspace:  "#{__dirname}/plugins_http"
             command: 'test my_value'
@@ -26,4 +26,43 @@
         app.cmd 'test :my_param', (req, res) ->
             assert.eql req.params.my_param, 'my_value'
             next()
+    'Test param # special char': (next) ->
+        app = shell
+            workspace:  "#{__dirname}/plugins_http"
+            command: 'test 12.32/abc'
+            stdin: new shell.NullStream
+            stdout: new shell.NullStream
+        app.configure ->
+            app.use shell.http
+            app.use shell.router shell: app
+        app.cmd 'test :my_param', (req, res) ->
+            assert.eql req.params.my_param, '12.32/abc'
+            next()
+    'Test # param with restriction # ok': (next) ->
+        app = shell
+            workspace:  "#{__dirname}/plugins_http"
+            command: 'test 9034'
+            stdin: new shell.NullStream
+            stdout: new shell.NullStream
+        app.configure ->
+            app.use shell.http
+            app.use shell.router shell: app
+        app.cmd 'test :my_param([0-9]+)', (req, res) ->
+            assert.eql req.params.my_param, '9034'
+            next()
+        app.cmd 'test :my_param', (req, res) ->
+            assert.ok false
+    'Test # param with restriction # error': (next) ->
+        app = shell
+            workspace:  "#{__dirname}/plugins_http"
+            command: 'test abc'
+            stdin: new shell.NullStream
+            stdout: new shell.NullStream
+        app.configure ->
+            app.use shell.http
+            app.use shell.router shell: app
+        app.cmd 'test :my_param([0-9]+)', (req, res) ->
+            assert.ok false
+        app.cmd 'test :my_param', (req, res) ->
+            next()


Verify style.theme instead of style.userTheme

This caused specs to fail locally but not on CI since CI has
not user theme

--- spec/theme-manager-spec.coffee
+++ spec/theme-manager-spec.coffee
@@ -30,7 +30,7 @@
       themeManager.load()

       config.set('core.themes', [])
-      expect($('style.userTheme').length).toBe 0
+      expect($('style.theme').length).toBe 0
       expect(reloadHandler).toHaveBeenCalled()

       config.set('core.themes', ['atom-dark-syntax'])


client: use default route instead of explicit '/' string route for logos

--- client/Core/mainview.coffee
+++ client/Core/mainview.coffee
@@ -42,23 +42,26 @@
     @header.addSubView new TopNavigation

     @header.addSubView @logo = new KDCustomHTMLView
-      tagName   : "a"
-      domId     : "koding-logo"
-      cssClass  : if entryPoint?.type is 'group' then 'group' else ''
-      partial   : ''
+      tagName    : "a"
+      attributes : href : '/'
+      domId      : "koding-logo"
+      cssClass   : if entryPoint?.type is 'group' then 'group' else ''
+      partial    : ''
       click     : (event)=>
         KD.utils.stopDOMEvent event
         {router} = KD.singletons
-        if KD.isLoggedIn()
-        then router.handleRoute '/Activity', {entryPoint}
-        else router.handleRoute '/', {entryPoint}
+        router.handleRoute router.getDefaultRoute()

     @logo.setClass KD.config.environment

     @header.addSubView @logotype = new CustomLinkView
       cssClass : 'logotype'
       title    : 'Koding'
-      href     : '/Home'
+      href     : '/'
+      click    : (event)=>
+        KD.utils.stopDOMEvent event
+        {router} = KD.singletons
+        router.handleRoute router.getDefaultRoute()

   createSidebar: ->
@@ -69,9 +72,19 @@
       tagName  : 'aside'
       domId    : 'main-sidebar'

-    @aside.addSubView new KDCustomHTMLView
+    logoWrapper = new KDCustomHTMLView
       cssClass  : if entryPoint?.type is 'group' then 'logo-wrapper group' else 'logo-wrapper'
-      partial   : "

"
+
+    logoWrapper.addSubView new KDCustomHTMLView
+      tagName    : 'a'
+      attributes : href : '/' # so that it shows 'koding.com' on status bar of browser
+      partial    : '

'
+      click      : (event)=>
+        KD.utils.stopDOMEvent event
+        {router} = KD.singletons
+        router.handleRoute router.getDefaultRoute()
+
+    @aside.addSubView logoWrapper

     @aside.addSubView @sidebar = new KDCustomScrollView
       offscreenIndicatorClassName: 'unread'


evaluate parens

evaluate parens

--- src/evaluator.coffee
+++ src/evaluator.coffee
@@ -101,6 +101,12 @@
       when '>='
         left >= right

+class Parens
+  constructor: (node) ->
+    @formula = node.formula
+  evaluate: (data) ->
+    @formula.evaluate data
+
 class Decimal
   constructor: (node) ->
     @value = parseFloat( node.whole + '.' + node.part )


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/expirable.coffee
+++ src/expirable.coffee
@@ -8,9 +8,7 @@

   self.bind "update", ->
     if I.fadeOut
-      I.alpha = (startingAlpha - ((I.age / I.duration) * startingAlpha)).clamp(0, 1)
-
-    if I.blink
+      I.alpha = (startingAlpha - ((I.age / I.duration) * startingAlpha)).clamp(0, 1)

     if I.duration != -1 && I.age >= I.duration
       I.active = false


Remove unused require

Remove unused require

--- src/file-view.coffee
+++ src/file-view.coffee
@@ -1,4 +1,4 @@
-{View, $$} = require 'space-pen'
+{View} = require 'space-pen'
 $ = require 'jquery'
 Git = require 'git'
 fs = require 'fs'


Update usage message for new name

Update usage message for new name

--- src/flips-cli.coffee
+++ src/flips-cli.coffee
@@ -7,10 +7,10 @@

 parseOptions = (args=[]) ->
   options = optimist(args)
-  options.usage('Usage: ceo <cik>')
+  options.usage('Usage: flips <cik>')
   options.demand(1)
   options.alias('h', 'help').describe('h', 'Print this usage message')
-  options.alias('v', 'version').describe('v', 'Print the ceo version')
+  options.alias('v', 'version').describe('v', 'Print the flips version')
   options

 fetchTransaction = ({connection, transaction}, callback) ->


Test d'existence avec un élément dans la base.

--- test/data_tests.coffee
+++ test/data_tests.coffee
@@ -28,4 +28,14 @@
             should.exist @body.exist
             @body.exist.should.not.be.ok

+	# L'element d'id 321 doit etre ajoute a la main dans la base.
+        it "When I send a request to check existence of Note with id 321", \
+                (done) ->
+            client.get "data/exist/321/", (error, response, body) =>
+                @body = JSON.parse body
+                done()

+        it "Then {exist: true} should be returned", ->
+            should.exist @body.exist
+            @body.exist.should.be.ok
+


Made tests a liiittle more usable

Made tests a liiittle more usable

--- test/files/stream.iced
+++ test/files/stream.iced
@@ -106,13 +106,3 @@
   console.log('Send the following to Patrick:')
   console.log(stb.getBuffer().toString())
   cb()
-
-exports.test_streaming = (T, cb) ->
-  {alice, _} = alice_and_bob()
-  es = new stream.EncryptStream(alice, gen_recipients(crypto.randomBytes(32)), true)
-  es.pipe(process.stdout)
-  await stream_random_data(es, random_megabyte_to_ten(), defer(data))
-  await
-    es.last_stream.on('finish', defer())
-    es.end(() ->)
-  cb()


Disable onbeforeunload test - it's not used any more.

--- tests/html/src/domtests.coffee
+++ tests/html/src/domtests.coffee
@@ -42,19 +42,19 @@
                     });
                 """))

-if navigator.userAgent.indexOf('Konqueror') isnt -1 or $.browser.opera
-    test "onbeforeunload [unsupported by client]", ->
-        ok(true)
-else
-    asyncTest('onbeforeunload', onunload_test_factory("""
-                    var u = SockJS.getUtils();
-                    u.attachEvent('load', function(){
-                        hook.load();
-                    });
-                    u.attachEvent('beforeunload', function(){
-                        hook.unload();
-                    });
-                """))
+# if navigator.userAgent.indexOf('Konqueror') isnt -1 or $.browser.opera
+#     test "onbeforeunload [unsupported by client]", ->
+#         ok(true)
+# else
+#     asyncTest('onbeforeunload', onunload_test_factory("""
+#                     var u = SockJS.getUtils();
+#                     u.attachEvent('load', function(){
+#                         hook.load();
+#                     });
+#                     u.attachEvent('beforeunload', function(){
+#                         hook.unload();
+#                     });
+#                 """))

 if not SockJS.getIframeTransport().enabled()
     test "onmessage [unsupported by client]", ->


comment test with wrong mail (use postfix)

--- test/mail_tests.coffee
+++ test/mail_tests.coffee
@@ -107,7 +107,7 @@
                         'attributes'

-    describe "Send an email with wrong mail: ", ->
+    ###describe "Send an email with wrong mail: ", ->

         it "When I send a request to send email", (done) ->
             data =
@@ -127,7 +127,7 @@
                 @body.error.name.should.be.equal 'RecipientError'

-    ###describe "Send an email: ", ->
+    describe "Send an email: ", ->

         it "When I send a request to send email", (done) ->
             data =


improved built-in colour schemes

improved built-in colour schemes


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_over.coffee
+++ src/game_over.coffee
@@ -15,7 +15,7 @@
 ###

 ###*
-Draws Game Over screen and rese
+Draws Game Over screen and reset instructions.

 @name overlay
 @methodOf GameOver#


refactor(VkApi): comment out the `revoke: 1`, don't force re-auth each time

The `revoke: 1` line is sometimes useful during development.
Let's disable it by default on the generic `develop` branch. Activate it when
needed, but don't merge into `develop`.

--- app/scripts/services/vkApi.coffee
+++ app/scripts/services/vkApi.coffee
@@ -19,7 +19,7 @@
 		display: "page"
 		v: apiVersion
 		response_type: "token"
-		revoke: 1
+		# revoke: 1

 	authUrl = "https://oauth.vk.com/authorize?" +
 		( "#{param}=#{value}" for param, value of authUrlParams ).join "&"