payment: code style: space operators

payment: code style: space operators

--- node_modules_koding/koding-payment/lib/main.coffee
+++ node_modules_koding/koding-payment/lib/main.coffee
@@ -8,7 +8,7 @@

   { GET, POST, PUT, DEL } = (require './request') KONFIG.recurly.apiKey

-  summarizeErrors = (errors)->
+  summarizeErrors = (errors) ->
     billing = 0
     for e in errors
       if e.field.indexOf('subscription.account.billing_info') > -1 and ++billing > 2
@@ -16,7 +16,7 @@

   # If requested list of records are longer than 50 items, recurly
   # paginates them. This method gets the URL path of next page.
-  parseNextUrl = (res)->
+  parseNextUrl = (res) ->
     links = {}
     for link in res.headers.link.split(', ')
       linkData = link.split('; ')
@@ -62,7 +62,7 @@
       else
         PUT "accounts/#{paymentMethodId}", xml, callback

-  @deleteAccount = (paymentMethodId, callback)->
+  @deleteAccount = (paymentMethodId, callback) ->
     DEL "accounts/#{paymentMethodId}", callback

   #
@@ -138,8 +138,8 @@
   # charge amount from pending one-time adjustments (carge/credit) to subscription
   # if not manually charged with this method, those will be automatically charged
   # on subscription's renewal (typically monthly)
-  @chargePending = (paymentMethodId, callback)->
-    POST "accounts/#{paymentMethodId}/invoices", '', (err, res)->
+  @chargePending = (paymentMethodId, callback) ->
+    POST "accounts/#{paymentMethodId}/invoices", '', (err, res) ->
       callback err, unless err then new models.Transaction res.transaction

   #
@@ -147,8 +147,8 @@
   # See https://docs.recurly.com/api/accounts for XML format
   #

-  @fetchPaymentMethodById = (paymentMethodId, callback)->
-    GET "accounts/#{paymentMethodId}/billing_info", (err, res)->
+  @fetchPaymentMethodById = (paymentMethodId, callback) ->
+    GET "accounts/#{paymentMethodId}/billing_info", (err, res) ->
       return callback err  if err?
       paymentMethod = res[0]?.billing_info
       callback err,
@@ -159,7 +159,7 @@
   makeTag = (field, tagName = field) ->
     if @[field]? then "<#{ tagName }>#{ @[field] }</#{ tagName }>" else ''

-  @setPaymentMethodById = (paymentMethodId, data, callback)->
+  @setPaymentMethodById = (paymentMethodId, data, callback) ->
     # Remove credit card number if it's not updated
     if (data.cardNumber?.indexOf '*') > -1 or data.cardCV?.cardCV is '***'
       delete data.cardNumber
@@ -239,7 +239,7 @@
     POST 'plans', xml, (err, res) ->
       callback err, unless err then new models.Plan res.plan

-  @updatePlan = (data, callback)->
+  @updatePlan = (data, callback) ->
     data.feeInitial  ?= 0
     data.feeInterval ?= 1

@@ -258,10 +258,10 @@
       </plan>
       """

-    PUT "plans/#{data.code}", xml, (err, res)->
+    PUT "plans/#{data.code}", xml, (err, res) ->
       callback err, unless err then new models.Plan res.plan

-  @deletePlan = (data, callback)->
+  @deletePlan = (data, callback) ->
     DEL "plans/#{data.code}", callback

   #
@@ -270,6 +270,7 @@
   #

   @fetchSubscriptions = (paymentMethodId, callback) ->
+    console.trace()  unless callback
     GET "accounts/#{paymentMethodId}/subscriptions", (err, res) ->
       return callback err  if err

@@ -288,7 +289,7 @@
       else
         callback new models.Error 'subscription', 'Requested subscription not found'

-  @createSubscription = (paymentMethodId, data, callback)->
+  @createSubscription = (paymentMethodId, data, callback) ->
     data.quantity ?= 1

     xml =
@@ -304,10 +305,10 @@
       </subscription>
       """

-    POST 'subscriptions', xml, (err, res)->
-      callback err, unless err then new models.Subscription res.subscription
-
-  @updateSubscription = (paymentMethodId, data, callback)->
+    POST 'subscriptions', xml, (err, res) ->
+      callback err, unless err then new models.Subscription res.subscription
+
+  @updateSubscription = (paymentMethodId, data, callback) ->
     data.quantity ?= 1
     timeframe      = 'now'

@@ -321,21 +322,21 @@
       </subscription>
       """

-    PUT "subscriptions/#{data.uuid}", xml, (err, res)->
-      callback err, unless err then new models.Subscription res.subscription
-
-  @terminateSubscription = (paymentMethodId, data, callback)->
+    PUT "subscriptions/#{data.uuid}", xml, (err, res) ->
+      callback err, unless err then new models.Subscription res.subscription
+
+  @terminateSubscription = (paymentMethodId, data, callback) ->
     data.refund ?= 'none'

     PUT "subscriptions/#{data.uuid}/terminate?refund=#{data.refund}", '', (err, res)->
       callback err, unless err then new models.Subscription res.subscription

-  @cancelSubscription = (paymentMethodId, data, callback)->
-    PUT "subscriptions/#{data.uuid}/cancel", '', (err, res)->
-      callback err, unless err then new models.Subscription res.subscription
-
-  @reactivateUserSubscription = (paymentMethodId, data, callback)->
-    PUT "subscriptions/#{data.uuid}/reactivate", '', (err, res)->
+  @cancelSubscription = (paymentMethodId, data, callback) ->
+    PUT "subscriptions/#{data.uuid}/cancel", '', (err, res) ->
+      callback err, unless err then new models.Subscription res.subscription
+
+  @reactivateUserSubscription = (paymentMethodId, data, callback) ->
+    PUT "subscriptions/#{data.uuid}/reactivate", '', (err, res) ->
       callback err, unless err then new models.Subscription res.subscription

   #
@@ -353,7 +354,7 @@

       callback null, trans

-  @createTransaction = (paymentMethodId, data, callback)->
+  @createTransaction = (paymentMethodId, data, callback) ->
     xml =
       """
       <transaction>
@@ -366,8 +367,8 @@
       </transaction>
       """

-    POST 'transactions', xml, (err, res)->
+    POST 'transactions', xml, (err, res) ->
       callback err, unless err then new models.Transaction res.transaction

-  @deleteTransaction = (paymentMethodId, data, callback)->
+  @deleteTransaction = (paymentMethodId, data, callback) ->
     DEL "transactions/#{data.uuid}?amount_in_cents=##{data.amount}", callback


Don't send heartbeat for death or killed workers

--- node_modules_koding/processes/src/processes.coffee
+++ node_modules_koding/processes/src/processes.coffee
@@ -114,7 +114,6 @@
     options.restart = no

     workerProcess.connect()
-    workerProcess.startReporter()
     console.log "[PROCESSES][#{name}] connected to Kontrold. Waiting for instructions..." if verbose

     #############
@@ -126,6 +125,7 @@
           @child = @startProcess options
           @populateChildObject options, @child

+          workerProcess.startReporter()
           # Update kontrold worker information with our newly created pid.
           workerProcess.fetchWorkerExchange (workerExchange) =>
             workerProcess.worker.message.command = "update"
@@ -165,6 +165,7 @@
       workerProcess.worker.status = 4
       console.log "[PROCESSES][#{name}] received 'kill' message from Kontrold. Sending SIGTERM to the child_process." if verbose
       # @child.kill 'SIGKILL' #try this in the future
+      workerProcess.stopReporter()
       @kill name

     #############


Error handling: at least log them to the console.

I know that real error handling is much more than this, but a little
bit is better than nothing.

--- lib/man-view.coffee
+++ lib/man-view.coffee
@@ -9,18 +9,27 @@

         @content: ->
             @div class: 'man-view native-key-bindings', tabindex: -1, =>
+                @div class: 'man-view-error', outlet: "manViewError"
                 @div outlet: "manViewContent"

         constructor: ({@filePath, @uri}) ->
             super
             wcmd = "man -w #{@filePath}"
             exec wcmd, (error, stdout, stderr) =>
+                if error
+                    console.error error
+                if stderr
+                    console.error stderr
                 file = stdout.replace("\n", "")
                 if file.match(/\.gz$/)
                     cmd = "gzcat '#{file}' | groff -mandoc -T html"
                 else
                     cmd = "groff -mandoc -T html '#{file}'"
                 exec cmd, (error, stdout, stderr) =>
+                    if error
+                        console.error error
+                    if stderr
+                        console.error stderr
                     fudged = stdout.replace('', '
').replace('','
');
                     dom = $(fudged).filter('div.manpage-body')
                     dom.css('fontFamily', atom.config.get('editor.fontFamily'))


:bug: fix stayOnDelete bug in visual mode

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -384,7 +384,12 @@
   wasLinewise: null

   initialize: ->
+    super
     @wasLinewise = null
+    if @instanceof('DeleteLine')
+      @wasLinewise = true
+    else if @isMode('visual') and not @isMode('visual', 'linewise')
+      @stayAtSamePosition = false

   mutateSelection: (selection) =>
     {cursor} = selection
@@ -401,12 +406,12 @@
         cursor.setBufferPosition([vimEof.row, 0])

       if @needStay()
-        headPosition = swrap(selection).getBufferPositionFor('head', fromProperty: true)
-        cursor.setBufferPosition([cursor.getBufferRow(), headPosition.column])
-        cursor.goalColumn = headPosition.column
+        head = swrap(selection).getBufferPositionFor('head', fromProperty: true)
+        start = swrap(selection).getBufferPositionFor('start', fromProperty: true)
+        cursor.setBufferPosition([start.row, head.column])
+        cursor.goalColumn = head.column
       else
         cursor.skipLeadingWhitespace()
-

 class DeleteRight extends Delete
   @extend()


add hyperclick to initial requirements

add hyperclick to initial requirements

--- lib/packages.coffee
+++ lib/packages.coffee
@@ -4,6 +4,7 @@
   'tool-bar'
   'indent-detective'
   'latex-completions'
+  'hyperclick'
   'language-julia'
   'ink'
   'julia-client'


Fix deprecated discuss link

Fix deprecated discuss link

--- lib/packages.coffee
+++ lib/packages.coffee
@@ -65,7 +65,7 @@
     atom.notifications.addError "Juno: Error downloading package info for #{name}",
     detail: """
       Please check your internet connection, or report this to
-          http://discuss.junolab.org
+          https://discourse.julialang.org
       and we'll try to help.
           –––
       #{err}
@@ -77,7 +77,7 @@
     atom.notifications.addError "Juno: Error installing package #{name}",
     detail: """
       Please check your internet connection, or report this to
-          http://discuss.junolab.org
+          https://discourse.julialang.org/
       and we'll try to help.
           –––
       #{err}


pass url to open into windows exec

pass url to open into windows exec

--- lib/protocol.coffee
+++ lib/protocol.coffee
@@ -1,6 +1,6 @@
 protocol = require 'register-protocol-win32'

-protocol.install('learn-ide', "#{process.execPath} \"%1\"")
+protocol.install('learn-ide', "#{process.execPath} --url-to-open=\"%1\"")
 	.then ->
 		console.log 'success'
   .catch (err) ->


Show suggestions only for 4+ chars or when activated manually

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -24,13 +24,17 @@
     @dict_data = dict_data

   getSuggestions: (options) ->
-    { prefix } = options
-    ret = @findMatchingSuggestions(prefix)
+    { prefix, activatedManually } = options
+    ret = @findMatchingSuggestions(prefix, activatedManually)
     return ret;

-  findMatchingSuggestions: (prefix) ->
-    matchingSuggestions = dict_data.filter((elem) -> elem[0].startsWith(prefix))
-    console.log(matchingSuggestions);
+  findMatchingSuggestions: (prefix, activatedManually) ->
+    matchingSuggestions = []
+
+    if prefix.length > 4 or activatedManually
+      matchingSuggestions = dict_data.filter((elem) -> elem[0].startsWith(prefix))
+      console.log(matchingSuggestions);
+
     return matchingSuggestions.map(@inflateSuggestion);

   inflateSuggestion: (elem) -> { text: elem[1] }


added self support

added self support

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -51,10 +51,13 @@
                         resolve(completions)

                     @getObjectAvailableMethods(editor, prefix, objectType, setAsInherited)
+                else if matches[0] == "self::"
+                    completions = @getLocalAvailableCompletions(editor).filter((item) -> item.isStatic)
+                    resolve(completions)
             else if objectType = @isKnownObject(editor, bufferPosition, prefix)
                 @getObjectAvailableMethods(editor, prefix, objectType, resolve)
             else
-                resolve([])
+                    resolve([])

     matchCurrentContext: (prefix) ->

@@ -253,6 +256,7 @@
         type: completion.type ? 'method',
         leftLabel: "#{completion.visibility}#{if completion.isStatic then ' static' else ''}",
         className: "method-#{completion.visibility}"
+        isStatic: completion.isStatic

     getParentClassName: (editor) ->


Thank you Shedna !

Thank you Shedna !

--- src/core/voicious.coffee
+++ src/core/voicious.coffee
@@ -82,14 +82,14 @@
         @app.use @app.router
         @app.use Express.static Config.Paths.Webroot
         do @setAllRoutes
-        #@app.use (err, req, res, next) =>
-        #    if err instanceof Errors.NotFound
-        #        Errors.RenderNotFound req, res
-        #    else
-        #        Errors.RenderError req, res
+        @app.use (err, req, res, next) =>
+            if err instanceof Errors.NotFound
+                Errors.RenderNotFound req, res
+            else
+                Errors.RenderError req, res
         @configured = yes

-    # Main function
+    # Main function
     # It'll populate the database, fetch the configuration and launch the listenning.
     start       : () =>
         Db.connect () =>


Split text when decorations interleave with spatial tokens

--- src/display-layer.coffee
+++ src/display-layer.coffee
@@ -492,16 +492,19 @@
         if spatialDecoration = @getSpatialTokenTextDecoration(metadata)
           @updateTags(closeTags, openTags, containingTags, [], [spatialDecoration])

+        lastSplitColumn = 0
         while comparePoints(decorationIterator.getPosition(), spatialTokenBufferEnd) < 0
-          text = @buildTokenText(metadata, screenExtent, bufferStart, decorationIterator.getPosition())
+          extent = decorationIterator.getPosition().column - bufferStart.column
+          text = @buildTokenText(metadata, extent, bufferStart, decorationIterator.getPosition())
           tokens.push({closeTags, openTags, text})
           bufferStart = decorationIterator.getPosition()
+          lastSplitColumn += extent
           closeTags = []
           openTags = []
           @updateTags(closeTags, openTags, containingTags, decorationIterator.getCloseTags(), decorationIterator.getOpenTags())
           decorationIterator.moveToSuccessor()

-        text = @buildTokenText(metadata, screenExtent, bufferStart, spatialTokenBufferEnd)
+        text = @buildTokenText(metadata, screenExtent - lastSplitColumn, bufferStart, spatialTokenBufferEnd)
         tokens.push({closeTags, openTags, text})

         closeTags = []


Add DisplayLayer.prototype.outermostFoldsInBufferRowRange

--- src/display-layer.coffee
+++ src/display-layer.coffee
@@ -77,6 +77,9 @@
     @textDecorationLayer = layer
     @decorationLayerDisposable = layer.onDidInvalidateRange?(@decorationLayerDidInvalidateRange.bind(this))

+  bufferRangeForFold: (id) ->
+    @foldsMarkerLayer.getMarkerRange(id)
+
   foldBufferRange: (bufferRange) ->
     bufferRange = @buffer.clipRange(bufferRange)
     foldId = @foldsMarkerLayer.markRange(bufferRange).id
@@ -96,6 +99,19 @@

   foldsIntersectingBufferRange: (bufferRange) ->
     @foldsMarkerLayer.findMarkers(intersectsRange: bufferRange).map ({id}) -> id
+
+  outermostFoldsInBufferRowRange: (startRow, endRow) ->
+    folds = []
+    lastFoldEndRow = -1
+
+    for marker in @foldsMarkerLayer.findMarkers(intersectsRowRange: [startRow, endRow])
+      range = marker.getRange()
+      if range.start.row > lastFoldEndRow
+        lastFoldEndRow = range.end.row
+        if startRow <= range.start.row <= range.end.row < endRow
+          folds.push(marker.id)
+
+    folds

   destroyFold: (foldId) ->
     if foldMarker = @foldsMarkerLayer.getMarker(foldId)


also extract non CDATA encoded descriptions from feed

--- src/javascripts/feed.coffee
+++ src/javascripts/feed.coffee
@@ -15,7 +15,8 @@
     @enclosure = @mapEnclosure()
     @description = @extract('description')
       .html()
-      .match(/<!\[CDATA\[([\s\S]*)]]>$/)[1]
+    if @description.match(/^<!/)
+      @description = @description.match(/<!\[CDATA\[([\s\S]*)]]>$/)[1]

   extract: (elemName) =>
     @[elemName] ?= $(@xml).find(elemName)


Rename course clone menu options

Rename course clone menu options

--- tutor/src/flux/current-user.coffee
+++ tutor/src/flux/current-user.coffee
@@ -60,20 +60,20 @@
     label: 'Change Student ID'
     roles:
       student: 'changeStudentId'
-  cloneCourse:
-    label: 'Add New Course'
+  creatCourse:
+    label: 'Teach another Course'
+    roles:
+      default: 'createNewCourse'
     allowedForCourse: (course) ->
       if course
         CourseStore.isTeacher(course.id)
       else
         CurrentUserStore.isTeacher()
-    params: null
-    options: (courseId) ->
-      if courseId
-        query:
-          courseId: courseId
-    roles:
-      default: 'createNewCourse' # use default role since we ensured it was a teacher in allowedForCourse
+  cloneCourse:
+    label: 'Teach this Course Again'
+    params: (courseId) -> {sourceId: courseId}
+    roles:
+      teacher: 'createNewCourse'

 CurrentUserActions = flux.createActions [
   'setToken'  # (token) ->
@@ -219,16 +219,15 @@

       _.chain(routes)
         .map((routeType) =>
-          routeName = @_getRouteByRole(routeType, menuRole)
-
-          if routeName?
+          name = @_getRouteByRole(routeType, menuRole)
+
+          if name?
             options = @_getOptionsForRoute(courseId, routeType, menuRole)
             params  = @_getParamsForRoute(courseId, routeType, menuRole)
-
-            route =
-              name: routeName
-              label: ROUTES[routeType].label
-
+            label = ROUTES[routeType].label
+            label = label(courseId) if _.isFunction(label)
+
+            route = {name, label}
             route.options = options if options
             route.params = params if params
             route


Fixed asset fingerprint plugin

Fixed asset fingerprint plugin

--- config/plugins/asset-fingerprint.coffee
+++ config/plugins/asset-fingerprint.coffee
@@ -4,10 +4,10 @@
       options:
         manifestPath: "<%= files.assetFingerprint.manifest %>"

-    dist:
-      files: [
-        expand: true
-        cwd: "dist"
-        src: ["<%= files.js.minifiedWebRelative %>", "<%= files.css.minifiedWebRelative %>"]
-        dest: "dist"
-      ]
+      dist:
+        files: [
+          expand: true
+          cwd: "dist"
+          src: ["<%= files.js.minifiedWebRelative %>", "<%= files.css.minifiedWebRelative %>"]
+          dest: "dist"
+        ]


Properly show user

Properly show user

--- SingularityUI/app/components/webhooks/Webhooks.cjsx
+++ SingularityUI/app/components/webhooks/Webhooks.cjsx
@@ -83,7 +83,7 @@
             uri: uri
             type: type
         }
-        data.user = app.user.user.id if app.user.authenticated
+        data.user = app.user.attributes.user.id if app.user.attributes.authenticated
         $.ajax
             url: "#{ config.apiRoot }/webhooks"
             type: "POST"


use respond rather than hear

use respond rather than hear

--- src/hubot-tapsaff.coffee
+++ src/hubot-tapsaff.coffee
@@ -1,5 +1,16 @@
+# Description:
+#   hubot-tapsaff
+#
+# Configuration:
+#   HUBOT_TAPSAFF_TOON - optional default location for lookups
+#
+# Commands:
+#   tapsaff           - get the tapsaff status for the default location (HUBOT_TAPSAFF_TOON)
+#   tapsaff in <toon> - get the tapsaff status for the specified location
+#
+
 module.exports = (robot) ->
-  robot.hear /tapsaff in (\w+)/i, (msg) ->
+  robot.respond /tapsaff in (\w+)/i, (msg) ->
     toon = msg.match[1]
     robot.http("http://www.taps-aff.co.uk/?api&location=#{toon}")
       .get() (err, res, body) ->
@@ -15,7 +26,7 @@
         msg.send "yer tap should be #{json.taps} in #{json.location}. The weather's #{json.description} there the now."
         return

-  robot.hear /tapsaff$/i, (msg) ->
+  robot.respond /tapsaff$/i, (msg) ->
     toon = process.env.HUBOT_TAPSAFF_TOON
     unless toon?
       msg.send "You havnae told me whur aboots.  (try setting HUBOT_TAPSAFF_TOON or 'tapsaff in <place>')"


remove submodel class in BaseFactory#modelProperties

--- src/lib/base-factory.coffee
+++ src/lib/base-factory.coffee
@@ -42,9 +42,7 @@
         for prop, type of propertyInfo
             typeInfo = TYPES.info(type)
             if typeInfo.model
-                typeInfo.modelClass = @getFacade().getModel(typeInfo.model)
                 @modelProperties[prop] = typeInfo
-


Finalize Figure._glyph()

Finalize Figure._glyph()

--- bokehjs/src/coffee/api/plotting.coffee
+++ bokehjs/src/coffee/api/plotting.coffee
@@ -142,6 +142,51 @@
   triangle:          (args...) -> @_marker(models.Triangle,         args)
   x:                 (args...) -> @_marker(models.X,                args)

+  _vectorable: [
+      "fill_color", "fill_alpha",
+      "line_color", "line_alpha", "line_width",
+      "text_color", "text_alpha", "text_font_size",
+  ]
+
+  _default_color: "#1f77b4"
+  _default_alpha: 1.0
+
+  _pop_colors_and_alpha: (cls, attrs, prefix="") ->
+      result = {}
+
+      color = attrs[prefix + "color"] ? @_default_color
+      alpha = attrs[prefix + "alpha"] ? @_default_alpha
+
+      delete attrs[prefix + "color"]
+      delete attrs[prefix + "alpha"]
+
+      _update_with = (name, default_value) ->
+        if cls.prototype.props[name]?
+          result[name] = attrs[prefix + name] ? default_value
+          delete attrs[prefix + name]
+
+      _update_with("fill_color", color)
+      _update_with("line_color", color)
+      _update_with("text_color", "black")
+
+      _update_with("fill_alpha", alpha)
+      _update_with("line_alpha", alpha)
+      _update_with("text_alpha", alpha)
+
+      return result
+
+  _fixup_values: (cls, source, attrs) ->
+    for name, value of attrs
+      [prop, ...] = cls.prototype.props[name]
+
+      if prop.prototype.dataspec
+        if value?
+          if _.isArray(value)
+            source.data[name] = value
+            attrs[name] = { field: name }
+          else if _.isNumber(value) or _.isString(value) # or Date?
+            attrs[name] = { value: value }
+
   _glyph: (cls, params, args) ->
     params = params.split(",")

@@ -157,19 +202,25 @@
     source = attrs.source ? new models.ColumnDataSource()
     delete attrs.source

-    # TODO: process and pop other *_color and *_alpha attrs
-    glyph_ca   = {}
-    nsglyph_ca = {}
-    sglyph_ca  = {}
-    hglyph_ca  = {}
-    delete attrs.color
-
-    _make_glyph = (cls, attrs, ca) => new cls(attrs)
-
-    glyph   = _make_glyph(cls, attrs, glyph_ca)
+    glyph_ca   = @_pop_colors_and_alpha(cls, attrs)
+    nsglyph_ca = @_pop_colors_and_alpha(cls, attrs, "nonselection_")
+    sglyph_ca  = @_pop_colors_and_alpha(cls, attrs, "selection_")
+    hglyph_ca  = @_pop_colors_and_alpha(cls, attrs, "hover_")
+
+    @_fixup_values(cls, source,   glyph_ca)
+    @_fixup_values(cls, source, nsglyph_ca)
+    @_fixup_values(cls, source,  sglyph_ca)
+    @_fixup_values(cls, source,  hglyph_ca)
+
+    @_fixup_values(cls, source, attrs)
+
+    _make_glyph = (cls, attrs, extra_attrs) =>
+      new cls(_.extend({}, attrs, extra_attrs))
+
+    glyph   = _make_glyph(cls, attrs,   glyph_ca)
     nsglyph = _make_glyph(cls, attrs, nsglyph_ca)
-    sglyph  = _make_glyph(cls, attrs, sglyph_ca)
-    hglyph  = _make_glyph(cls, attrs, hglyph_ca)
+    sglyph  = _make_glyph(cls, attrs,  sglyph_ca)
+    hglyph  = _make_glyph(cls, attrs,  hglyph_ca)

     glyph_renderer = new models.GlyphRenderer({
       data_source:        source


accordion method works with both left and right anchors

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -313,80 +313,66 @@
         panel.style[transformProp] = 'translate3d(0, #{@panelHeight}px, 0)'

-  accordion: (angle, axis = 'h', options) ->
+  accordion: (angle, options) ->
     options = extendObj options, @_accordionDefaults
+    {anchor} = options
     angle = @_normalizeAngle angle
-    left = @panelWidth - 1
-
-    for panel, i in @vPanels
-
-      if axis is 'h'
-
-        @_resetRow i
-
-        if i % 2 isnt 0 and !options.twist
-          deg = -angle
-        else
-          deg = angle
-
-        x = left
-        ++x if angle is 90
-
-        if options.anchor
+
+    for panel, i in @panels[anchor]
+
+      switch anchor
+        when 'left'
+          y = 0
           if i is 0
             x = 0
-            deg = 0
-          else if i > 1 or options.stairs
-            deg *= 2
+          else
+            x = @panelWidth - 1
+        when 'right'
+          y = 0
+          if i is 0
+            x = @panelWidth * (@vPanels - 1)
+          else
+            x = -@panelWidth + 1
+
+      if i % 2 isnt 0 and !options.twist
+        deg = -angle
+      else
+        deg = angle
+
+      if options.sticky
+        if i is 0
+          deg = 0
+        else if i > 1 or options.stairs
+          deg *= 2
+      else
+        deg *= 2 unless i is 0
+
+      if options.fracture
+        rotation = [1, 1, 1, deg]
+      else
+        rotation = [0, 1, 0, deg]
+
+      panel.style[transformProp] = @_transform [x, y], rotation
+
+      if @shading and !(i is 0 and options.anchor) and Math.abs(deg) isnt 180
+
+        opacity = Math.abs(deg) / 90 * @shadingIntensity * .4
+
+        if anchor is 'left' or anchor is 'right'
+          if deg < 0
+            @shaders[anchor].right[i].style.opacity = 0
+            @shaders[anchor].left[i].style.opacity = opacity
+          else
+            @shaders[anchor].left[i].style.opacity = 0
+            @shaders[anchor].right[i].style.opacity = opacity
         else
-          if i is 0
-            x = 0
-          else
-            deg *= 2
-
-        if options.fracture
-          rotation = "rotate3d(1, 1, 1, #{deg}deg)"
-        else
-          rotation = "rotate3d(0, 1, 0, #{deg}deg)"
-
-      else
-        deg = 0
-
-        if i is 0
-          x = 0
-        else
-          x = @panelWidth
-
-        for hPanel, j in @hPanels[i]
-
-          if j % 2 isnt 0 and !options.twist
-            yDeg = -angle
-          else
-            yDeg = angle
-
-          if j is 0
-            y = 0
-            yDeg = 0
-          else
-            y = @panelHeight
-            yDeg
-
-
-
-      panel.style[transformProp] = "translate3d(#{x}px, 0, 0) #{rotation}"
-
-      if @settings.shading and !(i is 0 and options.anchor)
-        if axis isnt 'h'
-          opacity = 0
-        else
-          opacity = Math.abs(angle) / 90 * @settings.shadingIntensity * .4
-
-        if deg < 0
-          @rightShaders[i].style.opacity = 0
-          @leftShaders[i].style.opacity = opacity
-        else
-          @leftShaders[i].style.opacity = 0
-          @rightShaders[i].style.opacity = opacity
+          if deg < 0
+            @shaders[anchor].bottom[i].style.opacity = 0
+            @shaders[anchor].top[i].style.opacity = opacity
+          else
+            @shaders[anchor].top[i].style.opacity = 0
+            @shaders[anchor].bottom[i].style.opacity = opacity
+

     @_callback options


remove unnecessary require

remove unnecessary require

--- src/lib/list-factory.coffee
+++ src/lib/list-factory.coffee
@@ -1,5 +1,4 @@

-BaseList = require './base-list'
 BaseFactory = require './base-factory'


Use charAt rather than indexOf to check the last character of the match

--- src/lib/named-routes.coffee
+++ src/lib/named-routes.coffee
@@ -63,9 +63,10 @@
               count = 0
               prefix + route.replace pattern, (match, ..., offset) ->

-                # If the last character of `match` is an asterisk, we're dealing with a largecode
-                if match.indexOf('*') == match.length-1
-                  match = match.substring(0, match.length-1)
+                # If the last character of `match` is an asterisk, we're dealing with a largecode and need to remove it
+                # in order to support named-route directives
+                if match.charAt(match.length - 1) == '*'
+                  match = match.substring(0, match.length - 1)

                 if type(options) is 'array'
                   output = options[count]


button i18n

button i18n

--- views/components/settings/parts/poi-config.cjsx
+++ views/components/settings/parts/poi-config.cjsx
@@ -84,14 +84,14 @@
     toggleBtnStyle = if @state.enable then 'success' else 'default'
     toggleBtnStyle = 'danger' if @state.showInput
     toggleBtnTxt = if @state.enable then 'ON' else 'OFF'
-    toggleBtnTxt = 'DISABLE' if @state.showInput
+    toggleBtnTxt = __ 'Disable' if @state.showInput
     toggleBtn = <Button onClick={@handleToggleInput} bsSize='xs'
       bsStyle={toggleBtnStyle} style={verticalAlign: 'text-bottom'}>
       {toggleBtnTxt}</Button>
     inputValid = @CheckValid @state.value
     submitBtn = <Button type='submit'
       bsStyle={if inputValid then 'success' else 'danger'}>
-      {if inputValid then 'SAVE' else 'DISABLE'}</Button>
+      {if inputValid then __ 'Save' else __ 'Disable'}</Button>

       <form onSubmit={@handleSubmit}>


Fix typo

Fix typo

--- views/services/plugin-manager.cjsx
+++ views/services/plugin-manager.cjsx
@@ -85,7 +85,7 @@
     pluginPaths = yield Promise.promisify(globAsync)(path.join @pluginPath, 'node_modules', 'poi-plugin-*')
     @plugins_ = pluginPaths.map @readPlugin_
     for plugin_ in @plugins_
-      if plugin.enabled
+      if plugin_.enabled
         @loadPlugin(plugin_)
     if opt_notifyFailed
       @notifyFailed_()
@@ -458,7 +458,7 @@
       plugin.version = '0.0.0'

     plugin.pluginPath = pluginPath
-    plugin.enabled = config.get "plugin.#{newPlugin.name}.enable", true
+    plugin.enabled = config.get "plugin.#{plugin.name}.enable", true

     try
       plugin.packageData = fs.readJsonSync path.join pluginPath, 'package.json'


Revert "Revert "Fix issue #86: "Layer registration point vs originX/Y?"""

This reverts commit ecf3c54a895267f288d64b8217c60363fe2f24a5.

--- framer/LayerStates.coffee
+++ framer/LayerStates.coffee
@@ -138,7 +138,6 @@
 		keys = []

 		for stateName, state of @_states
-			continue if stateName is "default"
 			keys = _.union(keys, _.keys(state))

 		keys


Removed old tour show / hide functions

Removed old tour show / hide functions

--- core/app/assets/javascripts/tour.coffee
+++ core/app/assets/javascripts/tour.coffee
@@ -88,16 +88,6 @@
           StateMachine.ASYNC
           @state.transition()

-  hideHelpText: (step) ->
-    $("#step#{step}").fadeOut 'fast', =>
-      @state.transition()
-
-    StateMachine.ASYNC
-
-  showHelpText: (current_step) ->
-    setTimeout =>
-      $("#step#{current_step}").fadeIn 'fast'
-    , @helpTextDelay

 _.extend window.InteractiveTour.prototype, Backbone.Factlink.TooltipMixin


Fixed motif/Company#203

Fixed motif/Company#203

--- framer/Components/PageComponent.coffee
+++ framer/Components/PageComponent.coffee
@@ -68,7 +68,7 @@
 		return _.first(layers)

 	snapToPage: (page, animate=true, animationOptions=null) ->
-		@scrollToLayer(page, @originX, @originY, true, animationOptions)
+		@scrollToLayer(page, @originX, @originY, animate, animationOptions)

 	snapToNextPage: (direction="right", animate=true, animationOptions=null) ->
 		animationOptions ?= @animationOptions


set focus on textbox when opening add box

--- src/main/coffee/main.coffee
+++ src/main/coffee/main.coffee
@@ -39,6 +39,7 @@
     @route "news/:uid/feeds/add", (uid) ->
         this._uid = uid
         $("#addFeedUrl").val(this.urlParams["url"])
+        $("#addFeed").on("shown.bs.modal", () -> $("#addFeedUrl").focus())
         $("#addFeed").modal()

     @route "news/:uid/feeds/:fid", (uid, fid) ->


test failed

test failed

--- src/main/coffee/main.coffee
+++ src/main/coffee/main.coffee
@@ -497,8 +497,7 @@
                     successWrapper,
                     errorWrapper)
             else
-                NR.API.GetAllPostsInMultipleFeeds(
-                    this.feedList.filter((i) -> i.numUnread > 0).map((i) -> i.id),
+                NR.API.GetAllPosts(
                     0,
                     lastArticleId,
                     this._maxId,


death-star checking is much less fragile

--- src/scripts/jenkins-notifier.coffee
+++ src/scripts/jenkins-notifier.coffee
@@ -95,7 +95,7 @@
               console.log res.statusCode
             robot.messageRoom "#release", "Identity service hotfix has been release!"
             robot.messageRoom "#release", "I hope you know what you're doing..."
-          if data.build.parameters.SERVER_HOSTNAME == 'deathstar.1stdibs.com'
+          if data.build and data.build.parameters and data.build.parameters.SERVER_HOSTNAME == 'deathstar.1stdibs.com'
             http.get 'http://xserve:5051/deathstar', (res) ->
               console.log res.statusCode
             robot.messageRoom "#dev", "The Death Star is now fully armed and operational"


Don't wait forever when message refresh clicked call callback after 7 seconds

--- client/landing/app/Applications/Inbox.kdapplication/Controllers/InboxMessageListController.coffee
+++ client/landing/app/Applications/Inbox.kdapplication/Controllers/InboxMessageListController.coffee
@@ -1,15 +1,16 @@
 class InboxMessageListController extends KDListViewController
-
+
   constructor:()->
     super
     @selectedMessages = {}
-
+
   loadMessages:(callback)->
     @removeAllItems()
+    @utils.wait 7000, => callback?()
     KD.whoami().fetchMail
       limit       : 20
       sort        :
         timestamp : -1
     , (err, messages)=>
       @instantiateListItems messages
-      callback?()
+      callback?()


Fixed error when treeData is an object (not an array).

--- src/abn_tree_directive.coffee
+++ src/abn_tree_directive.coffee
@@ -37,8 +37,8 @@
       return

     if !scope.treeData.length?
-      if treeData.label?
-        scope.treeData = [ treeData ]
+      if scope.treeData.label?
+        scope.treeData = [ scope.treeData ]
       else
         alert 'treeData should be an array of root branches'
         return


Rename user-setting for proposed MRU-disabling feature

--- .config/config.cson
+++ .config/config.cson
@@ -57,6 +57,7 @@
   "toggle-quotes": {}
   "tree-view":
     hideIgnoredNames: true
+    openFilesWithSingleClick: true
   welcome:
     showOnStartup: false
   whitespace:


another key binding for entering edit mode

--- app/assets/javascripts/lists.js.coffee
+++ app/assets/javascripts/lists.js.coffee
@@ -402,11 +402,13 @@
       App.mainList.view.selectPrevious()
     "down"         : ->
       App.mainList.view.selectNext()
-    "k"           : ->
+    "k"            : ->
       App.mainList.view.selectPrevious()
-    "j"         : ->
+    "j"            : ->
       App.mainList.view.selectNext()
     "esc"          : ->
+      App.mainList.view.switchItem()
+    "i"            : ->
       App.mainList.view.switchItem()
     "ctrl+up"      : ->
       App.mainList.view.moveSelectionUp()


fix "x" positions

fix "x" positions

--- intervals.coffee
+++ intervals.coffee
@@ -395,7 +395,7 @@
       ctx.beginPath()
       ctx.arc h_gutter + string * string_spacing, y, string_spacing / 2, Math.PI/2, Math.PI*3/2, false
       ctx.arc h_gutter + (string + string_count - 1) * string_spacing, y, string_spacing / 2
-        , Math.PI*3/2, Math.PI/2, false
+        , Math.PI * 3/2, Math.PI * 1/2, false
       ctx.fillStyle = 'rgba(0,0,0, 0.5)'
       ctx.fill()
     # positions = remove_barre_fingerings(barres, positions)
@@ -408,7 +408,10 @@
       continue if fretted_strings[string_number]
       ctx.font = "#{closed_string_fontsize}pt Helvetica"
       ctx.fillStyle = 'black'
-      ctx.fillText "x", h_gutter + string_number * string_spacing - 1, v_gutter + above_fretboard - 2.5
+      m = ctx.measureText("x")
+      ctx.fillText "x"
+      , h_gutter + string_number * string_spacing - m.width / 2
+      , v_gutter + above_fretboard - fret_height * 0.5 + m.emHeightDescent

 draw_intervals_from = (root_position, semitones, color) ->
   root_note_number = pitch_number_for_position(root_position)


The dropzone gets reset now if no more files.

Closes #36

--- src/dropzone.coffee
+++ src/dropzone.coffee
@@ -59,6 +59,7 @@
     "sending"
     "success"
     "complete"
+    "reset"
   ]

@@ -136,6 +137,10 @@
     selectedfiles: (files) ->
       @element.addClass "started"

+    # Called whenever there are no files left in the dropzone anymore, and the
+    # dropzone should be displayed as if in the initial state.
+    reset: ->
+      @element.removeClass "started"

     # Called when a file is added to the queue
     # Receives `file`
@@ -385,8 +390,10 @@
   removeFile: (file) ->
     throw new Error "Can't remove file currently processing" if file.processing
     @files = without @files, file
+    @filesQueue = without @filesQueue, file

     @emit "removedfile", file
+    @emit "reset" if @files.length == 0

   createThumbnail: (file) ->

@@ -446,7 +453,7 @@
     i = processingLength

     while i < parallelUploads
-      return  unless @filesQueue.length # Nothing left to process
+      return unless @filesQueue.length # Nothing left to process
       @processFile @filesQueue.shift()
       i++


Add class to hidden input

Add class to hidden input

This adds a className to the hidden uploader input so that automated test cases can find it programmatically.

--- src/dropzone.coffee
+++ src/dropzone.coffee
@@ -488,6 +488,7 @@
         @hiddenFileInput = document.createElement "input"
         @hiddenFileInput.setAttribute "type", "file"
         @hiddenFileInput.setAttribute "multiple", "multiple" if !@options.maxFiles? || @options.maxFiles > 1
+        @hiddenFileInput.className = "dz-hidden-input"

         @hiddenFileInput.setAttribute "accept", @options.acceptedFiles if @options.acceptedFiles?


Handle when expiration variable isn't set

--- app/assets/javascripts/problems.coffee
+++ app/assets/javascripts/problems.coffee
@@ -32,6 +32,8 @@
     return

   # Update deadlines
+  if typeof expiration == 'undefined'
+    expiration = 0
   deadline = new Date(Date.parse(new Date) + expiration * 1000)

   getTimeRemaining = (endtime) ->


bounds in progress map

bounds in progress map

--- app/assets/javascripts/progress.coffee
+++ app/assets/javascripts/progress.coffee
@@ -5,10 +5,14 @@
 			zoomControl: false
 			animate: true
 			attributionControl: false
-			minZoom: 8
+			minZoom: 12
 			maxZoom: 20
 			dragging: true
+			maxBounds: new L.LatLngBounds(new L.LatLng(40.791289,-74.040598), new L.LatLng(40.683883,-73.942495))
 		)
+	# var NE = new L.LatLng(41.0053,-74.4234),
+ #    SW = new L.LatLng(40.3984,-73.5212),
+ #    NYCbounds = new L.LatLngBounds(SW, NE);

 		$("#score .total").on 'click', () ->
 			location.href = "/fixer/building"


The place string ("4/11") now looks even better in various sizes. At least in Chrome.

--- app/assets/javascripts/roofpig/DomHandler.js.coffee
+++ app/assets/javascripts/roofpig/DomHandler.js.coffee
@@ -9,6 +9,7 @@
     @div.append(renderer.domElement);

     @scale = @div.width()/400
+    console.log("scale:#{@scale}")

   has_focus: (has_it) ->
     color = if has_it then 'gray' else '#eee'
@@ -63,7 +64,7 @@

   _scale: (button_area_element) ->
     @button_area.append(button_area_element)
-    button_area_element.height(40 * @scale).width(72 * @scale - 12).css("font-size", 32 * @scale)
+    button_area_element.height(40 * @scale).width(80 * @scale - 16).css("font-size", 32 * @scale) # -16 = 2x6px margin +2x2px border

   _make_place_area: ->
     place_div = $("<div/>", { id: "place" }).css("text-align": 'right', 'float': 'right')


Use a selector in call to $().on to allow delegation of events

This means that we don't have to rebind to our new form on element replace

--- app/assets/javascripts/votes.js.coffee
+++ app/assets/javascripts/votes.js.coffee
@@ -1,5 +1,5 @@
 $(document).ready ->
-  $(".vote-form").on 'ajax:success', (event, xhr, status) ->
+  $(".vote-controls").on 'ajax:success', '.vote-form', (event, xhr, status) ->
     $(this).parent().find('.vote-count').html(xhr.count)
     $(this).replaceWith(xhr.content)


#46 handle old style #channel urls

#46 handle old style #channel urls

--- meteor/client/router.coffee
+++ meteor/client/router.coffee
@@ -1,4 +1,7 @@
 Router.route '/', ->
+  if location.hash
+    Router.go '/' + location.hash.slice(1)
+
   @render 'home'
   mtrPlayer.setChannel ''


Drag Rows Functionality

Drag Rows Functionality

--- app/classifier/drawing-tools/grid.cjsx
+++ app/classifier/drawing-tools/grid.cjsx
@@ -85,22 +85,51 @@

   renderRow: ->
     totalPoints = []
-    for cell in @state.row
-      points = @pointParser cell
-      totalPoints.push points
+    if @props.mark.renderDrag is true
+      for cell in @state.row
+        points = @pointRow cell
+        totalPoints.push points
+    else
+      @props.mark.x = Infinity
+      for cell in @state.row
+        points = @pointParser cell # know if it's the first or second time to parse. if second, it won't be able to move left and right due to pointParser
+        @markRow(cell)  # turn that dang mark into a row
+        totalPoints.push points
     <Draggable onDrag={@handleRowDrag} onEnd={deleteIfOutOfBounds.bind null, this} disabled={@props.disabled}>
       <polyline key={Math.random()} points={totalPoints.join()} />
     </Draggable>

+  markRow: (cell) ->
+    if cell.x < @props.mark.x
+      @props.mark.x = cell.x
+    if cell.x > @props.mark.x
+      @props.mark.width = (cell.x + cell.width - @props.mark.x)
+
   handleRowDrag: (e, d) ->
+    @props.mark.renderDrag = true
     @props.mark.x += d.x / @props.scale.horizontal
     @props.mark.y += d.y / @props.scale.vertical
-    @props.onChange @props.mark # this should be updated to reflect row
+    newRows = @state.row
+    for cell in newRows
+      cell.x += d.x / @props.scale.horizontal
+      cell.y += d.y / @props.scale.vertical
+    @setState row: newRows
+    @props.onChange @props.mark

   handleMainDrag: (e, d) ->
     @props.mark.x += d.x / @props.scale.horizontal
     @props.mark.y += d.y / @props.scale.vertical
     @props.onChange @props.mark
+
+  pointRow: (cell) ->
+    {y, height} = @props.mark #now do this according to state, or mark?
+    points = [
+      [cell.x, y].join ','
+      [cell.x + cell.width, y].join ','
+      [cell.x + cell.width, y + height].join ','
+      [cell.x, y + height].join ','
+      [cell.x, y].join ','
+    ].join '\n'

   pointFinder: (mark) ->
     {x, y, width, height} = mark


Add method #focusDrawingTool to maintain the window scroll when drawing tools are created, selected, or deleted.

--- app/classifier/drawing-tools/root.cjsx
+++ app/classifier/drawing-tools/root.cjsx
@@ -25,8 +25,10 @@
   getInitialState: ->
     destroying: false

+  # In Chrome, refocusing the drawing tool without keeping track of scrollX and scrollY
+  # would scroll volunteers to the top of an image upon drawing tool creation, selection, and deletion.
   componentDidMount: ->
-    @root?.focus()
+    @focusDrawingTool()

   render: ->
     toolProps = @props.tool.props
@@ -49,7 +51,7 @@

     unless toolProps.disabled
       startHandler = (e) =>
-        @root?.focus()
+        @focusDrawingTool()
         toolProps.onSelect(e)

     <g className="drawing-tool" {...rootProps} {...@props}>
@@ -91,3 +93,9 @@
   handleDetailsFormClose: ->
     # TODO: Check if the details tasks are complete.
     @props.tool.props.onDeselect?()
+
+  focusDrawingTool: ->
+    x = window.scrollX
+    y = window.scrollY
+    @root?.focus()
+    window.scrollTo(x, y)


add _ to token regexp. Devise sometimes generates these.

--- app/js/controllers/authentication_controller.coffee
+++ app/js/controllers/authentication_controller.coffee
@@ -16,7 +16,7 @@
     _redirectTo(window.ENV.apiHost + '/sign_out')

   extractAccessToken: ->
-    match = location.href.match(/authentication_token=([a-zA-Z0-9]+)/)
+    match = location.href.match(/authentication_token=([a-zA-Z0-9_]+)/)
     if (match)
       @set('accessToken', match[1])
       location.href = location.origin


add missing displayName

add missing displayName

--- client/lanes/workspace/ScreenView.cjsx
+++ client/lanes/workspace/ScreenView.cjsx
@@ -1,8 +1,7 @@
 Screen = React.createClass
-
+    displayName: 'Screen'
     shouldComponentUpdate: ->
         false
-
     render: ->
         React.createElement(@props.screen.component(), @props.screen.props)


small function separation

small function separation

--- app/Scrapbook.coffee
+++ app/Scrapbook.coffee
@@ -15,8 +15,7 @@
         className: 'new'
         onSubmit: @handleSubmit
       ,
-        (input {ref: 'from', name: 'from', placeholder: 'your scrapbook URL, if you have one'})
-        (input {ref: 'name', name: 'name', placeholder: 'your name, optionally'})
+        (input {ref: 'from', name: 'from', placeholder: 'your scrapbook URL, if you have one, or your name'})
         (textarea {ref: 'content', name: 'content'})
         (button
           type: 'submit'
@@ -37,31 +36,40 @@
     e.preventDefault()

     try
-      val = @refs.from.getDOMNode().value
-      throw {} if not val
+      homeurl = @refs.from.getDOMNode().value
+      throw {} if not homeurl

-      home = getQuickBasePath val
-      superagent.put(home + '/elsewhere')
-                .send({
-                  content: @refs.content.getDOMNode().value
-                  target: location.href
-                })
-                .withCredentials()
-                .end (err, res) =>
+      @postHomeFirst homeurl, (err, srcid, home) =>
         throw {} if err
-
-        body = JSON.parse res.text
-        throw {} if not body.ok
-
-        @submitScrap(body.id, home)
+        @submitScrap(srcid, home)

     catch e
       @submitScrap()

-  submitScrap: (srcid, from) ->
+  postHomeFirst: (homeurl, callback) ->
+    home = getQuickBasePath homeurl
+    superagent.put(home + '/elsewhere')
+              .send({
+                content: @refs.content.getDOMNode().value
+                target: getQuickBasePath location.href
+              })
+              .withCredentials()
+              .end (err, res) =>
+      callback err if err
+
+      body = JSON.parse res.text
+      callback true if not body.ok
+
+      callback null, body.id, home
+
+  submitScrap: (srcid, from, name) ->
     payload =
       content: @refs.content.getDOMNode().value
-      name: @refs.name.getDOMNode().value
+
+    if name
+      payload.name = name
+    else
+      name = @refs.from.getDOMNode().value

     if srcid
       payload.srcid = srcid


Raise timeout for starting handoff

Raise timeout for starting handoff

On a production instance that is having memory leak trouble, we're seeing
the ACK on this come back after the timeout, which causes the handoff to
not move forward.

This change improves the situation, but doesn't fix the issue: If we fail
to start a handoff, either the old or new instances need to die. Right now
both can stay alive, though the new instances would never get a server handle.

--- src/streammachine/modes/base.coffee
+++ src/streammachine/modes/base.coffee
@@ -34,7 +34,7 @@

                 @log.info "Sending process for USR2. Starting handoff via proxy."

-                @_rpc.request "HANDOFF_GO", null, null, timeout:10000, (err,reply) =>
+                @_rpc.request "HANDOFF_GO", null, null, timeout:20000, (err,reply) =>
                     if err
                         @log.error "Error handshaking handoff: #{err}"
                         @_restarting = false


insights: Put number of matches in error

--- src/insights.coffee
+++ src/insights.coffee
@@ -34,7 +34,8 @@
     return callback err if err
     return callback new Error "#{body.error}" if body.error

-    return callback new Error 'Number of events for interval hit max limit' if body.performanceStats.matchCount >= limit
+    matches = body.performanceStats.matchCount
+    return callback new Error "Number of events for interval was above max limit #{matches}" if matches >= limit
     results = body.results[0].events
     return callback new Error 'No results returned' if not results? # empty array is fine though


Wait till save finishes before closing the overlay

Hides “flash” of newly created cards if we’re deleting a card that event
stream created too soon

--- app/assets/javascripts/controllers/overlays/new_message_card_overlay_controller.js.coffee
+++ app/assets/javascripts/controllers/overlays/new_message_card_overlay_controller.js.coffee
@@ -20,5 +20,4 @@
           initialComment.save()
         else
           initialComment.deleteRecord()
-
-      @send('closeOverlay')
+        @send('closeOverlay')


Add debug log again

Add debug log again

--- src/coffee/stockimport.coffee
+++ src/coffee/stockimport.coffee
@@ -261,6 +261,7 @@
       else
         @client.inventoryEntries.create(entry)

+    @logger.debug "About to send #{_.size posts} requests"
     Q.all(posts)

 module.exports = StockImport


Fixed #42

Fixed #42

--- app/lib/steps.coffee
+++ app/lib/steps.coffee
@@ -63,6 +63,7 @@
     options: [
       'male'
       'female'
+      'unidentifiable'
     ]

 stepChimpBehavior =


Annotate.js on one hallobutton

Annotate.js on one hallobutton

--- src/plugins/annotate.coffee
+++ src/plugins/annotate.coffee
@@ -2,41 +2,54 @@
     z = new VIE
     z.use new z.StanbolService
         proxyDisabled: true
-        url : "http://dev.iks-project.eu:8081",
+        url : 'http://dev.iks-project.eu:8081',

-    jQuery.widget "IKS.halloannotate",
+    jQuery.widget 'IKS.halloannotate',
         options:
             vie: z
             editable: null
             toolbar: null
+            uuid: ''
             select: ->
             decline: ->
             remove: ->

         _create: ->
-            widget = this
-            widget.buttons = {}
+          widget = @
+          # states are off, working, on
+          @state = 'off'

-            buttonset = jQuery ""
-            buttonize = (cmd, label) =>
-                id = "#{@options.uuid}-#{cmd}"
-                buttonset.append jQuery("<input id=\"#{id}\" type=\"checkbox\" />#{label}").button()
-                button = jQuery "##{id}", buttonset
-                button.attr "hallo-command", cmd
-                button.bind "change", (event) ->
-                    cmd = jQuery(this).attr "hallo-command"
-                    do widget[cmd]
-                widget.buttons[cmd] = button
+          buttonHolder = jQuery ''
+          @button = buttonHolder.hallobutton
+            label: ''
+            icon: 'icon-tags'
+            editable: @options.editable
+            command: null
+            uuid: @options.uuid
+          buttonHolder.bind 'change', (event) =>
+            console.info @, arguments
+            switch @state
+              when 'off' then @enhance()
+              when 'on' then @done()

-            buttonize "enhance", "Enhance"
-            buttonize "done", "Done"
-            buttonize "acceptAll", "Accept all"
-            buttonset.buttonset()
+          @options.toolbar.append @button
+          @instantiate()

-            widget.buttons.done.button "disable"
-            widget.buttons.acceptAll.button "disable"
-            @options.toolbar.append buttonset
-            @instantiate()
+          editableElement = @options.editable.element
+          queryState = (event) =>
+            if document.queryCommandState @options.command
+              @button.attr 'checked', true
+              @button.next('label').addClass 'ui-state-clicked'
+              @button.button 'refresh'
+              return
+            @button.attr 'checked', false
+            @button.next('label').removeClass 'ui-state-clicked'
+            @button.button 'refresh'
+
+          editableElement.bind 'halloenabled', =>
+            editableElement.bind 'keyup paste change mouseup hallomodified', queryState
+          editableElement.bind 'hallodisabled', =>
+            editableElement.unbind 'keyup paste change mouseup hallomodified', queryState

         instantiate: ->
@@ -51,36 +64,28 @@
             # @buttons.acceptAll.hide()
         acceptAll: ->
             @options.editable.element.each ->
-                jQuery(this).annotate "acceptAll", (report) ->
-                    console.log "AcceptAll finished with the report:", report
+                jQuery(this).annotate 'acceptAll', (report) ->
+                    console.log 'AcceptAll finished with the report:', report

-            @buttons.acceptAll.button "disable"
+            @buttons.acceptAll.button 'disable'

         enhance: ->
             widget = @
-            console.info ".content", @options.editable.element
-            origLabel = @buttons.enhance.button( "option", "label" )
-            @buttons.enhance.button("disable")
-#            .button "option", "label", "in progress..."
+            @button.hallobutton "disable"
+            console.info '.content', @options.editable.element
             try
-                @options.editable.element.annotate "enable", (success) =>
+                @options.editable.element.annotate 'enable', (success) =>
                     if success
-#                        @buttons.enhance.button("disable").button "option", "label", origLabel
-                        @buttons.enhance.button "enable"
-                        @buttons.enhance.button "disable"
-                        @buttons.done.button "enable"
-                        @buttons.acceptAll.button "enable"
-                        console.log "done"
+                        @state = "on"
+                        @button.hallobutton "enable"
+                        console.log 'done'
                     else
                         @buttons.enhance.show()
-                        .button("enable")
-                        .button "option", "label", "error, see the log.. Try to enhance again!"
+                        .button('enable')
+                        .button 'option', 'label', 'error, see the log.. Try to enhance again!'
             catch e
                 alert e
         done: ->
-            @options.editable.element.annotate "disable"
-            @buttons.enhance.button "enable"
-
-            @buttons.done.button "disable"
-            @buttons.acceptAll.button "disable"
+            @options.editable.element.annotate 'disable'
+            @state = 'off'
 )(jQuery)


Fix incorrect language about starter license purchase limits

--- app/locale/en.coffee
+++ app/locale/en.coffee
@@ -976,7 +976,7 @@
     project_based_title: "Project-Based Courses"
     project_based_description: "Web and Game Development courses feature shareable final projects."
     great_for_clubs_title: "Great for clubs and electives"
-    great_for_clubs_description: "Teachers can purchase up to __maxQuantityStarterLicenses__ Starter Licenses per year."
+    great_for_clubs_description: "Teachers can purchase up to __maxQuantityStarterLicenses__ Starter Licenses." #{change}
     low_price_title: "Just __starterLicensePrice__ per student"
     low_price_description: "Starter Licenses are active for __starterLicenseLengthMonths__ months from purchase."
     three_great_courses: "Three great courses included in the Starter License:"


fully async now

fully async now

--- app/cloud-box.coffee
+++ app/cloud-box.coffee
@@ -43,13 +43,11 @@

    ############################################### CONFIG ###############################################

-   app.configure('development', () ->
+   app.configure 'development', () ->
       USE_SSL = no
-   )

-   app.configure('production', () ->
+   app.configure 'production', () ->
       USE_SSL = yes
-   )

    ############################################### HELPERS ###############################################

@@ -57,63 +55,61 @@
       response.statusCode = 404
       response.end()

-   latestVersionForLocalResource = (resource) ->
+   latestVersionForLocalResource = (resource, callback) ->
       local_path = "res/#{resource}"

-      if fs.existsSync(local_path)#foo
-         fs.readdirSync(local_path).reduce (a,b) -> Math.max a, b
-      else
-         null
+      fs.exists local_path, (exists) ->
+         if exists
+            fs.readdir local_path, (err, files) ->
+               callback files.reduce (a,b) -> Math.max a, b
+         else
+            null

    publicPathForLocalResource = (request, resource) ->
       protocol = if USE_SSL then "https" else "http"
       "#{protocol}://#{request.headers.host}/#{RESOURCES_DATA_PATH}/#{resource}"

-   localPathForLocalResource = (resource) ->
-      "res/#{resource}/#{latestVersionForLocalResource(resource)}"
+   localPathForLocalResource = (resource, callback) ->
+      latestVersionForLocalResource resource, (latestVersion) ->
+         callback "res/#{resource}/#{latestVersion}"

    ############################################### META ROUTE ###############################################

-   app.get("/#{RESOURCES_META_PATH}/:resource_identifier", (request, response) ->
+   app.get "/#{RESOURCES_META_PATH}/:resource_identifier", (request, response) ->
       identifier = request.params.resource_identifier

       #if its a local resource, get the public path. if its an external resource the path is already set
       if identifier in RESOURCES_MANIFEST_LOCAL
-         response.setHeader 'Content-Type', 'application/json'
+         latestVersionForLocalResource identifier, (latestVersion) ->
+            response.setHeader 'Content-Type', 'application/json'

-         response.end(JSON.stringify({
-            "v" : latestVersionForLocalResource(identifier),
-            "url" : publicPathForLocalResource(request, identifier)
-         }))
+            response.end(JSON.stringify({
+               "v" : latestVersion,
+               "url" : publicPathForLocalResource(request, identifier)
+            }))
       else if resource = RESOURCES_MANIFEST_EXTERNAL[identifier]
          response.end(JSON.stringify(resource))
       else
          error400(request, response)
-   )

    ############################################### DATA ROUTE ###############################################

-
-   app.get("/#{RESOURCES_DATA_PATH}/:resource_identifier", (request, response) ->
+   app.get "/#{RESOURCES_DATA_PATH}/:resource_identifier", (request, response) ->
       identifier = request.params.resource_identifier

       #get path
-      path = localPathForLocalResource(identifier)
-
-      #make sure file exists
-      fs.exists(path, (exists) ->
-         if exists
-            response.sendFile(path)
-         else
-            error400(request, response)
-      )
-   )
+      localPathForLocalResource identifier, (path) ->
+         #make sure file exists
+         fs.exists path, (exists) ->
+            if exists
+               response.sendfile(path)
+            else
+               error400(request, response)

    ############################################### LAUNCH ###############################################

-   server.listen(PORT, () ->
+   server.listen PORT, () ->
       console.log("GBCloudBox Server: Listening on port " + PORT + "!")
-   )

 # Export server as start function which when called starts the server
 exports.start = cloudBox


Change loop concept to be specifically while loops

--- app/locale/en.coffee
+++ app/locale/en.coffee
@@ -1408,7 +1408,7 @@
     strings: "Strings"
     variables: "Variables"
     vectors: "Vectors"
-    while_loops: "Loops"
+    while_loops: "While Loops" # {change}
     recursion: "Recursion"

   delta:


Update ja.coffee

Update ja.coffee

--- app/locale/ja.coffee
+++ app/locale/ja.coffee
@@ -255,8 +255,8 @@
     victory_new_item: "ニューアイテム"
     victory_viking_code_school: "あなたはハードレベルのホーリー・スモークを打ち破りました! もしあなたが既にソフトウェア開発者でないなら, ぜひやってみましょう. あなたはちょうどViking Code Scoolで受け入れられるための出世街道にいます,そこでは次のレベルへのスキルを取得でき、14週間でプロのWeb開発者になれます。"
     victory_become_a_viking: "バイキングになる"
-#    victory_bloc: "Great work! Your skills are improving, and someone's taking notice. If you've considered becoming a software developer, this may be your lucky day. Bloc is an online bootcamp that pairs you 1-on-1 with an expert mentor who will help train you into a professional developer! By beating A Mayhem of Munchkins, you're now eligible for a $500 price reduction with the code: CCRULES"
-#    victory_bloc_cta: "Meet your mentor – learn about Bloc"
+    victory_bloc: "すばらしい偉業ですね！あなたのスキルは伸びています、そしてそれに注目している人もいます。もしあなたがソフトウェア開発者になろうと考えているなら今日は幸運な日です。Blocはエキスパートのメンターが一対一であなたをプロの開発者に訓練するブートキャンプです！Mayhem of Munchkinsを倒したあなたはコードにより500ドルの割引の対象となっています。: CCRULES"
+    victory_bloc_cta: "あなたのメンターに会う – Blockについて学ぶ"
     guide_title: "ガイド"
     tome_minion_spells: "操作できるキャラクターの呪文" # Only in old-style levels.
     tome_read_only_spells: "読込専用の呪文" # Only in old-style levels.
@@ -401,7 +401,7 @@

   subscribe:
     comparison_blurb: "CodeCombatへ課金してスキルを磨きましょう！"
-    feature1: "100以上の基本レベルが４つの世界に" # {change}
+    feature1: "110以上の基本レベルが４つの世界に" # {change}
     feature2: "10人のパワフルな ニューヒーロー とユニークなスキル!" # {change}
     feature3: "70以上のボーナスレベル"
     feature4: "3500のジェムが毎月ボーナス!"
@@ -607,14 +607,14 @@
     intro_2: "プログラミングの経験は必要ありません！"
     free_title: "価格について"
 #    cost_china: "CodeCombat in China is free for the first five levels, after which it costs $9.99 USD per month for access to our other 180+ levels on our exclusive China servers."
-    free_1: "CodeCombat は基本的に無料です！100以上のレベルが無料です。" # {change}
+    free_1: "CodeCombat は基本的に無料です！110以上のレベルが無料です。" # {change}
     free_2: "月々の課金をするとビデオのチュートリアルにアクセスでき、また追加のレベルが楽しめます。"
     teacher_subs_title: "教育関係者は無料のサブスクリプションを得ることができます！"
     teacher_subs_1: "" # {change}
     teacher_subs_2: "に連絡して無料の月々のサブスクリプションを得ましょう。" # {change}
 #    teacher_subs_3: "to set up your subscription."
     sub_includes_title: "サブスクリプションの内容について"
-    sub_includes_1: "100以上の基本レベルに加えて、生徒は月々のサブスクリプションを得て次の機能が使えます:" # {change}
+    sub_includes_1: "110以上の基本レベルに加えて、生徒は月々のサブスクリプションを得て次の機能が使えます:" # {change}
     sub_includes_2: "70以上の練習レベル"
     sub_includes_3: "ビデオチュートリアル"
     sub_includes_4: "メールによるサポート"
@@ -836,7 +836,7 @@
     latest_achievement: "最新業績"
     playtime: "プレイ時間"
     last_played: "最終プレイ"
-#    leagues_explanation: "Play in a league against other clan members in these multiplayer arena instances."
+    leagues_explanation: "リーグで他のマルチアリーナインスタンス内の他のクランメンバーとプレイ"

   classes:
     archmage_title: "アークメイジ"
@@ -1077,7 +1077,7 @@
 #    tournament_blurb_blog: "on our blog"
     rules: "ルール"
     winners: "勝者"
-#    league: "League"
+    league: "リーグ"

   user:
     stats: "ステータス"