Fixed #2406.

Fixed #2406.

--- app/views/play/level/tome/SpellView.coffee
+++ app/views/play/level/tome/SpellView.coffee
@@ -221,6 +221,8 @@
       bindKey: 'Space'
       exec: =>
         disableSpaces = @options.level.get('disableSpaces') or false
+        aceConfig = me.get('aceConfig') ? {}
+        disableSpaces = false if aceConfig.keyBindings and aceConfig.keyBindings isnt 'default'  # Not in vim/emacs mode
         if not disableSpaces or (_.isNumber(disableSpaces) and disableSpaces < me.level())
           return @ace.execCommand 'insertstring', ' '
         line = @aceDoc.getLine @ace.getCursorPosition().row
@@ -266,6 +268,8 @@
       return
     return unless @spell.source is @spell.originalSource or force
     return if @isIE()  # Temporary workaround for #2512
+    aceConfig = me.get('aceConfig') ? {}
+    return if aceConfig.keyBindings and aceConfig.keyBindings isnt 'default'  # Don't lock in vim/emacs mode

     console.info 'Locking down default code.'

@@ -915,8 +919,8 @@
       return
     else
       @ace.insert "{x: #{e.x}, y: #{e.y}}"
-
-
+
+
     @highlightCurrentLine()

   onStatementIndexUpdated: (e) ->


updated dronewar to turn off fire timer in root element if destroyed

--- games/dronewar/src/objects/root.coffee
+++ games/dronewar/src/objects/root.coffee
@@ -27,6 +27,7 @@

   fire: () =>
     timestamp   = Utils.timestamp()
+    return true if @destroyed
     return unless @collision and timestamp - @lastfire > @wait
     @lastfire   = timestamp
     bullet      = new Bullet()
@@ -123,4 +124,4 @@
       .duration(dur * 0.25 )
       .ease('sqrt')
       .style("opacity", 0)
-    @bitmap.transition().duration(dur).attr('opacity', 0)  +    @bitmap.transition().duration(dur).attr('opacity', 0).each('end', => @destroy())


skip clean during build

skip clean during build

--- natal.coffee
+++ natal.coffee
@@ -292,7 +292,7 @@
          -workspace native/ios/#{name}.xcworkspace
          -scheme #{name}
          -destination platform='iOS Simulator',OS=latest,id='#{device}'
-         clean test
+         test
          "

     log 'Launching simulator'


update om-next to alpha14

update om-next to alpha14

--- natal.coffee
+++ natal.coffee
@@ -26,7 +26,7 @@
 process.title   = 'natal'
 reactInterfaces =
   om:        'org.omcljs/om "0.9.0"'
-  'om-next': 'org.omcljs/om "1.0.0-alpha11"'
+  'om-next': 'org.omcljs/om "1.0.0-alpha14"'

 interfaceNames   = Object.keys reactInterfaces
 defaultInterface = 'om'


Fix typo

Fix typo

--- lib/util/form-view.coffee
+++ lib/util/form-view.coffee
@@ -91,7 +91,7 @@
       field.setAttribute "value", 0
       field.setAttribute "max", 100

-    if type = "minieditor"
+    if type == "minieditor"
       field.setAttribute("mini", "mini")
       # field.tabIndex = "0"


Fixed truncation. Again.

Fixed truncation. Again.

--- app/assets/javascripts/calendar.js.coffee
+++ app/assets/javascripts/calendar.js.coffee
@@ -21,14 +21,19 @@
   truncate_to_now: =>
     start_time = new Date($(".room-data-wrap").data("start"))
     current_time = new Date()
-    difference = current_time - start_time
+    compare_time = new Date(start_time.getTime())
+    compare_time.setDate(current_time.getDate())
+    compare_time.setMonth(current_time.getMonth())
+    compare_time.setFullYear(current_time.getFullYear())
+    difference = current_time - compare_time
     current_hour = Math.floor(difference/1000/60/60)
     bar_length = current_hour*60*60/180
     hour_elements = $(".tab-content div").filter( -> $(this).data("hour") < current_hour)
     hour_elements.show()
     $("div").filter( -> $(this).data("old-height")?).each (key, item) ->
       $(this).height($(this).data("old-height"))
-    return unless [current_time.getFullYear(), current_time.getMonth()+1, current_time.getDate()].toString() == @date_selected.toString()
+    console.log(current_time - start_time)
+    return if current_time < start_time || (current_time - start_time) > 24*60*60*1000
     $(".tab-pane").show()
     $(".room-data").each (key, item) =>
       $(item).data("old-height", $(item).height())
@@ -41,7 +46,6 @@
       if start_at < bar_length
         if end_at > bar_length
           if(item.data("start")?)
-            console.log(current_hour)
             new_time = new Date(current_time.getTime())
             new_time.setHours(0)
             new_time.setSeconds(0)


optimize html rendering

optimize html rendering

Now pic will not blink when user inputing

Changes:
1. Change html_post_process() to async returing a Promise
2. render_html() would render html two times previously, now only one
time (another time is for rendering a temp dom not attached to document,
so pic will not blink)

--- app/assets/javascripts/app.coffee
+++ app/assets/javascripts/app.coffee
@@ -171,20 +171,31 @@
   # markdown render functions
   # ------------------------------------------------------------------------------------------------------------------
   vm.render_html = (jq_html_div) ->
-    jq_html_div.html($window.marked(vm.get_md(), {sanitize: true}))
-    vm.html_post_process(jq_html_div)
-
-  vm.html_post_process = (jq_html_div) ->
-    # code highliting
-    jq_html_div.find('pre code').each (i, block) ->
+    processed_md = vm.md_pre_process(vm.get_md())
+    _html_dom = $('

')
+    _html_dom.html($window.marked(processed_md, {sanitize: true}))
+    vm.html_post_process(_html_dom).then () ->
+      jq_html_div.empty()
+      jq_html_div.append(_html_dom)
+
+  vm.md_pre_process = (md) ->
+    # TODO more handling
+    processed_md = md
+    return processed_md
+
+  # return promise
+  vm.html_post_process = (jq_tmp_div) ->
+    # code highlighting
+    jq_tmp_div.find('pre code').each (i, block) ->
       hljs.highlightBlock(block)
-    # render Latax
-    MathJax.Hub.Queue(['Typeset', MathJax.Hub, jq_html_div.get(0)])
+    # render Latex
+    MathJax.Hub.Queue(['Typeset', MathJax.Hub, jq_tmp_div.get(0)])
     # change img src to real data url
-    jq_html_div.find('img[src]').each (index) ->
+    must_finish_promise_list = []
+    jq_tmp_div.find('img[src]').each (index) ->
       $img = $(this)
       uuid = $img.attr('src')
-      imageManager.find_image_by_uuid(uuid).then(
+      p = imageManager.find_image_by_uuid(uuid).then(
         (image) =>
           if image?
             console.log('change img src from ' + uuid + ' to its base64 content')
@@ -193,6 +204,8 @@
         (error) =>
           alert('vm.html_post_process() failed due to failure in imageManager.find_image_by_uuid(' + uuid + ')')
       )
+      must_finish_promise_list.push(p)
+    return Promise.all(must_finish_promise_list).then () -> return jq_tmp_div

   # ------------------------------------------------------------------------------------------------------------------
   # Operations for notes
@@ -492,9 +505,6 @@
     # remove all script tags
     jq_html_div.find('script').remove()

-    # set src of img to full data url
-    jq_html_div.find('img[src]').attr 'src', (i, src) ->
-
     # add inline style
     # refer: https://github.com/Karl33to/jquery.inlineStyler
     # TODO still too much redundant styles


adds permission helper

adds permission helper

--- models/block.coffee
+++ models/block.coffee
@@ -42,7 +42,7 @@
       @get('visibility')

   getPermissions: (user, channel)->
-    return "" unless @has('user') && channel? and user?
+    return "" unless @has('user') and user?

     permissions = ['can-read']

@@ -51,13 +51,16 @@
       permissions.push 'can-edit'

     # Block owner or connector can manage if block is in channel
-    if (@connectedByCurrentUser(user) or @belongsToCurrentUser(user))
+    if (@connectedByCurrentUser(user) or @belongsToCurrentUser(user)) && channel?
       permissions.push 'can-manage'

     (_.uniq permissions).join ' '

   belongsToCurrentUser: (user)->
     @get('user').id is user.id
+
+  allows: (permission, user) ->
+    _.include @getPermissions(user), permission

   connectedByCurrentUser: (user)->
     @get('connected_by_user_id') is user.id


better link anchor points

better link anchor points

--- app/assets/javascripts/d3/topology.coffee
+++ app/assets/javascripts/d3/topology.coffee
@@ -16,17 +16,23 @@
     @right = right

   path_points: =>
+    left_x  = @left.x + 70
+    right_x = @right.x
+    left_y  = @left.y + 25
+    right_y = @right.y + 25
+    distance = right_x - left_x
+
     [
-      {x: @left.x + 70,  y: @left.y + 25},
-      {x: @left.x + 270,  y: @left.y + 25},
-      {x: @right.x - 200, y: @right.y + 25}
-      {x: @right.x, y: @right.y + 25}
+      {x: left_x,  y: left_y},
+      {x: left_x + distance / 4,  y: left_y},
+      {x: right_x - distance / 4, y: right_y}
+      {x: right_x, y: right_y}
     ]

 class Topology
   constructor: ->
-    @width = 800
-    @height = 500
+    @width = 1000
+    @height = 600
     d3.json 'http://etengine.dev/api/v3/converters/topology', @render

   render: (data) =>


CoffeeScript-in-CoffeeScript can compile object[indexes]

--- nodes.coffee
+++ nodes.coffee
@@ -460,40 +460,53 @@
 }

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+# An indexed accessor into a part of an array or object.
+IndexNode: exports.IndexNode: inherit Node, {
+
+  constructor: (index) ->
+    @children: [@index: index]
+    this
+
+  compile_node: (o) ->
+    '[' + @index.compile(o) + ']'
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


Fixes #1771: Fixing the indexOf shim.

Fixes #1771: Fixing the indexOf shim.

--- nodes.coffee
+++ nodes.coffee
@@ -1841,7 +1841,7 @@

   # Discover if an item is in an array.
   indexOf: -> """
-    Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (#{utility 'hasProp'}.call(this, i) && this[i] === item) return i; } return -1; }
+    Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }
   """

   # Shortcuts to speed up the lookup time for native functions.


One character fix, for the sake of consistency.

--- nodes.coffee
+++ nodes.coffee
@@ -1674,7 +1674,7 @@
   # Discover if an item is in an array.
   inArray: '''
     (function() {
-      var indexOf = Array.prototype.indexOf || function (item) {
+      var indexOf = Array.prototype.indexOf || function(item) {
         var i = this.length; while (i--) if (this[i] === item) return i;
         return -1;
       };


#1534 class then "use strict": herecomments fix

--- nodes.coffee
+++ nodes.coffee
@@ -917,10 +917,11 @@
         child.expressions = exps = flatten exps

   checkStrict: ->
-    if (node = @body.expressions[0]) instanceof Value
-      if /^['"]use strict['"]$/.test node.unwrapAll().value
-        @strict = yes
-        @body.expressions.shift()
+    for node,i in @body.expressions when node not instanceof Comment
+      return unless node instanceof Value
+      return unless /^['"]use strict['"]$/.test node.unwrapAll().value
+      @body.expressions.splice i,1
+      return @strict = yes

   # Make sure that a constructor is defined for the class, and properly
   # configured.


minor cson2json command line update

minor cson2json command line update

--- package.cson
+++ package.cson
@@ -148,7 +148,7 @@
 #=====================
     cson2json: '

-        npm run cson2json package.cson > package.json
+        node ./node_modules/cson/bin/cson2json package.cson > package.json
         &&
         node readium-build-tools/optimizePackageJsonScripts.js
     '


config: Improve description of serverName

--- config.coffee
+++ config.coffee
@@ -6,7 +6,8 @@
   # Server listen port
   serverPort: 80

-  # Server name to be embedded in response headers
+  # Server name which will be embedded in
+  # RTSP and HTTP response headers
   serverName: 'node-rtsp-rtmp-server/0.2.0'

   # Average frame rate of video


Allow arbitrary data on components.

Allow arbitrary data on components.

--- source/store.coffee
+++ source/store.coffee
@@ -53,8 +53,9 @@
     newComponent = {}

     # Copy 'static' properties
-    newComponent.css = component.css.toString() if component.css
-    newComponent.components = component.components if component.components
+    for key in Object.keys(component)
+      continue if key is 'properties' or key is 'events'
+      newComponent[key] = if key is 'css' then component[key].toString() else component[key]

     # Serialize properties
     if component.properties


[module] cover case when input is string starting with `={{` in Nunjucks render

--- modules/nunjucks-render.coffee
+++ modules/nunjucks-render.coffee
@@ -23,7 +23,7 @@
   input = if isObject then JSON.stringify(input) else input
   # Remove escaping of wrapping string litrals quotes inside Nunjucks templates, otherwise they won't be recognized by Nunjucks
   # @example ={{ fn("Text \" quote\") }} -> {{ fn(\"Text \\\" quote\") }} -> {{ fn("Text \\\" quote") }} -> "Text \" quote"
-  input = input.replace(/(?={{)*([^\\])(\\")(?=.*}})/g, '$1"').replace(/"\={{/g, '"{{')
+  input = input.replace(/(?={{)*([^\\])(\\")(?=.*}})/g, '$1"').replace(/(^|["])\={{/g, '$1{{')

   result = env.renderString(input, context)


Fix Skip

Fix Skip

--- modules/player/commands.coffee
+++ modules/player/commands.coffee
@@ -42,7 +42,7 @@
         queue.nextItem()
       # Vote skip if enabled
       else
-        return msg.reply "You are not allowed to skip songs." if not data.data.voteSkip
+        return msg.reply "You are not allowed to skip songs." if not d.data.voteSkip
         return msg.reply 'You must be in a voice channel.' if not msg.member.getVoiceChannel()
         return msg.reply 'You must be in the same voice channel the bot is in.' if queue.nowPlaying.voiceChannel.id isnt msg.member.getVoiceChannel().id
         queue.nowPlaying.voteSkip = [] if not queue.nowPlaying.voteSkip


Stop logging

Stop logging

--- components/PortalToMessage.coffee
+++ components/PortalToMessage.coffee
@@ -20,7 +20,7 @@

     send = ->
       topic = "ingress/status/#{data.guid}"
-      console.log "Sending #{data.title} to #{topic}"
+      #console.log "Sending #{data.title} to #{topic}"
       out.topic.send topic
       out.message.send JSON.stringify data
       c.previousData[data.guid] = data


Lower rocketchat-colors priority so it doesn't run before highlighter. Fixes #778

--- packages/rocketchat-colors/client.coffee
+++ packages/rocketchat-colors/client.coffee
@@ -14,4 +14,4 @@
 			message.html = msg
 		return message

-RocketChat.callbacks.add 'renderMessage', ColorsClient, RocketChat.callbacks.priority.HIGH+RocketChat.callbacks.add 'renderMessage', ColorsClient, RocketChat.callbacks.priority.MEDIUM


Removed progress class for now

Removed progress class for now

--- source/progress/progress-provider.coffee
+++ source/progress/progress-provider.coffee
@@ -1,15 +0,0 @@
-class ProgressProvider
-
-  BOUNDS =
-    lower: 0.0
-    upper: 1.0
-
-  constructor: ->
-    @progress = 0
-
-  get: ->
-    throw new Error 'Progress must be between 0.0 and 1.0' unless @inBounds()
-    @progress
-
-  inBounds: ->
-    BOUNDS.lower <= @progress <= BOUNDS.upper


JMachine::reviveUsers: an helper to get list of users as JAccount on the machine

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -3,7 +3,7 @@

 module.exports = class JMachine extends Module

-  { ObjectId, signature } = require 'bongo'
+  { ObjectId, signature, daisy } = require 'bongo'

   @trait __dirname, '../../traits/protected'
   {permit} = require '../group/permissionset'
@@ -23,9 +23,13 @@
       static            :
         one             :
           (signature String, Function)
+      instance          :
+        reviveUsers     :
+          (signature Function)

     permissions         :
       'list machines'   : ['member']
+      'populate users'  : ['member']

     schema              :

@@ -74,3 +78,27 @@

       JMachine.one selector, (err, machine)->
         callback err, machine
+
+  reviveUsers: permit 'populate users',
+
+  success: (client, callback)->
+
+    JUser = require '../user'
+
+    accounts = []
+    queue    = []
+
+    (@users ? []).forEach (_user)->
+      queue.push -> JUser.one _id: _user.id, (err, user)->
+        if not err? and user
+          user.fetchOwnAccount (err, account)->
+            if not err? and account?
+              accounts.push account
+            queue.next()
+        else
+          queue.next()
+
+    queue.push =>
+      callback null, accounts
+
+    daisy queue


SocialWorker: return error idiomatically

--- workers/social/lib/social/models/computeproviders/managed.coffee
+++ workers/social/lib/social/models/computeproviders/managed.coffee
@@ -9,21 +9,18 @@
 KONFIG            = require('koding-config-manager').load("main.#{argv.c}")

-isValid = ({ ipAddress, queryString, storage }, callback) ->
+isValid = ({ ipAddress, queryString, storage }) ->

   if ipAddress? and (ipAddress.split '.').length isnt 4
-    callback new KodingError 'Provided IP is not valid', 'WrongParameter'
-    return no
+    return new KodingError 'Provided IP is not valid', 'WrongParameter'

   if queryString? and (queryString.split '/').length isnt 8
-    callback new KodingError 'Provided queryString is not valid', 'WrongParameter'
-    return no
+    return new KodingError 'Provided queryString is not valid', 'WrongParameter'

   if storage? and isNaN +storage
-    callback new KodingError 'Provided storage is not valid', 'WrongParameter'
-    return no
+    return new KodingError 'Provided storage is not valid', 'WrongParameter'

-  return yes
+  return null

 getKiteIdOnly = (queryString) ->
   "///////#{queryString.split('/').reverse()[0]}"
@@ -43,7 +40,8 @@
     { label, queryString, ipAddress } = options
     { r: { group, user, account } } = client

-    return  unless isValid { queryString, ipAddress }, callback
+    if err = isValid { queryString, ipAddress }
+      return callback err

     queryString = getKiteIdOnly queryString
     provider    = @providerSlug
@@ -125,7 +123,8 @@
       return callback new KodingError \
         'A valid machineId and an update option is required.', 'WrongParameter'

-    return  unless isValid { ipAddress, queryString, storage }, callback
+    if err = isValid { ipAddress, queryString, storage }
+      return callback err

     fieldsToUpdate = {}


don't center header title on android

don't center header title on android

--- app/js/config/ionic_config.coffee
+++ app/js/config/ionic_config.coffee
@@ -6,7 +6,7 @@
   # $ionicConfigProvider.backButton.icon('ion-ios7-arrow-back')
   # $ionicConfigProvider.backButton.text($translateProvider.instant("GO_BACK"))
   # $ionicConfigProvider.backButton.previousTitleText(false)
-  $ionicConfigProvider.navBar.alignTitle('center')
+  # $ionicConfigProvider.navBar.alignTitle('center')
   # $ionicConfigProvider.navBar.positionPrimaryButtons('left')
   # $ionicConfigProvider.navBar.positionSecondaryButtons('right')


autocomplete only fills in mine or favorite accounts

--- app/js/controllers/account.coffee
+++ app/js/controllers/account.coffee
@@ -186,5 +186,9 @@

     $scope.accountSuggestions = (input) ->
         deferred = $q.defer()
-        deferred.resolve(Object.keys(Wallet.accounts))
+        ret = Object.keys(Wallet.accounts)
+        angular.forEach ret, (name) ->
+            if Wallet.accounts[name].is_favorite || Wallet.accounts[name].is_my_account
+                ret.push name
+        deferred.resolve(ret)
         return deferred.promise


run grunt with the built in gruntfile, but in the project's working directory (so config files get found)

--- lib/cli/main.coffee
+++ lib/cli/main.coffee
@@ -60,6 +60,7 @@
     command("grunt").
     description("Run a grunt command with lineman's version of grunt").
     action ->
+      cli.options.base = process.cwd()
       cli.tasks = grunt.util._(arguments).chain().toArray().initial().without("grunt").value()
       grunt.cli(gruntfile: (__dirname + "/../../Gruntfile.coffee"))


correct some typos, and also cause literal strings to be allocated once at function entry instead of at every use - this speeds up test/alloc1 immensely.

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -433,9 +433,9 @@
                 for casenum in [0...case_checks.length-1]
                         test = @visit case_checks[casenum].test
                         discTest = @createCall @ejs["binop==="], [discr, test], "test"
-                        discTest.setReadOnlyMemory()
+                        discTest.setOnlyReadsMemory()
                         disc_truthy = @createCall @ejs.truthy, [discTest], "disc_truthy"
-                        disc_truthy.setReadOnlyMemory()
+                        disc_truthy.setOnlyReadsMemory()
                         disc_cmp = irbuilder.createICmpEq disc_truthy, (llvm.Constant.getIntegerValue boolType, 0), "disccmpresult"
                         irbuilder.createCondBr disc_cmp, case_checks[casenum+1].dest_check, case_checks[casenum].body
                         irbuilder.setInsertPoint case_checks[casenum+1].dest_check
@@ -808,6 +808,7 @@
                 ir_func.topScope = new_scope
                 ir_func.entry_bb = entry_bb

+                ir_func.stringLiteralAllocas = {}

                 allocas = []

@@ -1150,15 +1151,28 @@
                         return @loadNullEjsValue() # this isn't properly typed...  dunno what to do about this here
                 else if typeof n.raw is "string" and (n.raw[0] is '"' or n.raw[0] is "'")
                         debug.log "literal string: #{n.value}"
-                        c = irbuilder.createGlobalStringPtr n.value, "strconst"
-                        strcall = @createCall @ejs.string_new_utf8, [c], "strtmp"
-                        debug.log "strcall = #{strcall}"
-                        return strcall
+                        if @currentFunction.stringLiteralAllocas[n.value]?
+                                str_alloca = @currentFunction.stringLiteralAllocas[n.value]
+                        else
+                                # only create 1 instance of string literals used in a function, and allocate them in the entry block
+                                insertBlock = irbuilder.getInsertBlock()
+
+                                irbuilder.setInsertPoint @currentFunction.entry_bb
+                                str_alloca = irbuilder.createAlloca EjsValueType, "str-alloca-#{n.value}"
+                                c = irbuilder.createGlobalStringPtr n.value, "strconst"
+                                irbuilder.createStore (@createCall @ejs.string_new_utf8, [c], "strtmp"), str_alloca
+                                @currentFunction.stringLiteralAllocas[n.value] = str_alloca
+
+                                irbuilder.setInsertPoint insertBlock
+
+                        strload = irbuilder.createLoad str_alloca, "%prop_alloca"
+                        debug.log "strload = #{strload}"
+                        return strload
                 else if typeof n.raw is "string" and n.raw[0] is '/'
                         debug.log "literal regexp: #{n.raw}"
                         c = irbuilder.createGlobalStringPtr n.raw, "strconst"
                         regexpcall = @createCall @ejs.regexp_new_utf8, [c], "regexptmp"
-                        debug.log "regexpcall = #{strcall}"
+                        debug.log "regexpcall = #{regexpcall}"
                         return regexpcall
                 else if typeof n.value is "number"
                         debug.log "literal number: #{n.value}"


rewrite external css resource paths

rewrite external css resource paths

--- monocat.coffee
+++ monocat.coffee
@@ -51,7 +51,13 @@
             process.exit 1

           min   = new CleanCss().minify data.toString()
+          urlRx = /url\((.*?)\)/ig
+          while url = urlRx.exec min
+            continue if /^['"]?data/i.test url[1]
+            rel = path.relative outDir, path.join path.dirname(srcPath), url[1]
+            min = min.replace url[1], rel

+          $el.after("<style>#{ min }</style>").remove()
           deliver() if ++completed is total

       else


Req -> resp for consistency.

Req -> resp for consistency.

--- picoCTF-web/web/coffee/front-page.coffee
+++ picoCTF-web/web/coffee/front-page.coffee
@@ -168,24 +168,24 @@
       apiNotify({status: 1, message: "Your account has been successfully verified. Please login."})
     if @state.gid
       apiCall "GET", "/api/group/settings", {gid: @state.gid}
-      .done ((req) ->
+      .done ((resp) ->
         @setState update @state,
-          groupName: $set: req.data.name
-          affiliation: $set: req.data.name
-          settings: $merge: req.data.settings
+          groupName: $set: resp.data.name
+          affiliation: $set: resp.data.name
+          settings: $merge: resp.data.settings
           page: $set: "Register"
       ).bind this
     else
       apiCall "GET", "/api/team/settings"
-      .done ((req) ->
+      .done ((resp) ->
         @setState update @state,
-          settings: $merge: req.data
+          settings: $merge: resp.data
       ).bind this

     apiCall "GET", "/api/user/status"
-    .done ((req) ->
+    .done ((resp) ->
       @setState update @state,
-        settings: $merge: req.data
+        settings: $merge: resp.data
      ).bind this

   onRegistration: (e) ->


Changed container formatting for management area.

--- picoCTF-web/web/coffee/management.coffee
+++ picoCTF-web/web/coffee/management.coffee
@@ -9,10 +9,8 @@

   componentDidMount: ->
     # Formatting hack
-    $("#main-content").prepend """
-

-    """
-    $("#main-content>.container").addClass("col-md-10")
+    $("#main-content>.container").addClass("container-fluid")
+    $("#main-content>.container").removeClass("container")

     apiCall "GET", "/api/admin/problems"
     .done ((api) ->


Some code refactoring

Some code refactoring

--- app/scripts/helpers/routes.coffee
+++ app/scripts/helpers/routes.coffee
@@ -2,20 +2,20 @@
 AppConfig = require('scripts/config')

 class RoutesHelper
-  @isInited: false
+  @alreadyInitialized: false

   @init: ->
-    return if @isInited
+    return if @alreadyInitialized

     for moduleName, module of App.submodules when module.router?
       for pattern, routeName of module.router.appRoutes
         addRoute(moduleName, routeName, pattern)

-    @isInited = true
+    @alreadyInitialized = true

   @rootPath: -> AppConfig.rootPath

-  checkRoot = (path) =>
+  prependRoot = (path) =>
     rootPath = @rootPath()
     if path.indexOf(rootPath) then "#{rootPath}#{path}" else path

@@ -24,13 +24,13 @@
     methodName = "#{moduleName.toLowerCase()}#{routeName.charAt(0).toUpperCase()}#{routeName.substr(1).toLowerCase()}Path"

     @[methodName] = (params...) ->
-      return checkRoot(pattern) unless keys
+      return prependRoot(pattern) unless keys

       if keys.length isnt params.length
         throw new Error("incorrect params count (#{params.length} for #{keys.length})")

       pattern = pattern.replace(/\:\w+/, param) for param in params

-      checkRoot(pattern)
+      prependRoot(pattern)

 module.exports = RoutesHelper


fix cb

fix cb

--- lib/eslogger.coffee
+++ lib/eslogger.coffee
@@ -44,10 +44,11 @@
         @robot.http(@logESUrl)
           .path(index)
           .post(json) (err, res, body) =>
+            console.log res.statusCode
             if res.statusCode is 404
               json_body = JSON.parse(body)
               if json_body.error.type is 'index_not_found_exception'
-                @createIndex index, =>
+                @createIndex index, () =>
                   @logMessageES log, room, msg
             else
               if res.statusCode > 299
@@ -62,7 +63,7 @@
           @robot.logger.warning res.statusCode
           @robot.logger.warning body
         else
-          cb ()
+          cb()

   getLogs: (room, start, stop, cb) ->
     # would be good to replace this with a filter, we don't need relevance


Keep the installed source.diff grammar

Keep the installed source.diff grammar

this PR is a fix for https://github.com/akonwi/git-plus/issues/646

disable `syntaxHighlighting` in settings and restart atom.

after atom is restarted, open the developer tools and run the following
code inside the console.

```javascript
var XXX_get = function() {
  return atom.grammars.grammarForScopeName('source.diff')
};
var XXX_say = function() {
  var g = XXX_get();
  console.log('name:%s, package:%s, path:%s',
    g.name, g.packageName, g.path);
};
XXX_say()
```

the expected output is as follows:

```
name:Diff, package:language-diff,
  path:~/.atom/packages/language-diff/grammars/diff.cson
```

now open a new empty file and run `XXX_say()` in the console. the output
should be the same as in first run. next open the grammar selector and
type `diff` but do not yet change the grammar! there should be two
entries in the selector. `Diff` and `Line Diff`. `Diff` is from
`language-diff` and `Line Diff` is from `git-plus`. change into the
console and run `XXX_say()` again. as before, the output is correct. now
change the grammar and check the console. output should as expected. the
grammar is now `Diff`, the file is still empty and unsaved. save the
empty file somewhere and watch the grammar indicator inside the status
bar. immediately after save the grammar automatically changes to
`Line Diff` and i got this as output in the console

```
name:Line Diff, package:git-plus,
  path:~/.atom/packages/git-plus/lib/grammars/line-diff.json
```

run `XXX_get()` to dump the entire `Grammar` object.

the grammar selector now has two `Line Diff` entries.

maybe the problem is the `onPathsChanged()` callback function. after
saving the file, atom opens the `tree view` with the directory of the
file as root. `onPathsChanged()` calls `@deactivate()` and
`@activate()`. `@activate()` calls `setDiffGrammar()` which removes all
grammars for `source.diff` and enables his own `Line Diff` grammar if
`syntaxHighlighting` is disabled.

this patch moves the code that removes the grammars some lines down into
the if condition where the new grammar is added. the else condition to
reload the grammar is not longer needed. because nothing is removed if
`syntaxHighlighting` is not enabled.

works for me (atom is packaged from copr
[mosquito/atom](https://copr.fedorainfracloud.org/coprs/mosquito/atom/))

`apm list -b | grep -e language-diff -e git-plus`

> git-plus@7.3.3
> language-diff@0.7.0

`atom --version`

> Atom    : 1.15.0
> Electron: 1.3.13
> Chrome  : 52.0.2743.82
> Node    : 6.5.0

`lsb_release -s -d`

> "Fedora release 25 (Twenty Five)"

--- lib/git-plus.coffee
+++ lib/git-plus.coffee
@@ -61,9 +61,6 @@
   repo.relativize(atom.workspace.getActiveTextEditor()?.getPath())

 setDiffGrammar = ->
-  while atom.grammars.grammarForScopeName 'source.diff'
-    atom.grammars.removeGrammarForScopeName 'source.diff'
-
   enableSyntaxHighlighting = atom.config.get('git-plus.diffs.syntaxHighlighting')
   wordDiff = atom.config.get('git-plus.diffs.wordDiff')
   diffGrammar = null
@@ -77,11 +74,9 @@
     baseGrammar = baseLineGrammar

   if enableSyntaxHighlighting
+    while atom.grammars.grammarForScopeName 'source.diff'
+      atom.grammars.removeGrammarForScopeName 'source.diff'
     atom.grammars.addGrammar diffGrammar
-  else
-    grammar = atom.grammars.readGrammarSync baseGrammar
-    grammar.packageName = 'git-plus'
-    atom.grammars.addGrammar grammar

 getWorkspaceRepos = -> atom.project.getRepositories().filter (r) -> r?


Dispatch collide event.

Dispatch collide event.

--- lib/observer.coffee
+++ lib/observer.coffee
@@ -39,7 +39,7 @@
             point : Vector.fromString(element.getAttribute("point"))
           }
         else if el && (element.getAttribute('name') is "collide")
-          el.dispatchEvent 'click', {
+          el.dispatchEvent 'collide', {
             player : @player
             normal : Vector.fromString(element.getAttribute("normal"))
           }


improve

improve

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -4,7 +4,6 @@
 globalState = require './global-state'

 {inspect} = require 'util'
-p = (args...) -> console.log inspect(args...)
 {
   haveSomeSelection
   highlightRanges
@@ -85,7 +84,7 @@
     @initialize()
     @setTarget(@new(@target)) if _.isString(@target)

-  # @target - TextObject or Motion to operate on.
+  # target is TextObject or Motion to operate on.
   setTarget: (target) ->
     unless _.isFunction(target.select)
       @emitDidFailToSetTarget()
@@ -147,7 +146,7 @@
     # We need to preserve selections before selection is cleared as a result of mutation.
     @updatePreviousSelectionIfVisualMode()
     # Mutation phase
-    console.log "== Execution start #{@getName()}:#{@getTarget()?.getName()}"
+    # console.log "== Execution start #{@getName()}:#{@getTarget()?.getName()}"
     if @selectTarget()
       @editor.transact =>
         for selection in @editor.getSelections()
@@ -160,39 +159,46 @@
     # we have to return to normal-mode from operator-pending or visual
     @activateMode('normal')

+  capturePatternForOccurrence: ->
+    @scanRangesForOccurrence = null
+
+    if @isMode('visual')
+      scanRanges = @editor.getSelectedBufferRanges()
+      @vimState.modeManager.deactivate() # clear selection FIXME
+      console.log 'deactivate on will-select-target'
+
+      unless @isMode('visual', 'blockwise') # extend scanRange to include cursorWord
+        # BUG dont extend if register value is specified
+        range = getCurrentWordBufferRangeAndKind(@editor.getLastCursor()).range
+        newRange = scanRanges.pop().union(range)
+        scanRanges.push(newRange)
+      @scanRangesForOccurrence = scanRanges
+    @patternForOccurence ?= @getPatternForOccurrence()
+
+  selectOccurrence: ->
+    @scanRangesForOccurrence ?= @editor.getSelectedBufferRanges()
+    ranges = scanInRanges(@editor, @patternForOccurence, @scanRangesForOccurrence)
+    if ranges.length
+      @editor.setSelectedBufferRanges(ranges)
+    else
+      # Restoring cursor position also clear selection
+      # Unless clearing selection, we mutate original selection(e.g. paragraph) rather than occurrence.
+      console.log "Fail to select occurrence"
+      @restoreCursorPositions()
+      return false
+
   # Return true unless all selection is empty.
   selectTarget: ->
     @saveCursorPositionsToRestore()
     @emitWillSelectTarget()
     if @isWithOccurrence()
-      scanRanges = null
-      if @isMode('visual')
-        scanRanges = @editor.getSelectedBufferRanges()
-        @vimState.modeManager.deactivate() # clear selection FIXME
-        console.log 'deactivate on will-select-target'
-
-        unless @isMode('visual', 'blockwise') # extend scanRange to include cursorWord
-          # BUG dont extend if register value is specified
-          range = getCurrentWordBufferRangeAndKind(@editor.getLastCursor()).range
-          scanRanges.push(scanRanges.pop().union(range))
-
-      @patternForOccurence ?= @getPatternForOccurrence()
-
-    @target.select()
-    # @debug()
-
-    if @isWithOccurrence()
-      scanRanges ?= @editor.getSelectedBufferRanges()
-      ranges = scanInRanges(@editor, @patternForOccurence, scanRanges)
-      if ranges.length
-        @editor.setSelectedBufferRanges(ranges)
-      else
-        # Restoring cursor position also clear selection
-        # Unless clearing selection, we mutate original selection(e.g. paragraph) rather than occurrence.
-        console.log "Fail to select occurrence"
-        @restoreCursorPositions()
-        return false
-
+      @capturePatternForOccurrence()
+      @target.select()
+      @selectOccurrence()
+    else
+      @target.select()
+
+    @selectOccurrence() if @isWithOccurrence()
     @emitDidSelectTarget()
     @flashIfNecessary(@editor.getSelectedBufferRanges())
     @trackChangeIfNecessary()
@@ -216,15 +222,15 @@
     wasVisual = @isMode('visual')

     if @needStay() and wasVisual
-      console.log 'case-1'
+      # console.log 'case-1'
       @cursorPositionManager.save('head', fromProperty: true, allowFallback: true) # visual-stay

     else if @needStay() and not wasVisual
-      console.log 'case-2'
+      # console.log 'case-2'
       @cursorPositionManager.save('head') unless @instanceof('Select') # stay

     else
-      console.log 'case-3'
+      # console.log 'case-3'
       @preemptDidSelectTarget =>
         @cursorPositionManager.save('start')

@@ -282,6 +288,7 @@
   @description: "Add selection onto each matching word within target range"
   withOccurrence: true
   initialize: ->
+    console.log 'mode!', @vimState.mode
     # FIXME don't trying to do everytin in event
     @onDidSelectTarget =>
       swrap.clearProperties(@editor)
@@ -357,7 +364,6 @@
   mutateSelection: (selection) =>
     @setTextToRegisterForSelection(selection)
     selection.deleteSelectedText()
-

 class DeleteRight extends Delete
   @extend()


cleanup

cleanup

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -229,13 +229,14 @@
     if @isOccurrence()
       @selectOccurrence()

-    isExplicitEmptyTarget = @target.getName() is "Empty"
-    if haveSomeNonEmptySelection(@editor) or isExplicitEmptyTarget
+    if haveSomeNonEmptySelection(@editor) or @target.getName() is "Empty"
       @mutationManager.setCheckPoint('did-select')
       @emitDidSelectTarget()
       @flashChangeIfNecessary()
       @trackChangeIfNecessary()
-    haveSomeNonEmptySelection(@editor) or isExplicitEmptyTarget
+      true
+    else
+      false

   restoreCursorPositionsIfNecessary: ->
     return unless @restorePositions
@@ -544,7 +545,7 @@
   location: 'before'

   initialize: ->
-    @target = "Empty" if @isMode('normal')
+    @target = 'Empty' if @isMode('normal')

   mutateSelection: (selection) ->
     {text, type} = @vimState.register.get(null, selection)


Timezone fixes

Timezone fixes

* Remove excess console.log
* Check for valid timezone and use default otherwise

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -20,9 +20,8 @@
   @momentInUserTimezone = (date, user = Meteor.user()) ->
     date = moment date unless date instanceof moment
     zone = user?.profile?.timezone
-    console.log user, zone
     zone = timezoneCanon zone if zone?
     ## Default timezone is the server's timezone
-    zone = moment.tz.guess() unless zone
+    zone = moment.tz.guess() unless zone and moment.tz.zone(zone)?
     date = date.tz zone if zone
     date


Draggable: Fixed an small bug where the target was sometimes null in Firefox. See #48946

--- src/base/DragDropSelect/Draggable.coffee
+++ src/base/DragDropSelect/Draggable.coffee
@@ -263,6 +263,8 @@
 					pointTarget = ev.getTarget()

 				$target = pointTarget
+				if not $target
+					return

 				if CUI.globalDrag.ended
 					return


Remove stateFields from google-file-store

--- src/code/stores/google-file-store.coffee
+++ src/code/stores/google-file-store.coffee
@@ -11,12 +11,6 @@
   "revertToOriginal", "revertToLastSave", "connectToApi"
   "addAfterAuthHandler"
 ]
-
-stateFields = [
-  'gapiLoaded', 'fileId', 'action', 'isPublic',
-  'docLink', 'showingSaveDialog'
-]
-

 GoogleFileStore = Reflux.createStore
   listenables: [GoogleFileActions]


[backport] Issue 3744 New bulk insert of US assigns a 0 value to Points, but default should be '?' (or whatever is predefined), not '0'

--- app/coffee/modules/common/estimation.coffee
+++ app/coffee/modules/common/estimation.coffee
@@ -161,7 +161,7 @@
             values = _.map(@us.points, (v, k) => @pointsById[v]?.value)

             if values.length == 0
-                return "0"
+                return "?"

             notNullValues = _.filter(values, (v) -> v?)
             if notNullValues.length == 0


if no buckets, commentsLoaded and contributionsLoaded set to true

--- app/components/group-page/group-page.coffee
+++ app/components/group-page/group-page.coffee
@@ -13,11 +13,14 @@
         $scope.group = group
         $scope.currentMembership = group.membershipFor(CurrentUser())
         Records.buckets.fetchByGroupId(group.id).then (data) ->
-          _.each data.buckets, (bucket) ->
-            Records.contributions.fetchByBucketId(bucket.id).then ->
-              $scope.contributionsLoaded = true
-            Records.comments.fetchByBucketId(bucket.id).then ->
-              $scope.commentsLoaded = true
+          if data.buckets.length > 0
+            _.each data.buckets, (bucket) ->
+              Records.contributions.fetchByBucketId(bucket.id).then ->
+                $scope.contributionsLoaded = true
+              Records.comments.fetchByBucketId(bucket.id).then ->
+                $scope.commentsLoaded = true
+          else
+            $scope.contributionsLoaded = $scope.commentLoaded = true
         Records.memberships.fetchByGroupId(group.id).then ->
           $scope.membershipsLoaded = true


:bug: Remove decorations on hide

:bug: Remove decorations on hide

--- lib/views/panel.coffee
+++ lib/views/panel.coffee
@@ -10,6 +10,7 @@
       try decoration.destroy()
     @decorations = []
   hide: ->
+    @removeDecorations()
     @innerHTML = ''
     @linter.views.panelWorkspace.hide() if @linter.views.panelWorkspace.isVisible()
   render: (messages) ->


Changed k-turn to look more like it does on the dial.


labelWidth option added and uses the defaultKey event to flush the value, also reduced refreshAfter to 0.0 seconds

--- js/controls/textcontrol/textcontrol.coffee
+++ js/controls/textcontrol/textcontrol.coffee
@@ -25,7 +25,8 @@
       textIndent: 0
       fontSize: '10px'
       color: '#666'
-    refreshAfter:   0.2 # 200ms
+    labelWidth: 'auto'
+    refreshAfter:   0.0 # amount of milliseconds to wait for a refresh from the input field
     refreshOnBlur:  true
     refreshOnInput: true
     refreshOnIdle:  true
@@ -56,7 +57,10 @@
         label: @label
         style: @options.labelStyle
       )
-    _labelWidth = @_labelView.stringWidth( @label, null, @_labelView.markupElemIds.value )+4
+    if @options.labelWidth == 'auto'
+      _labelWidth = @_labelView.stringWidth( @label, null, @_labelView.markupElemIds.value )+4
+    else
+      _labelWidth = @options.labelWidth
     @_labelView.rect.setWidth( _labelWidth )
     @_labelView.drawRect()
     if @componentName == 'textarea'
@@ -286,10 +290,16 @@
     else if _inputElement.selectionStart
       _inputElement.setSelectionRange( _selectionStart, _selectionEnd )

+  defaultKey: ->
+    @refreshAfter()
+    null
+
   ### = Description
   ## Receives the +textEnter+ event to update the value
   ## based on what's (potentially) entered in the text input field.
   ###
   textEnter: ->
     @refreshAfter() if @options.refreshOnInput
-    return false
+    false
+
+HTextField = HTextControl


Adds casing check for unloaded/non-tasked levels.

--- app/views/editor/level/LevelEditView.coffee
+++ app/views/editor/level/LevelEditView.coffee
@@ -221,4 +221,7 @@
     ++@levelBuildTime

   getTaskCompletionRatio: ->
-    return _.filter(@level.get('tasks'), (_elem) -> return _elem.complete).length + "/" + @level.get('tasks').length
+    if !@level.get('tasks')?
+      return {}
+    else
+      return _.filter(@level.get('tasks'), (_elem) -> return _elem.complete).length + "/" + @level.get('tasks').length


bugfix. sequence.play(0) was being interpreted as play from current position instead of play from start

--- src/prong/sequence.coffee
+++ src/prong/sequence.coffee
@@ -314,7 +314,7 @@
         if time == undefined and loopStart!= null and loopEnd != null and (not timeline.loopDisabled())
             time = loopStart

-        currentTime = time or currentTime
+        currentTime = if time != undefined then time else currentTime
         playStartSequenceTime = currentTime
         playStartComputerTime = new Date()
         playing = true


when installing wakatime cli, always extract the zip file.

--- lib/wakatime.coffee
+++ lib/wakatime.coffee
@@ -194,15 +194,23 @@
     url = 'https://github.com/wakatime/wakatime/archive/master.zip'
     zipFile = __dirname + path.sep + 'wakatime-master.zip'
     downloadFile(url, zipFile, ->
-        console.log 'Extracting wakatime-master.zip file...'
-        if fs.existsSync(__dirname + path.sep + 'wakatime-master')
-            rimraf(__dirname + path.sep + 'wakatime-master', ->
-                unzip(zipFile, __dirname, true)
-                console.log 'Finished installing wakatime cli.'
-                if callback?
-                    callback()
-            )
-    )
+        extractCLI(zipFile, callback)
+    )
+
+extractCLI = (zipFile, callback) ->
+    console.log 'Extracting wakatime-master.zip file...'
+    if fs.existsSync(__dirname + path.sep + 'wakatime-master')
+        rimraf(__dirname + path.sep + 'wakatime-master', ->
+            unzip(zipFile, __dirname, true)
+            console.log 'Finished installing wakatime cli.'
+            if callback?
+                callback()
+        )
+    else
+        unzip(zipFile, __dirname, true)
+        console.log 'Finished installing wakatime cli.'
+        if callback?
+            callback()

 downloadFile = (url, outputFile, callback) ->
     r = request(url)


Fixes #2331 -- bound 'super' regression

Fixes #2331 -- bound 'super' regression

--- nodes.coffee
+++ nodes.coffee
@@ -525,7 +525,8 @@

   # The appropriate `this` value for a `super` call.
   superThis : (o) ->
-    o.scope.method?.context or "this"
+    method = o.scope.method
+    (method and not method.klass and method.context) or "this"

   # Soaked chained invocations unfold into if/else ternary structures.
   unfoldSoak: (o) ->


Fixes #2781, fixes #2782. Reverting to old method of instance method binding.

--- nodes.coffee
+++ nodes.coffee
@@ -983,14 +983,9 @@
   # Ensure that all functions bound to the instance are proxied in the
   # constructor.
   addBoundFunctions: (o) ->
-    if @boundFuncs.length
-      o.scope.assign '_this', 'this'
-      for [name, func] in @boundFuncs
-        lhs = new Value (new Literal "this"), [new Access name]
-        body = new Block [new Return new Literal "#{@ctor.name}.prototype.#{name.value}.apply(_this, arguments)"]
-        rhs = new Code func.params, body, 'boundfunc'
-        bound = new Assign lhs, rhs
-        @ctor.body.push bound
+    for bvar in @boundFuncs
+      lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
+      @ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
     return

   # Merge the properties from a top-level object as prototypal properties
@@ -1020,7 +1015,7 @@
           else
             assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
             if func instanceof Code and func.bound
-              @boundFuncs.push [base, func]
+              @boundFuncs.push base
               func.bound = no
       assign
     compact exprs
@@ -2122,6 +2117,11 @@
     function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }
   """

+  # Create a function bound to the current value of "this".
+  bind: -> '''
+    function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
+  '''
+
   # Discover if an item is in an array.
   indexOf: -> """
     [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }


removed extra parens from soak compilations

--- nodes.coffee
+++ nodes.coffee
@@ -403,9 +403,10 @@
         ref = new Literal o.scope.freeVariable 'ref'
         fst = new Parens new Assign ref, fst
         snd.base = ref
-      ifn = new If new Existence(fst), snd, soak: yes
-      return ifn
+      return new If new Existence(fst), snd, soak: on, operation: @tags.operation
     null
+
+  @wrap: (node) -> if node instanceof Value then node else new Value node

 #### Comment

@@ -463,17 +464,16 @@
   # Soaked chained invocations unfold into if/else ternary structures.
   unfoldSoak: (o) ->
     if @soakNode
-      if val = @variable
-        val = new Value val unless val instanceof Value
-        [left, rite] = val.cacheReference o
+      if @variable
+        return ifn if ifn = If.unfoldSoak o, this, 'variable'
+        [left, rite] = Value.wrap(@variable).cacheReference o
       else
         left = new Literal @superReference o
         rite = new Value left
       rite = new Call rite, @args
       rite.isNew = @isNew
       left = new Literal "typeof #{ left.compile o } === \"function\""
-      ifn  = new If left, new Value(rite), soak: yes
-      return ifn
+      return new If left, new Value(rite), soak: yes, operation: @tags.operation
     call = this
     list = []
     loop
@@ -518,7 +518,7 @@
     splatargs = @compileSplatArguments o
     return "#{ @superReference o }.apply(this, #{splatargs})" if @isSuper
     unless @isNew
-      base = new Value base unless (base = @variable) instanceof Value
+      base = Value.wrap @variable
       if (name = base.properties.pop()) and base.isComplex()
         ref = o.scope.freeVariable 'this'
         fun = "(#{ref} = #{ base.compile o })#{ name.compile o }"
@@ -893,9 +893,8 @@
         idx = if isObject
           if obj.tags.this then obj.properties[0].name else obj
         else new Literal 0
-      value = new Value value unless value instanceof Value
       accessClass = if IDENTIFIER.test idx.value then Accessor else Index
-      value.properties.push new accessClass idx
+      (value = Value.wrap value).properties.push new accessClass idx
       return new Assign(obj, value).compile o
     top     = del o, 'top'
     otop    = merge o, top: yes
@@ -1581,10 +1580,11 @@

   # Compile the If as a conditional operator.
   compileExpression: (o) ->
+    @condition.tags.operation = on
     code = @condition.compile(o)      + ' ? ' +
            @bodyNode().compileBare(o) + ' : ' +
            @elseBodyNode()?.compileBare o
-    if @tags.operation or @soakNode then "(#{code})" else code
+    if @tags.operation then "(#{code})" else code

   unfoldSoak: -> @soakNode and this

@@ -1593,6 +1593,7 @@
     return unless ifn = parent[name].unfoldSoak o
     parent[name] = ifn.body
     ifn.body     = new Value parent
+    ifn.tags.operation = on if parent.tags.operation
     ifn

 # Faux-Nodes


Added provider support

Added provider support

--- packages/http/src/grind.coffee
+++ packages/http/src/grind.coffee
@@ -9,5 +9,22 @@

 	grind.routes = make './router', grind
 	grind.config = make './config', grind
+	grind.booted = false
+	grind.providers = [ ]
+
+	grind.boot = ->
+		return if @booted
+
+		for provider in @providers
+			provider this
+
+		@booted = true
+		return
+
+	listen = grind.listen
+
+	grind.listen = ->
+		@boot()
+		return listen.apply grind, arguments

 	return grind


js to coffee fail

js to coffee fail

--- src/remote/handler.coffee
+++ src/remote/handler.coffee
@@ -4,14 +4,14 @@
     timeout = null

     ->
+      context = this
+      args.push(Array::slice.call(arguments))
+
       delayed = ->
         fn.call(context, args)

         timeout = null
         args = []
-
-      context = this
-      args.push(Array::slice.call(arguments))

       clearTimeout(timeout)
       timeout = setTimeout(delayed, threshold)


Add spaces before and after the URL.

Add spaces before and after the URL.

--- src/scripts/gitlab.coffee
+++ src/scripts/gitlab.coffee
@@ -78,9 +78,9 @@
         branch = hook.ref.split("/")[2..].join("/")
         # if the ref before the commit is 00000, this is a new branch
         if /^0+$/.test(hook.before)
-            message = "#{bold(hook.user_name)} pushed a new branch (#{bold(branch)}) to #{bold(hook.repository.name)} (#{underline(hook.repository.homepage)})"
+            message = "#{bold(hook.user_name)} pushed a new branch (#{bold(branch)}) to #{bold(hook.repository.name)} ( #{underline(hook.repository.homepage)} )"
         else
-            message = "#{bold(hook.user_name)} pushed #{bold(hook.total_commits_count)} commits to #{bold(branch)} in #{bold(hook.repository.name)} (#{underline(hook.repository.homepage + '/compare/' + hook.before.substr(0,9) + '...' + hook.after.substr(0,9))})"
+            message = "#{bold(hook.user_name)} pushed #{bold(hook.total_commits_count)} commits to #{bold(branch)} in #{bold(hook.repository.name)} ( #{underline(hook.repository.homepage + '/compare/' + hook.before.substr(0,9) + '...' + hook.after.substr(0,9))} )"
         robot.send user, message

   robot.router.post "/gitlab/system", (req, res) ->


Cleaning up formatting, making code more concise

--- src/services/table.coffee
+++ src/services/table.coffee
@@ -188,7 +188,7 @@

           # Check if we're working with an existing section, if so we want to
           # intelligently insert / remove only what we need to
-          if @sections[sectionName]? and @sections[sectionName].rows.length
+          if @sections[sectionName]?.rows.length
             tableModels  = []
             toBeRemoved  = []
             toBeInserted = []
@@ -202,15 +202,14 @@

             @remove.apply this, args for args in toBeRemoved

-            for model, index in models
-              if model not in tableModels
+            for model, index in models when model not in tableModels
                 toBeInserted.push [sectionName, model, index]

             @insert.apply this, args for args in toBeInserted

           # New or empty section, load using set which will also create a section
           else
-            @rowsCtrl.set(sectionName, models, sectionController)
+            @rowsCtrl.set sectionName, models, sectionController

         insert: (sectionName, model, index = 0) ->
           @rowsCtrl.insert sectionName, model, index


minor reformat

minor reformat

--- package.cson
+++ package.cson
@@ -265,7 +265,8 @@
     'build:styles': '

         node readium-cfi-js/node_modules/cpy/cli.js
-            static/sdk.css build-output/css/
+            static/sdk.css
+            build-output/css/
     '

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


Fix typo.

Fix typo.

--- atom/browser/api/lib/content-tracing.coffee
+++ atom/browser/api/lib/content-tracing.coffee
@@ -4,4 +4,4 @@
 module.exports.DEFAULT_OPTIONS = 0
 module.exports.ENABLE_SYSTRACE = 1 << 0
 module.exports.ENABLE_SAMPLING = 1 << 1
-module.exports.RECORD_CONTINUOUSLY =  << 2
+module.exports.RECORD_CONTINUOUSLY = 1 << 2


fixes distance-to-station broken by addition of Location class

--- ng-modules/game.coffee
+++ ng-modules/game.coffee
@@ -98,17 +98,12 @@

     # === "private" methods ===
     _getRemainingLocations: ()->
-        # returns obj with aligned arrays of locations & distances not yet reached
-        locNames = []
-        locDists = []
-        for key of @locations
-            if @locations[key] > @distanceTraveled
-                locNames.push(key)
-                locDists.push(@locations[key])
-        return {
-        "names": locNames,
-        "distances": locDists
-        }
+        # returns array of locations not yet reached
+        remainingLocs = []
+        for location in @locations
+            if location.x > @distanceTraveled
+                remainingLocs.push(location)
+        return remainingLocs

     _getStatsToNextLocation: ()->
         # returns distance, location, & name of next location as dict
@@ -124,12 +119,12 @@

         # get minimum of remaining locations
         next = {}
-        next.location = remaining.distances[0]
-        next.name     = remaining.names[0]
-        for i of remaining.distances
-            if remaining.distances[i] < next.distance  # assumes no equal distances
-                next.location = remaining.distances[i]
-                next.name = remaining.names[i]
+        next.location = remaining[0].x
+        next.name     = remaining[0].name
+        for i of remaining
+            if remaining[i].x < next.distance  # assumes no equal distances
+                next.location = remaining[i].x
+                next.name = remaining[i].name

             # calculate distance remaining before arrival
         next.distance = next.location - @distanceTraveled


Fix course progress tab select

Fix course progress tab select

--- app/views/courses/TeacherClassView.coffee
+++ app/views/courses/TeacherClassView.coffee
@@ -41,6 +41,7 @@
     'click .select-all': 'onClickSelectAll'
     'click .student-checkbox': 'onClickStudentCheckbox'
     'keyup #student-search': 'onKeyPressStudentSearch'
+    'change .course-select, .bulk-course-select': 'onChangeCourseSelect'

   getInitialState: ->
     {
@@ -149,6 +150,8 @@
     @listenTo @students, 'sort', ->
       @state.set students: @students
       @render()
+    @listenTo @, 'course-select:change', ({ selectedCourse }) ->
+      @state.set selectedCourse: selectedCourse

   setCourseMembers: =>
     for course in @courses.models
@@ -272,6 +275,10 @@

   onKeyPressStudentSearch: (e) ->
     @state.set('searchTerm', $(e.target).val())
+
+  onChangeCourseSelect: (e) ->
+    console.log '??'
+    @trigger 'course-select:change', { selectedCourse: @courses.get($(e.currentTarget).val()) }

   getSelectedStudentIDs: ->
     @$('.student-row .checkbox-flat input:checked').map (index, checkbox) ->


Rearrange compile flags

Rearrange compile flags

--- services/clsi/Gruntfile.coffee
+++ services/clsi/Gruntfile.coffee
@@ -73,8 +73,8 @@
 	grunt.registerTask 'compile:bin', () ->
 		callback = @async()
 		proc = spawn "cc", [
-			"-o", "bin/synctex", "-lz", "-Isrc/synctex",
-			"src/synctex.c", "src/synctex/synctex_parser.c", "src/synctex/synctex_parser_utils.c"
+			"-o", "bin/synctex", "-Isrc/synctex",
+			"src/synctex.c", "src/synctex/synctex_parser.c", "src/synctex/synctex_parser_utils.c", "-lz"
 		], stdio: "inherit"
 		proc.on "close", callback


Support pathReplace

Support pathReplace


add warning message on Appveyor tests

add warning message on Appveyor tests

--- tasks/tests.coffee
+++ tasks/tests.coffee
@@ -58,6 +58,10 @@

 mochaWindows = (cb) ->
+  # TODO: Fix so Mocha results are shown in Appveyor.
+  if _.contains(process.argv, '--appveyor')
+    console.log('Note you can\'t see Mocha tests result in AppVeyor due to how Windows spawns processes')
+
   options = {stdio: [process.stdin, process.stdout, process.stderr]}
   env = process.env
   env.ELECTRON_PATH = path.resolve('./node_modules/.bin/electron') + '.cmd'


color2 ->

color2 ->

--- test/color2.coffee
+++ test/color2.coffee
@@ -4,10 +4,10 @@
   message ||= "" + expected + " within " + tolerance + " of " + actual
   ok(expected + tolerance >= actual && expected - tolerance <= actual, message)

-module "Color2"
+module "Color"

 test "r, g, b default to 0, a defaults to 1", ->
-  color = Color2()
+  color = Color()

   equalEnough color.r, 0
   equalEnough color.g, 0
@@ -15,14 +15,14 @@
   equalEnough color.a, 1

 test "accepts a single array of length 3", ->
-  color = Color2([255, 1, 2])
+  color = Color([255, 1, 2])

   equalEnough color.r, 255
   equalEnough color.g, 1
   equalEnough color.b, 2

 test "accepts a single array of length 4", ->
-  color = Color2([255, 4, 3, 0.8])
+  color = Color([255, 4, 3, 0.8])

   equalEnough color.r, 255
   equalEnough color.g, 4
@@ -30,7 +30,7 @@
   equalEnough color.a, 0.8

 test "accepts an array of length 3 as the first argument and an alpha value as the second", ->
-  color = Color2([100, 5, 3], 0.4)
+  color = Color([100, 5, 3], 0.4)

   equalEnough color.r, 100
   equalEnough color.g, 5
@@ -38,7 +38,7 @@
   equalEnough color.a, 0.4

 test "accepts an array of length 4 as the first argument and an alpha value. The alpha value passed as the second argument overrides the alpha in the array", ->
-  color = Color2([4, 20, 90, 0.1], 0.6)
+  color = Color([4, 20, 90, 0.1], 0.6)

   equalEnough color.r, 4
   equalEnough color.g, 20
@@ -46,7 +46,7 @@
   equalEnough color.a, 0.6

 test "accepts an rgb string as the first argument and an alpha value as the second", ->
-  color = Color2('rgb(255, 40, 30)', 0.4)
+  color = Color('rgb(255, 40, 30)', 0.4)

   equalEnough color.r, 255
   equalEnough color.g, 40
@@ -54,7 +54,7 @@
   equalEnough color.a, 0.4

 test "accepts an rgba string as the first argument and an alpha value as the second. The alpha value takes precedence over the alpha from the rgba string", ->
-  color = Color2('rgba(30, 20, 15, 0.8)', 0.35)
+  color = Color('rgba(30, 20, 15, 0.8)', 0.35)

   equalEnough color.r, 30
   equalEnough color.g, 20
@@ -62,7 +62,7 @@
   equalEnough color.a, 0.35

 test "accepts an hsl string as the first argument and an alpha value as the second", ->
-  color = Color2('hsl(63, 0.4, 0.3)', 0.21)
+  color = Color('hsl(63, 0.4, 0.3)', 0.21)

   equalEnough color.r, 104
   equalEnough color.g, 107
@@ -70,7 +70,7 @@
   equalEnough color.a, 0.21

 test "accepts an hsla string as the first argument and an alpha value as the second. The alpha value takes precedence over the hsla string alpha value", ->
-  color = Color2('hsla(45, 0.3, 0.5, 0.1)', 0.47)
+  color = Color('hsla(45, 0.3, 0.5, 0.1)', 0.47)

   equalEnough color.r, 166
   equalEnough color.g, 147
@@ -78,7 +78,7 @@
   equalEnough color.a, 0.47

 test "accepts hex value of length 3 as first argument and alpha value as second argument", ->
-  color = Color2('#ff0', 0.5)
+  color = Color('#ff0', 0.5)

   equalEnough color.r, 255
   equalEnough color.g, 255
@@ -86,7 +86,7 @@
   equalEnough color.a, 0.5

 test "accepts hex value of length 4 as first argument and alpha value as second argument. The alpha value takes precedence over the alpha from the hex string.", ->
-  color = Color2('#ef3c', 0.3)
+  color = Color('#ef3c', 0.3)

   equalEnough color.r, 238
   equalEnough color.g, 255
@@ -94,7 +94,7 @@
   equalEnough color.a, 0.3

 test "accepts hex value of length 6 as first argument and alpha value as second argument", ->
-  color = Color2('#de34ab', 0.27)
+  color = Color('#de34ab', 0.27)

   equalEnough color.r, 222
   equalEnough color.g, 52
@@ -102,7 +102,7 @@
   equalEnough color.a, 0.27

 test "accepts hex value of length 8 as first argument and alpha value as second argument. Alpha value takes precedence over hex alpha.", ->
-  color = Color2('#ab45cd', 0.59)
+  color = Color('#ab45cd', 0.59)

   equalEnough color.r, 171
   equalEnough color.g, 69
@@ -110,7 +110,7 @@
   equalEnough color.a, 0.59

 test "accepts hex string of length 3", ->
-  color = Color2('#df2')
+  color = Color('#df2')

   equalEnough color.r, 221
   equalEnough color.g, 255
@@ -118,7 +118,7 @@
   equalEnough color.a, 1.0

 test "accepts hex string of length 4", ->
-  color = Color2('#c987')
+  color = Color('#c987')

   equalEnough color.r, 204
   equalEnough color.g, 153
@@ -126,7 +126,7 @@
   equalEnough color.a.toFixed(2), 0.47

 test "accepts hex string of length 6", ->
-  color = Color2('#cdef12')
+  color = Color('#cdef12')

   equalEnough color.r, 205
   equalEnough color.g, 239
@@ -134,7 +134,7 @@
   equalEnough color.a, 1.0

 test "accepts hex string of length 8", ->
-  color = Color2('#ef1234af')
+  color = Color('#ef1234af')

   equalEnough color.r, 239
   equalEnough color.g, 18
@@ -142,7 +142,7 @@
   equalEnough color.a.toFixed(2), 0.69

 test "accepts 3 numeric values", ->
-  color = Color2(34, 54, 39)
+  color = Color(34, 54, 39)

   equalEnough color.r, 34
   equalEnough color.g, 54
@@ -150,7 +150,7 @@
   equalEnough color.a, 1.0

 test "accepts 4 numeric values", ->
-  color = Color2(23, 43, 100, 0.32)
+  color = Color(23, 43, 100, 0.32)

   equalEnough color.r, 23
   equalEnough color.g, 43
@@ -159,37 +159,37 @@

 test "invalid color throws error", ->
   raises ->
-    Color2("A Fake Color")
+    Color("A Fake Color")

 test "#copy", ->
-  color = Color2(123, 231, 2)
+  color = Color(123, 231, 2)
   copiedColor = color.copy()

   ok color.equal(copiedColor)
   ok color != copiedColor

 test "#equal", ->
-  color1 = Color2(255, 255, 255, 1)
-  color2 = Color2([255, 255, 255])
-
-  ok color1.equal(color2)
+  color1 = Color(255, 255, 255, 1)
+  Color = Color([255, 255, 255])
+
+  ok color1.equal(Color)

 test "#toString", ->
-  noAlpha = Color2(30, 40, 23)
-  withAlpha = Color2(29, 49, 50, 0.45)
-  decimalValues = Color2(34.7, 52.2, 50.1, 0.45)
+  noAlpha = Color(30, 40, 23)
+  withAlpha = Color(29, 49, 50, 0.45)
+  decimalValues = Color(34.7, 52.2, 50.1, 0.45)

   equal noAlpha.toString(), "rgba(30, 40, 23, 1)"
   equal withAlpha.toString(), "rgba(29, 49, 50, 0.45)"
   equal decimalValues.toString(), "rgba(35, 52, 50, 0.45)"

 test "#toHex", ->
-  color = Color2(23, 45, 100)
+  color = Color(23, 45, 100)

   equal color.toHex(), "#172d64"

 test "#toHsl", ->
-  color = Color2(45, 29, 20)
+  color = Color(45, 29, 20)

   hsl = color.toHsl()

@@ -199,17 +199,17 @@
   equalEnough hsl[3], 1.0

 test "#hue", ->
-  color = Color2(34, 54, 239)
-
-  color2 = color.hue(20)
-
-  equalEnough color2.r, 84
-  equalEnough color2.g, 37
-  equalEnough color2.b, 239
-  equalEnough color2.a, 1.0
+  color = Color(34, 54, 239)
+
+  Color = color.hue(20)
+
+  equalEnough Color.r, 84
+  equalEnough Color.g, 37
+  equalEnough Color.b, 239
+  equalEnough Color.a, 1.0

 test "#hue$", ->
-  color = Color2(34, 54, 239)
+  color = Color(34, 54, 239)

   color.hue$(60)

@@ -219,17 +219,17 @@
   equalEnough color.a, 1.0

 test "#complement", ->
-  color = Color2(10, 30, 50)
-
-  color2 = color.complement()
-
-  equalEnough color2.r, 51
-  equalEnough color2.g, 31
-  equalEnough color2.b, 10
-  equalEnough color2.a, 1.0
+  color = Color(10, 30, 50)
+
+  Color = color.complement()
+
+  equalEnough Color.r, 51
+  equalEnough Color.g, 31
+  equalEnough Color.b, 10
+  equalEnough Color.a, 1.0

 test "#complement$", ->
-  color = Color2(10, 30, 50)
+  color = Color(10, 30, 50)

   color.complement$()

@@ -239,17 +239,17 @@
   equalEnough color.a, 1.0

 test "#grayscale", ->
-  color = Color2(30, 40, 29)
-
-  color2 = color.grayscale()
-
-  equalEnough color2.r, 35
-  equalEnough color2.g, 35
-  equalEnough color2.b, 35
-  equalEnough color2.a, 1.0
+  color = Color(30, 40, 29)
+
+  Color = color.grayscale()
+
+  equalEnough Color.r, 35
+  equalEnough Color.g, 35
+  equalEnough Color.b, 35
+  equalEnough Color.a, 1.0

 test "#grayscale$", ->
-  color = Color2(30, 40, 29)
+  color = Color(30, 40, 29)

   color.grayscale$()

@@ -259,17 +259,17 @@
   equalEnough color.a, 1.0

 test "#saturate", ->
-  color = Color2(100, 200, 150)
-
-  color2 = color.saturate(0.3)
-
-  equalEnough color2.r, 69
-  equalEnough color2.g, 232
-  equalEnough color2.b, 150
-  equalEnough color2.a, 1.0
+  color = Color(100, 200, 150)
+
+  Color = color.saturate(0.3)
+
+  equalEnough Color.r, 69
+  equalEnough Color.g, 232
+  equalEnough Color.b, 150
+  equalEnough Color.a, 1.0

 test "#saturate$", ->
-  color = Color2(100, 200, 150)
+  color = Color(100, 200, 150)

   color.saturate$(0.3)

@@ -279,17 +279,17 @@
   equalEnough color.a, 1.0

 test "#desaturate", ->
-  color = Color2(69, 232, 150)
-
-  color2 = color.desaturate(0.3)
-
-  equalEnough color2.r, 100
-  equalEnough color2.g, 200
-  equalEnough color2.b, 150
-  equalEnough color2.a, 1.0
+  color = Color(69, 232, 150)
+
+  Color = color.desaturate(0.3)
+
+  equalEnough Color.r, 100
+  equalEnough Color.g, 200
+  equalEnough Color.b, 150
+  equalEnough Color.a, 1.0

 test "#desaturate$", ->
-  color = Color2(69, 232, 150)
+  color = Color(69, 232, 150)

   color.desaturate$(0.3)

@@ -299,17 +299,17 @@
   equalEnough color.a, 1.0

 test "#darken", ->
-  color = Color2(45, 64, 39)
-
-  color2 = color.darken(0.1)
-
-  equalEnough color2.r, 22
-  equalEnough color2.g, 32
-  equalEnough color2.b, 19
-  equalEnough color2.a, 1.0
+  color = Color(45, 64, 39)
+
+  Color = color.darken(0.1)
+
+  equalEnough Color.r, 22
+  equalEnough Color.g, 32
+  equalEnough Color.b, 19
+  equalEnough Color.a, 1.0

 test "#darken$", ->
-  color = Color2(45, 64, 39)
+  color = Color(45, 64, 39)

   color.darken$(0.1)

@@ -319,17 +319,17 @@
   equalEnough color.a, 1.0

 test "#lighten", ->
-  color = Color2(22, 32, 19)
-
-  color2 = color.lighten(0.1)
-
-  equalEnough color2.r, 45
-  equalEnough color2.g, 64
-  equalEnough color2.b, 39
-  equalEnough color2.a, 1.0
+  color = Color(22, 32, 19)
+
+  Color = color.lighten(0.1)
+
+  equalEnough Color.r, 45
+  equalEnough Color.g, 64
+  equalEnough Color.b, 39
+  equalEnough Color.a, 1.0

 test "#lighten$", ->
-  color = Color2(22, 32, 19)
+  color = Color(22, 32, 19)

   color.lighten$(0.1)

@@ -339,17 +339,17 @@
   equalEnough color.a, 1.0

 test "#mixWith", ->
-  color1 = Color2(50, 40, 60, 0.3)
-  color2 = Color2(10, 5, 16, 0.2)
-
-  mixedColor = color1.mixWith(color2)
+  color1 = Color(50, 40, 60, 0.3)
+  Color = Color(10, 5, 16, 0.2)
+
+  mixedColor = color1.mixWith(Color)

   equalEnough mixedColor.r, 30
   equalEnough mixedColor.g, (45 / 2).round()
   equalEnough mixedColor.b, (76 / 2).round()
   equalEnough mixedColor.a, 0.5 / 2

-  weightedMixedColor = color1.mixWith(color2, 0.1)
+  weightedMixedColor = color1.mixWith(Color, 0.1)

   equalEnough weightedMixedColor.r, ((50 * 0.1) + (10 * 0.9)).round()
   equalEnough weightedMixedColor.g, ((40 * 0.1) + (5 * 0.9)).round()
@@ -357,19 +357,19 @@
   equalEnough weightedMixedColor.a, (0.3 * 0.1) + (0.2 * 0.9)

 test "#mixWith$", ->
-  color1 = Color2(50, 40, 60, 0.3)
-  color2 = Color2(10, 5, 16, 0.2)
-
-  color3 = Color2(50, 40, 60, 0.3)
-
-  color1.mixWith$(color2)
+  color1 = Color(50, 40, 60, 0.3)
+  Color = Color(10, 5, 16, 0.2)
+
+  color3 = Color(50, 40, 60, 0.3)
+
+  color1.mixWith$(Color)

   equalEnough color1.r, 30
   equalEnough color1.g, (45 / 2).round()
   equalEnough color1.b, (76 / 2).round()
   equalEnough color1.a, 0.5 / 2

-  color3.mixWith$(color2, 0.1)
+  color3.mixWith$(Color, 0.1)

   equalEnough color3.r, ((50 * 0.1) + (10 * 0.9)).round()
   equalEnough color3.g, ((40 * 0.1) + (5 * 0.9)).round()
@@ -377,7 +377,7 @@
   equalEnough color3.a, (0.3 * 0.1) + (0.2 * 0.9)

 test "Color.random", ->
-  color = Color2.random()
+  color = Color.random()

   ok 0 <= color.r <= 255
   ok 0 <= color.g <= 255
@@ -385,17 +385,17 @@
   equalEnough color.a, 1.0

 test "Color.mix", ->
-  color1 = Color2(50, 40, 60, 0.3)
-  color2 = Color2(10, 5, 16, 0.2)
-
-  mixedColor = Color2.mix(color1, color2)
+  color1 = Color(50, 40, 60, 0.3)
+  Color = Color(10, 5, 16, 0.2)
+
+  mixedColor = Color.mix(color1, Color)

   equalEnough mixedColor.r, 30
   equalEnough mixedColor.g, (45 / 2).round()
   equalEnough mixedColor.b, (76 / 2).round()
   equalEnough mixedColor.a, 0.5 / 2

-  weightedMixedColor = Color2.mix(color1, color2, 0.1)
+  weightedMixedColor = Color.mix(color1, Color, 0.1)

   equalEnough weightedMixedColor.r, ((50 * 0.1) + (10 * 0.9)).round()
   equalEnough weightedMixedColor.g, ((40 * 0.1) + (5 * 0.9)).round()
@@ -403,14 +403,14 @@
   equalEnough weightedMixedColor.a, (0.3 * 0.1) + (0.2 * 0.9)

 test "accepts named colors", ->
-  white = Color2("white")
+  white = Color("white")

   equalEnough white.r, 255
   equalEnough white.g, 255
   equalEnough white.b, 255
   equalEnough white.a, 1.0

-  piPink = Color2("Paul Irish Pink")
+  piPink = Color("Paul Irish Pink")

   equalEnough piPink.r, 255
   equalEnough piPink.g, 94


Fix enemy death animation for last of squad

--- app/scripts/lib/script_modules/level.coffee
+++ app/scripts/lib/script_modules/level.coffee
@@ -82,10 +82,12 @@
                 lastLocation = location

           if allKilled and lastLocation
-            lastLocation.x -= Crafty.viewport.x
-            lastLocation.y -= Crafty.viewport.y
+            dropLocation = {
+              x: lastLocation.x - Crafty.viewport.x
+              y: lastLocation.y - Crafty.viewport.y
+            }
             if settings.drop
-              @drop(item: settings.drop, location: lastLocation)(sequence)
+              @drop(item: settings.drop, location: dropLocation)(sequence)

   attackWaves: (promise, settings = {}) ->
     (sequence) =>


Backslash bug under windows

Backslash bug under windows

--- src/aliasify.coffee
+++ src/aliasify.coffee
@@ -34,6 +34,6 @@
             if verbose
                 console.log "aliasify - #{opts.file}: replacing #{args[0]} with #{replacement}"

-            result = "require('#{replacement}')"
+            result = "require('#{replacement.replace(/\\/gi,"/")}')"

     done null, result


:construction: Try making tests passes on travis

--- spec/table-element-spec.coffee
+++ spec/table-element-spec.coffee
@@ -101,6 +101,7 @@
         if i % 2 is 0 then 'yes' else 'no'
       ]

+    atom.config.set 'editor.useShadowDom', false
     atom.config.set 'tablr.tableEditor.rowHeight', 20
     atom.config.set 'tablr.tableEditor.columnWidth', 100
     atom.config.set 'tablr.tableEditor.rowOverdraw', 10


:art:

:art:

--- src/tile-component.coffee
+++ src/tile-component.coffee
@@ -32,7 +32,7 @@
     @newState = state
     unless @oldState
       @oldState = {tiles: {}}
-      @oldState.tiles[@id] = { lines: {}}
+      @oldState.tiles[@id] = {lines: {}}

     @newTileState = @newState.tiles[@id]
     @oldTileState = @oldState.tiles[@id]


Removed a file that was not being used

Removed a file that was not being used

--- lib/components/breakpoint-component.coffee
+++ lib/components/breakpoint-component.coffee
@@ -1,27 +0,0 @@
-module.exports =
-class BreakpointComponent
-  constructor: ({@context}) ->
-    # expand/collapse:
-    @panels = { watchExprs: true, variables: true, callStack: true, console: true, breakpoints: true }
-
-  toggleConnect: =>
-    if @context.isDisconnected() then @context.connect() else @context.disconnect()
-
-  connectText: =>
-    if @context.isDisconnected() then "Connect" else "Disconnect"
-
-  playText: =>
-    if @context.isRunning() then "Pause" else "Play"
-
-  togglePlay: =>
-    if @context.isRunning() then @context.pause() else @context.play()
-
-  playIconClass: =>
-    if @context.isRunning() then "rd-icon-pause" else "rd-icon-play"
-
-rivets.components['rd-main'] =
-  template: ->
-    fs.readFileSync(require.resolve('../../templates/main.html'), 'utf8')
-
-  initialize: (el, data) ->
-    new MainComponent(data)


CUI.dom.setAttribute: Allow "object.DOM".

--- src/base/dom.coffee
+++ src/base/dom.coffee
@@ -206,9 +206,11 @@
 		node.removeAttribute(key)
 		node

-	@setAttribute: (node, key, value) ->
-		if not node
+	@setAttribute: (_node, key, value) ->
+		if not _node
 			return null
+
+		node = _node.DOM or _node

 		if CUI.util.isNull(value) or value == false
 			return @removeAttribute(node, key)


adapt conv model for added conversation

adapt conv model for added conversation

for some reason Client.createconversation response
gives back a conversation whose ‘id’ is at
conversation.id.id which is slightly different
compared to other calls

--- src/ui/models/conv.coffee
+++ src/ui/models/conv.coffee
@@ -13,7 +13,7 @@
         {conversation, event} = conv
         conv = conversation
         conv.event = event
-    {id} = conv.conversation_id
+    {id} = conv.conversation_id or conv.id
     domerge id, conv
     # participant_data contains entity information
     # we want in the entity lookup


uses full name of keys because of VolumeUp/Down

--- src/ui/views/input.coffee
+++ src/ui/views/input.coffee
@@ -84,8 +84,8 @@
                     ta.parentNode.style.height = (ta.offsetHeight + 24) + 'px'
                     messages.scrollToBottom() if messages?
             , onkeydown: (e) ->
-                if (e.metaKey or e.ctrlKey) and e.key.match('Up$')? then action 'selectNextConv', -1
-                if (e.metaKey or e.ctrlKey) and e.key.match('Down$')? then action 'selectNextConv', +1
+                if (e.metaKey or e.ctrlKey) and e.key == 'ArrowUp' then action 'selectNextConv', -1
+                if (e.metaKey or e.ctrlKey) and e.key == 'ArrowDown' then action 'selectNextConv', +1
                 unless isModifierKey(e)
                     if e.keyCode == 27
                         e.preventDefault()
@@ -104,8 +104,8 @@
                         e.target.value = ''
                         autosize.update e.target
                     if e.target.value == ''
-                        if e.key.match('Up$')? then historyWalk e.target, -1
-                        if e.key.match('Down$')? then historyWalk e.target, +1
+                        if e.key is 'ArrowUp' then historyWalk e.target, -1
+                        if e.key is 'ArrowDown' then historyWalk e.target, +1
                 action 'lastkeydown', Date.now() unless isAltCtrlMeta(e)
             , onkeyup: (e) ->
                 #check for emojis after pressing space


namespaced unbind

namespaced unbind

--- src/bindable.coffee
+++ src/bindable.coffee
@@ -43,8 +43,8 @@
   @param {Function} callback The function to be called when the specified event
   is triggered.
   ###
-  bind: (event, callback) ->
-
+  bind: (events, callback) ->
+    events.s
     eventCallbacks[event] = eventCallbacks[event] || []

     eventCallbacks[event].push(callback)


be a bit more fail-safe (still only workaround)

--- lib/nuclide-test-runner-pytest.coffee
+++ lib/nuclide-test-runner-pytest.coffee
@@ -167,7 +167,13 @@
             if testDetails.length
               debugger
               _details = testDetails.join("\n")
-              failedTests["#{fileName}::#{testName}"].details = "\x1b[0m"+_details
+              _key = "#{fileName}::#{testName}"
+
+              if _key of failedTests
+                failedTests["#{fileName}::#{testName}"].details = _details
+              else
+                console.error "could not find #{_key} in" , failedTests
+
               testDetails = []

             testName = m[1]
@@ -314,7 +320,6 @@
     # runPyTest "--version",
     #   error:

-
     return {
       label: "py.test"
       getByUri: (uri) ->


If the observer's target changes from the previous binding's @model value, reconstruct the dependency observers for the binding.

--- src/bindings.coffee
+++ src/bindings.coffee
@@ -58,7 +58,15 @@

   # Syncs up the view binding with the model.
   sync: =>
-    @model = @observer.target
+    if @model isnt @observer.target
+      observer.unobserve() for observer in @dependencies
+      @dependencies = []
+
+      if (@model = @observer.target)? and @options.dependencies?.length
+        for dependency in @options.dependencies
+          observer = new Rivets.Observer @view, @model, dependency, @sync
+          @dependencies.push observer
+
     @set @observer.value()

   # Publishes the value currently set on the input element back to the model.


Fix screen-row vs buffer-row error in indent operators

--- lib/operators/indent-operators.coffee
+++ lib/operators/indent-operators.coffee
@@ -1,61 +1,28 @@
 {Operator} = require './general-operators'
-#
-# It indents everything selected by the following motion.
-#
-class Indent extends Operator
-  # Public: Indents the text selected by the given motion.
-  #
-  # count - The number of times to execute.
-  #
-  # Returns nothing.
+
+class AdjustIndentation extends Operator
   execute: (count=1) ->
-    @indent(count)
-
-  # Protected: Indents or outdents the text selected by the given motion.
-  #
-  # count  - The number of times to execute.
-  # direction - Either 'indent' or 'outdent'
-  #
-  # Returns nothing.
-  indent: (count, direction='indent') ->
     mode = @vimState.mode
-
     @motion.select(count)
     {start} = @editor.getSelectedBufferRange()
-    if direction == 'indent'
-      @editor.indentSelectedRows()
-    else if direction == 'outdent'
-      @editor.outdentSelectedRows()
-    else if direction == 'auto'
-      @editor.autoIndentSelectedRows()

-    if mode != 'visual'
-      @editor.setCursorScreenPosition([start.row, 0])
+    @indent()
+
+    if mode isnt 'visual'
+      @editor.setCursorBufferPosition([start.row, 0])
       @editor.moveToFirstCharacterOfLine()
       @vimState.activateCommandMode()

-#
-# It outdents everything selected by the following motion.
-#
-class Outdent extends Indent
-  # Public: Indents the text selected by the given motion.
-  #
-  # count - The number of times to execute.
-  #
-  # Returns nothing.
-  execute: (count=1) ->
-    @indent(count, 'outdent')
+class Indent extends AdjustIndentation
+  indent: ->
+    @editor.indentSelectedRows()

-#
-# It autoindents everything selected by the following motion.
-#
-class Autoindent extends Indent
-  # Public: Autoindents the text selected by the given motion.
-  #
-  # count - The number of times to execute.
-  #
-  # Returns nothing.
-  execute: (count=1) ->
-    @indent(count, 'auto')
+class Outdent extends AdjustIndentation
+  indent: ->
+    @editor.outdentSelectedRows()
+
+class Autoindent extends AdjustIndentation
+  indent: ->
+    @editor.autoIndentSelectedRows()

 module.exports = {Indent, Outdent, Autoindent}


Adding support for the most recent version of Font Awesome.

--- src/widgets/button.coffee
+++ src/widgets/button.coffee
@@ -19,8 +19,8 @@
     _create: ->
       # By default the icon is icon-command, but this doesn't
       # always match with
-      # <http://fortawesome.github.com/Font-Awesome/#base-icons>
-      @options.icon ?= "icon-#{@options.label.toLowerCase()}"
+      # <http://fortawesome.github.io/Font-Awesome/icons/>
+      @options.icon ?= "fa-#{@options.label.toLowerCase()}"

       id = "#{@options.uuid}-#{@options.label}"
       opts = @options
@@ -109,7 +109,7 @@
       jQuery "<button id=\"#{id}\"
         class=\"#{classes.join(' ')}\" title=\"#{label}\">

-
+

         </button>"


:bug: Fix selection handle position when start column is not 0

--- lib/selection-handle-component.coffee
+++ lib/selection-handle-component.coffee
@@ -9,5 +9,6 @@

     div className: 'selection-box-handle', style: {
       top: (top + height) + 'px'
-      left: (left + width) + '%'
+      left: width + '%'
+      transform: "translate(#{left + 'px'}, 0)"
     }


Start documentation. Slightly refactor some arguments.

--- src/checkout.coffee
+++ src/checkout.coffee
@@ -30,16 +30,19 @@
 readSubcookie = (name, cookie) ->
 	mapize(cookie, '&', '=', ((s)->s), unescape)[name]

-# VTEX Checkout API v0.1.0
-# Depends on jQuery, vtex.utils.coffee, jquery.url.js
+# vtex.js
 #
 # Offers convenient methods for using the API in JS.
-# For more information head to: docs.vtex.com.br/js/CheckoutAPI
-class CheckoutAPI
-	constructor: (ajax = $.ajax) ->
+class VTEX
+	# Instantiate the SDK.
+	#
+	# @param ajax [Function] (default = $.ajax) an AJAX function that must follow the convention, i.e., accept an object of options such as 'url', 'type' and 'data', and return a promise.
+	# @param HostURL [String] (default = window.location.origin) the base URL for API calls, without the trailing slash, e.g. "http://example.vtexcommerce.com.br"
+	# @return [VTEX] the SDK
+	constructor: (ajax = $.ajax, hostURL) ->
 		@ajax = AjaxQueue(ajax)
 		@CHECKOUT_ID = 'checkout'
-		@HOST_URL = window.location.origin
+		@HOST_URL = hostURL || window.location.origin
 		@HOST_ORDER_FORM_URL = @HOST_URL + '/api/checkout/pub/orderForm/'
 		@POSTALCODE_URL = @HOST_URL + '/api/checkout/pub/postal-code/'
 		@GATEWAY_CALLBACK_URL = @HOST_URL + '/checkout/gatewayCallback/{0}/{1}/{2}'
@@ -47,7 +50,7 @@
 		@stateRequestHashToResponseMap = {}
 		@subjectToJqXHRMap = {}

-		@expectedFormSections =
+		@allOrderFormSections =
 			[
 				'items'
 				'totalizers'
@@ -63,7 +66,11 @@
 				'ratesAndBenefitsData'
 			]

-	getOrderForm: (expectedFormSections = @expectedFormSections) =>
+	# Sends an idempotent request to retrieve the current OrderForm.
+	# @param expectedOrderFormSections [Array] an array of attachment names.
+	# @return [Promise] a promise for the OrderForm.
+	getOrderForm: (expectedFormSections = @allOrderFormSections) =>
+		# TODO guardar orderForm
 		checkoutRequest = { expectedOrderFormSections: expectedFormSections }
 		@ajax
 			url: @_getOrderFormURL()
@@ -72,26 +79,29 @@
 			dataType: 'json'
 			data: JSON.stringify(checkoutRequest)

-	# Sends an orderForm attachment to the current OrderForm.
-	# @param attachmentId
-	# @param serializedAttachment stringified serializedAttachment
-	# @param expectedOrderFormSections
-	sendAttachment: (attachmentId, serializedAttachment, expectedOrderFormSections = @expectedFormSections, options = {}) =>
-		if attachmentId is undefined or serializedAttachment is undefined
+	# Sends an OrderForm attachment to the current OrderForm, possibly updating it.
+	# @param attachmentId [String] the name of the attachment you're sending.
+	# @param attachment [Object] the attachment.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @param options [Object] extra options.
+	# @option options [String] (default = null) subject an internal name to give to your attachment submission.
+	# @option options [Boolean] (default = false) abort indicates whether a previous submission with the same subject should be aborted, if it's ongoing.
+	# @return [Promise] a promise for the updated OrderForm.
+	sendAttachment: (attachmentId, attachment, expectedOrderFormSections = @allOrderFormSections, options = {}) =>
+		if attachmentId is undefined or attachment is undefined
 			d = $.Deferred()
 			d.reject("Invalid arguments")
 			return d.promise()

 		# TODO alterar chamadas para não mandar stringified
-		data = JSON.parse(serializedAttachment)
-		data[expectedOrderFormSections] = expectedOrderFormSections
+		attachment[expectedOrderFormSections] = expectedOrderFormSections

 		xhr = @ajax
 			url: @_getSaveAttachmentURL(attachmentId)
 			type: 'POST'
 			contentType: 'application/json; charset=utf-8'
 			dataType: 'json'
-			data: JSON.stringify(data)
+			data: JSON.stringify(attachment)

 		if options.abort and options.subject
 			@subjectToJqXHRMap[options.subject]?.abort()
@@ -99,16 +109,23 @@

 		return xhr

+	# Sends a request to set the used locale.
+	# @param locale [String] the locale string, e.g. "pt-BR", "en-US".
+	# @return [Promise] a promise for the success.
 	sendLocale: (locale='pt-BR') =>
-		attachmentId = 'clientPreferencesData';
-		serializedAttachment = JSON.stringify(locale: locale)
-		@sendAttachment(attachmentId, serializedAttachment, [])
-
-	addOfferingWithInfo: (offeringId, offeringInfo, itemIndex, expectedOrderFormSections) =>
+		@sendAttachment('clientPreferencesData', {locale: locale}, [])
+
+	# Sends a request to add an offering, along with its info, to the OrderForm.
+	# @param offeringId [String, Number] the id of the offering.
+	# @param offeringInfo
+	# @param itemIndex [Number] the index of the item for which the offering applies.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
+	addOfferingWithInfo: (offeringId, offeringInfo, itemIndex, expectedOrderFormSections = @allOrderFormSections) =>
 		updateItemsRequest =
 			id: offeringId
 			info: offeringInfo
-			expectedOrderFormSections: expectedOrderFormSections ? @expectedFormSections
+			expectedOrderFormSections: expectedOrderFormSections

 		@ajax
 			url: @_getAddOfferingsURL(itemIndex)
@@ -117,13 +134,23 @@
 			dataType: 'json'
 			data: JSON.stringify(updateItemsRequest)

+	# Sends a request to add an offering to the OrderForm.
+	# @param offeringId [String, Number] the id of the offering.
+	# @param itemIndex [Number] the index of the item for which the offering applies.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
 	addOffering: (offeringId, itemIndex, expectedOrderFormSections) =>
 		@addOfferingWithInfo(offeringId, null, itemIndex, expectedOrderFormSections)

-	removeOffering: (offeringId, itemIndex, expectedOrderFormSections) =>
+	# Sends a request to remove an offering from the OrderForm.
+	# @param offeringId [String, Number] the id of the offering.
+	# @param itemIndex [Number] the index of the item for which the offering applies.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
+	removeOffering: (offeringId, itemIndex, expectedOrderFormSections = expectedOrderFormSections) =>
 		updateItemsRequest =
 			Id: offeringId
-			expectedOrderFormSections: expectedOrderFormSections ? @expectedFormSections
+			expectedOrderFormSections: expectedOrderFormSections

 		@ajax
 			url: @_getRemoveOfferingsURL(itemIndex, offeringId)
@@ -132,14 +159,17 @@
 			dataType: 'json'
 			data: JSON.stringify(updateItemsRequest)

-	updateItems: (itemsJS, expectedOrderFormSections = @expectedFormSections) =>
+	# Sends a request to update the items in the OrderForm.
+	# @param items [Array] an array of objects representing the items in the OrderForm.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
+	updateItems: (items, expectedOrderFormSections = @allOrderFormSections) =>
 		updateItemsRequest =
-			orderItems: itemsJS
+			orderItems: items
 			expectedOrderFormSections: expectedOrderFormSections

 		if @requestingItem isnt undefined
 			@requestingItem.abort()
-			console.log 'Abortando', @requestingItem

 		return @requestingItem = @ajax(
 			url: @_getUpdateItemURL()
@@ -150,7 +180,11 @@
 		).done =>
 			@requestingItem = undefined

+	# Sends a request to remove items from the OrderForm.
+	# @param items [Array] an array of objects representing the items to remove.
+	# @return [Promise] a promise for the updated OrderForm.
 	removeItems: (items) =>
+		# TODO usar copia local do OrderForm
 		deferred = $.Deferred()
 		promiseForItems = if items then $.when(items) else @getOrderForm(['items']).then (orderForm) -> orderForm.items
 		promiseForItems.then (array) =>
@@ -158,10 +192,14 @@
 				.done((data) -> deferred.resolve(data)).fail(deferred.reject)
 		deferred.promise()

-	addDiscountCoupon: (couponCode, expectedOrderFormSections) =>
+	# Sends a request to add a discount coupon to the OrderForm.
+	# @param couponCode [String] the coupon code to add.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
+	addDiscountCoupon: (couponCode, expectedOrderFormSections = @allOrderFormSections) =>
 		couponCodeRequest =
 			text: couponCode
-			expectedOrderFormSections: expectedOrderFormSections ? @expectedFormSections
+			expectedOrderFormSections: expectedOrderFormSections

 		@ajax
 			url: @_getAddCouponURL()
@@ -170,36 +208,58 @@
 			dataType: 'json'
 			data: JSON.stringify couponCodeRequest

+	# Sends a request to remove the discount coupon from the OrderForm.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
 	removeDiscountCoupon: (expectedOrderFormSections) =>
-		return @addDiscountCoupon('', expectedOrderFormSections)
-
-	removeGiftRegistry: (expectedFormSections = @expectedFormSections) =>
+		@addDiscountCoupon('', expectedOrderFormSections)
+
+	# Sends a request to remove the gift registry for the current OrderForm.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the updated OrderForm.
+	removeGiftRegistry: (expectedFormSections = @allOrderFormSections) =>
 		checkoutRequest = { expectedOrderFormSections: expectedFormSections }
 		@ajax
-			url: "/api/checkout/pub/orderForm/giftRegistry/#{@_getOrderFormId()}/remove"
+			url: @_getRemoveGiftRegistryURL()
 			type: 'POST'
 			contentType: 'application/json; charset=utf-8'
 			dataType: 'json'
 			data: JSON.stringify(checkoutRequest)

+	# Sends a request to calculates shipping for the current OrderForm, given an address object.
+	# @param address [Object] an address object
+	# @return [Promise] a promise for the updated OrderForm.
 	calculateShipping: (address) =>
-		shippingRequest = address: address
-		return @sendAttachment('shippingData', JSON.stringify(shippingRequest))
-
-	# Aceita um address com propriedades postalCode e country
+		@sendAttachment('shippingData', {address: address})
+
+	# Given an address with postal code and a country, retrieves a complete address, when available.
+	# @param address [Object] an address that must contain the properties `postalCode` and `country`.
+	# @return [Promise] a promise for the address.
 	getAddressInformation: (address) =>
 		@ajax
 			url: @_getPostalCodeURL(address.postalCode, address.country)
 			type: 'GET'
 			timeout : 20000

-	getProfileByEmail: (email, salesChannel) =>
+	# Sends a request to retrieve a user's profile.
+	# @param email [String] the user's email.
+	# @param salesChannel [Number, String] the sales channel in which to look for the user's profile.
+	# @return [Promise] a promise for the profile.
+	getProfileByEmail: (email, salesChannel = 1) =>
 		@ajax
 			url: @_getProfileURL()
 			type: 'GET'
 			data: {email: email, sc: salesChannel}

-	startTransaction: (value, referenceValue, interestValue, savePersonalData = false, optinNewsLetter = false, expectedOrderFormSections = @expectedFormSections) =>
+	# Sends a request to start the transaction. This is the final step in the checkout process.
+	# @param value
+	# @param referenceValue
+	# @param interestValue
+	# @param savePersonalData [Boolean] (default = false) whether to save the user's data for using it later in another order.
+	# @param optinNewsLetter [Boolean] (default = true) whether to subscribe the user to the store newsletter.
+	# @param expectedOrderFormSections [Array] (default = *all*) an array of attachment names.
+	# @return [Promise] a promise for the final OrderForm.
+	startTransaction: (value, referenceValue, interestValue, savePersonalData = false, optinNewsLetter = false, expectedOrderFormSections = @allOrderFormSections) =>
 		transactionRequest = {
 			referenceId: @_getOrderFormId()
 			savePersonalData: savePersonalData
@@ -217,6 +277,9 @@
 			dataType: 'json',
 			data: JSON.stringify(transactionRequest)

+	# Sends a request to retrieve the orders for a specific orderGroupId.
+	# @param orderGroupId [String] the ID of the order group.
+	# @return [Promise] a promise for the orders.
 	getOrders: (orderGroupId) =>
 		@ajax
 			url: @_getOrdersURL(orderGroupId)
@@ -224,6 +287,8 @@
 			contentType: 'application/json; charset=utf-8'
 			dataType: 'json'

+	# Sends a request to clear the OrderForm messages.
+	# @return [Promise] a promise for the success.
 	clearMessages: =>
 		clearMessagesRequest = { expectedOrderFormSections: [] }
 		@ajax
@@ -233,6 +298,9 @@
 			dataType: 'json'
 			data: JSON.stringify clearMessagesRequest

+	# Sends a request to remove a payment account from the OrderForm.
+	# @param accountId [String] the ID of the payment account.
+	# @return [Promise] a promise for the success.
 	removeAccountId: (accountId) =>
 		removeAccountIdRequest = { expectedOrderFormSections: [] }
 		@ajax
@@ -242,16 +310,20 @@
 			dataType: 'json'
 			data: JSON.stringify removeAccountIdRequest

+	# This method should be used to get the URL to redirect the user to when he chooses to logout.
+	# @return [String] the URL.
 	getChangeToAnonymousUserURL: =>
 		@HOST_URL + '/checkout/changeToAnonymousUser/' + @_getOrderFormId()

 	#
-	# PRIVATE
+	# URL BUILDERS
 	#

+	# @nodoc
 	_getOrderFormId: =>
 		@_getOrderFormIdFromCookie() or @_getOrderFormIdFromURL() or ''

+	# @nodoc
 	_getOrderFormIdFromCookie: =>
 		COOKIE_NAME = 'checkout.vtex.com'
 		COOKIE_ORDER_FORM_ID_KEY = '__ofid'
@@ -259,38 +331,53 @@
 		return undefined if cookie is undefined or cookie is ''
 		return readSubcookie(cookie, COOKIE_ORDER_FORM_ID_KEY)

+	# @nodoc
 	_getOrderFormIdFromURL: =>
 		urlParam('orderFormId')

+	# @nodoc
 	_getOrderFormURL: =>
 		@HOST_ORDER_FORM_URL + @_getOrderFormId()

+	# @nodoc
 	_getSaveAttachmentURL: (attachmentId) =>
 		@_getOrderFormURL() + '/attachments/' + attachmentId

+	# @nodoc
 	_getAddOfferingsURL: (itemIndex) =>
 		@_getOrderFormURL() + '/items/' + itemIndex + '/offerings'

+	# @nodoc
 	_getRemoveOfferingsURL: (itemIndex, offeringId) =>
 		@_getOrderFormURL() + '/items/' + itemIndex + '/offerings/' + offeringId + '/remove'

+	# @nodoc
 	_getAddCouponURL: =>
 		@_getOrderFormURL() + '/coupons'

+	# @nodoc
 	_getOrdersURL: (orderGroupId) =>
 		@HOST_URL + '/api/checkout/pub/orders/order-group/' + orderGroupId

+	# @nodoc
 	_startTransactionURL: =>
 		@_getOrderFormURL() + '/transaction'

+	# @nodoc
 	_getUpdateItemURL: =>
 		@_getOrderFormURL() + '/items/update/'

+	# @nodoc
 	_getPostalCodeURL: (postalCode = '', countryCode = 'BRA') =>
 		@POSTALCODE_URL + countryCode + '/' + postalCode

+	# @nodoc
 	_getProfileURL: =>
 		@HOST_URL + '/api/checkout/pub/profiles/'
+
+	# @nodoc
+	_getRemoveGiftRegistryURL: =>
+		@HOST_ORDER_FORM_URL + "/giftRegistry/#{@_getOrderFormId()}/remove"

 # Compatibility with old clients - DEPRECATED!
 window.vtex.checkout.API = CheckoutAPI


fix infnite loop on unknown field

fix infnite loop on unknown field

--- bokehjs/src/coffee/tool/hover_tool.coffee
+++ bokehjs/src/coffee/tool/hover_tool.coffee
@@ -98,13 +98,11 @@
       }
       x = @plot_view.xmapper.map_from_target(vx)
       y = @plot_view.ymapper.map_from_target(vy)
-
       datasources = {}
       datasource_selections = {}
       for renderer in @mget_obj('renderers')
         datasource = renderer.get_obj('data_source')
         datasources[datasource.id] = datasource
-
       for renderer in @mget_obj('renderers')
         datasource_id = renderer.get_obj('data_source').id
         _.setdefault(datasource_selections, datasource_id, [])
@@ -147,16 +145,18 @@
               value = value.replace("$vy", "#{ vy }")
               value = value.replace("$sx", "#{ e.bokehX }")
               value = value.replace("$sy", "#{ e.bokehY }")
-
               while value.indexOf("@") >= 0
-                [match, unused, column] = value.match(/(@)(\w*)/)
-                column = ds.getcolumn(column)
-                if column?
-                  dsvalue = column[i]
-                  if typeof(dsvalue) == "number"
-                    value = value.replace(match, "#{ _format_number(dsvalue) }")
-                  else
-                    value = value.replace(match, "#{ dsvalue }")
+                [match, unused, column_name] = value.match(/(@)(\w*)/)
+                columns = ds.columns()
+                if column not in columns
+                  value = value.replace(column_name, "#{ column_name } unknown")
+                  break
+                column = ds.getcolumn(column_name)
+                dsvalue = column[i]
+                if typeof(dsvalue) == "number"
+                  value = value.replace(match, "#{ _format_number(dsvalue) }")
+                else
+                  value = value.replace(match, "#{ dsvalue }")
               span = $("<span>#{ value }</span>")
               td.append(span)