fix function definition

fix function definition

--- scripts/feed_checker.coffee
+++ scripts/feed_checker.coffee
@@ -23,7 +23,9 @@
   feed_check_interval = null

   # article with same guid not found
-  is_new = (articles, guid) -> articles.every (v) -> v.guid != guid
+  is_new = (articles, guid) ->
+    articles.every (v) ->
+      v.guid != guid

   robot.brain.on 'loaded', ->
     interval = parseInt process.env.FEED_CHECK_INTERVAL
@@ -42,7 +44,8 @@
         request(url).pipe(new feedparser())
           .on 'error', (err) ->
             robot.logger.warning "feed parsing error in #{url}: #{err}"
-          .on 'meta', (meta) -> next.push meta
+          .on 'meta', (meta) ->
+            next.push meta
           .on 'end', ->
             if prev.length != 0 then next.forEach (article) ->
               if is_new prev, article.guid


No more console for you.

No more console for you.

--- scripts/youtube-info.coffee
+++ scripts/youtube-info.coffee
@@ -35,5 +35,4 @@
     else
       $ = cheerio.load(body)
       title = $('title').text()
-      console.log title
       msg.send title


Typo fix: usefull -> useful

Typo fix: usefull -> useful

--- docker_tutorial/static/js/steps.coffee
+++ docker_tutorial/static/js/steps.coffee
@@ -183,7 +183,7 @@

Check your running image

You now have a running container. Let's see what is going on.

Using docker ps we can see a list of all running containers, and using docker inspect
-      we can see all sorts of usefull information about this container.

+      we can see all sorts of useful information about this container.

       """
 assignment: """

Assignment


comment

comment

--- test/files/get_primary_uid.iced
+++ test/files/get_primary_uid.iced
@@ -23,5 +23,6 @@
   cb()

 exports.test_gmax = (T, cb) ->
+  # compare hashes to protect people's UIDs from spam scrapers
   await test "gmax", "c82219629a4dd0283fd3d0d1129cca58ac0c8d45d6d0b40c1acda50a8991fb28", T, defer()
   cb()


improve coffeescript error outputs to handle generic errors

--- lib/adapters/coffee.coffee
+++ lib/adapters/coffee.coffee
@@ -13,13 +13,21 @@
 error_formatter = (error, file) ->
   return error unless error

-  new Error "
-  \n\nFile: #{file.relative_path}
-  \nLine\n
-  #{error.location.first_line}| #{error.message} \n
-  \n
-  #{fs.readFileSync(file.path, 'utf8').split("\n")[error.location.first_line]}\n
-  #{new Array(error.location.first_column).join(' ') + '^'}\n\n"
+  # this is from a coffeescript compile issue
+  if (error.location?)
+    new Error "
+    \n\nFile: #{file.relative_path}
+    \nLine\n
+    #{error.location.first_line}| #{error.message} \n
+    \n
+    #{fs.readFileSync(file.path, 'utf8').split("\n")[error.location.first_line]}\n
+    #{new Array(error.location.first_column).join(' ') + '^'}\n\n"
+  # to handle generic errors
+  else
+    new Error "
+    \n\nFile: #{file.relative_path}
+    \n#{error.message}
+    \n\n"

 exports.compile = (file, options={}, cb) ->
   _.defaults(options,


Get rid of redundant variable, add descriptive comment.

--- app/assets/service/upload.coffee
+++ app/assets/service/upload.coffee
@@ -12,7 +12,11 @@
       file.store.save()
       return

-    fileError: (file, message, flow) ->
+
+    # If there's an error in the file-upload,
+    # let's first kill the upload process, then
+    # send back the error message.
+    fileError: (file, message) ->
       file.abort()
       messages.addError
         type: 'red'


Rollback getSelectable

Rollback getSelectable

--- client/app/components/message-list.coffee
+++ client/app/components/message-list.coffee
@@ -84,8 +84,8 @@
             displayConversations : displayConvs

     # for SelectionManagerMixin
-    getSelectables: ->
-        @state.messages.mapKeys (key, value) -> value.get('id')
+    getSelectables: (props = @props, state = @state) ->
+        state.messages.map (message) -> message.get('id')

     getEmptyListMessage: ->
         return @props.emptyListMessage if @props.emptyListMessage


socialapi: add integration data to mapActivity

--- client/app/lib/socialapicontroller.coffee
+++ client/app/lib/socialapicontroller.coffee
@@ -137,6 +137,8 @@
     m.replies      = mapActivities data.replies or []
     m.repliesCount = data.repliesCount
     m.isFollowed   = data.isFollowed
+
+    m.integration = data.integration

     # this is sent by the server when
     # response for pinned messages


failing test for #572

failing test for #572

--- spec/specs/bus.coffee
+++ spec/specs/bus.coffee
@@ -94,6 +94,14 @@
     bus.onValue(->)
     expect(plugged).to.deep.equal(false)

+  it "respects end() calls before subscribers", ->
+    failed = false
+    bus = new Bacon.Bus()
+    bus.end()
+    bus.onValue(-> failed = true;)
+    bus.push('foo')
+    expect(failed).to.deep.equal(false)
+
   it "returns unplug function from plug", ->
     values = []
     bus = new Bacon.Bus()
@@ -117,5 +125,3 @@
     expect(o).to.deep.equal(["foo"])
   it "toString", ->
     expect(new Bacon.Bus().toString()).to.equal("Bacon.Bus()")
-
-


<debug> Adding forgotten comma.

<debug> Adding forgotten comma.

--- server/models/driver.coffee
+++ server/models/driver.coffee
@@ -130,7 +130,7 @@
 			return cleanUp()

 		# Check if this driver isn't already added (the name should be unique):
-		@byName file.name (err, drivers)->
+		@byName file.name, (err, drivers)->
 			if err
 				callback 'DB error', null
 			else if drivers.length isnt 0 # Driver already exists.


Optimize insertText

Optimize insertText

Rearrange the order of the conditions so that the cheapest goes first.

Signed-off-by: Nathan Sobo <2e8aa918660411855c6d44d5bb2da677aa033255@github.com>

--- lib/bracket-matcher.coffee
+++ lib/bracket-matcher.coffee
@@ -43,9 +43,13 @@
       text += '{'
       pair = '}'
     else
-      autoCompleteOpeningBracket = @getScopedSetting('bracket-matcher.autocompleteBrackets') and
-        @isOpeningBracket(text) and not hasWordAfterCursor and not
-        (@isQuote(text) and (hasWordBeforeCursor or hasQuoteBeforeCursor or hasEscapeSequenceBeforeCursor)) and not hasEscapeCharacterBeforeCursor
+      autoCompleteOpeningBracket = (
+        @isOpeningBracket(text) and
+        not hasWordAfterCursor and
+        @getScopedSetting('bracket-matcher.autocompleteBrackets') and
+        not (@isQuote(text) and (hasWordBeforeCursor or hasQuoteBeforeCursor or hasEscapeSequenceBeforeCursor)) and
+        not hasEscapeCharacterBeforeCursor
+      )
       pair = @matchManager.pairedCharacters[text]

     skipOverExistingClosingBracket = false


Comment ParseProvider keys

Comment ParseProvider keys

--- src-public/app.coffee
+++ src-public/app.coffee
@@ -27,8 +27,8 @@
   $urlRouterProvider.otherwise '/fr'

   ParseProvider.initialize(
-    "N2xyMRbsrFcBuzq7TXLwieDGM9FzwODEY44LLFOP",
-    "zTAHO7HKWvbV1awq5wQlexRc368lOQtSbmycOi0O"
+    "N2xyMRbsrFcBuzq7TXLwieDGM9FzwODEY44LLFOP", # Application ID
+    "zTAHO7HKWvbV1awq5wQlexRc368lOQtSbmycOi0O"  # REST API Key
   )

 app.run ($rootScope, $state) ->


Use text instead of html

Use text instead of html

Safer, etc

--- app/javascript/src/notice.coffee
+++ app/javascript/src/notice.coffee
@@ -28,11 +28,11 @@
       $staticNotice = $('#static_notice')
       if $staticNotice.length > 0
         $staticNotice
-          .html(msg)
+          .text(msg)
           .show()
         return

-    $('#notice').html msg
+    $('#notice').text msg
     $('#notice-container').show()

     clearTimeout @timeout


Spelling

Spelling

--- app/lib/views/application.coffee
+++ app/lib/views/application.coffee
@@ -286,7 +286,7 @@

         plotRerender: (->
             $.plot(@$(), [{
-                label: "Fermi-Driac Function"
+                label: "Fermi-Dirac Function"
                 data: @get('points')
             }], @get('options'))
         ).observes('points')


fixes JunoLab/atom-julia-client#108

fixes JunoLab/atom-julia-client#108

--- lib/console/console.coffee
+++ lib/console/console.coffee
@@ -223,9 +223,10 @@

   moveHistory: (up) ->
     {editor} = @getInput()
-    if editor.getText() or not @prefix?
+    if (editor.getText() or not @prefix?) and @prefix?.pos?[0] isnt Infinity
       pos = editor.getCursorBufferPosition()
       text = editor.getTextInRange [[0,0], pos]
+      pos = [Infinity, Infinity] if text is ''
       @prefix = {pos, text}
     next = if up
       @history.getPrevious @prefix.text


Improved insert-type

Improved insert-type

* Better handling of lhs bird tracks
* Works with same-line let/where bindings
* Should handle tab-indentation better

--- lib/haskell-ghc-mod.coffee
+++ lib/haskell-ghc-mod.coffee
@@ -213,19 +213,19 @@
           @process.getTypeInBuffer(editor.getBuffer(), crange)
           .then (o) ->
             {type} = o
-            n = editor.indentationForBufferRow(o.range.start.row)
-            indent = ' '.repeat n * editor.getTabLength()
-            {scope, range, symbol} =
-              Util.getSymbolAtPoint editor, pos
-            symbol = "(#{symbol})" if scope is 'keyword.operator.haskell'
-            # lhs
-            if 'meta.embedded.haskell' in editor.scopeDescriptorForBufferPosition(pos).getScopesArray()
+            {scope, range, symbol} = Util.getSymbolAtPoint editor, pos
+            if editor.getTextInBufferRange(o.range).match(/[=]/)?
               indent = editor.getTextInBufferRange([[o.range.start.row, 0], o.range.start])
-            if editor.getTextInBufferRange(o.range).match(/[=]/)?
-              pos = [range.start.row, 0]
-              editor.setTextInBufferRange [pos, pos],
-                indent + symbol + " :: " + type + "\n"
-            else if not scope? #neither keyword nor infix
+              symbol = "(#{symbol})" if scope is 'keyword.operator.haskell'
+              birdTrack = ''
+              if 'meta.embedded.haskell' in editor.scopeDescriptorForBufferPosition(pos).getScopesArray()
+                birdTrack = indent.slice 0, 2
+                indent = indent.slice(2)
+              if indent.match(/\S/)?
+                indent = indent.replace /\S/g, ' '
+              editor.setTextInBufferRange [o.range.start, o.range.start],
+                "#{symbol} :: #{type}\n#{birdTrack}#{indent}"
+            else if not scope? #neither operator nor infix
               editor.setTextInBufferRange o.range,
                 "(#{editor.getTextInBufferRange(o.range)} :: #{type})"
       'haskell-ghc-mod:insert-import': ({target, detail}) =>


make path reported by sicstus compatible with merged change

--- lib/linter-provider.coffee
+++ lib/linter-provider.coffee
@@ -30,7 +30,6 @@
       message = lines[1].substring(2)
       file = lines[lines.length-2]
       file = file.substring(file.indexOf("'")+1, file.length-1)
-      file = file.replace(cwd, "")
       line = lines[2].substring(9)
       return [file, line, 0, "Error", message]


Subscribe to Conflict in navigation-view.

--- lib/navigation-view.coffee
+++ lib/navigation-view.coffee
@@ -1,7 +1,9 @@
+{CompositeDisposable} = require 'atom'
 {CoveringView} = require './covering-view'

 module.exports =
 class NavigationView extends CoveringView
+
   @content: (navigator, editorView) ->
     @div class: 'controls navigation', =>
       @text ' '
@@ -11,13 +13,16 @@

   initialize: (@navigator, editorView) ->
     super editorView
+    @subs = new CompositeDisposable

     @prependKeystroke 'merge-conflicts:previous-unresolved', @prevBtn
     @prependKeystroke 'merge-conflicts:next-unresolved', @nextBtn

-    @navigator.conflict.on 'conflict:resolved', =>
+    @subs.add @navigator.conflict.onDidResolveConflict =>
       @deleteMarker @cover()
       @hide()
+
+  detached: -> @subs.dispose()

   cover: -> @navigator.separatorMarker


Add buttons for stack navigation.

Add buttons for stack navigation.

--- lib/navigation-view.coffee
+++ lib/navigation-view.coffee
@@ -19,6 +19,13 @@
         @span class: 'inline-block index', outlet: 'frameIndex'
         @span class: 'inline-block divider', '/'
         @span class: 'inline-block total', outlet: 'frameTotal'
+      @div class: 'pull-right controls', =>
+        @button class: 'inline-block btn', click: 'navigateToCaller', =>
+          @span class: 'icon icon-arrow-up'
+          @text 'Caller'
+        @button class: 'inline-block btn', click: 'navigateToCalled', =>
+          @span class: 'icon icon-arrow-down'
+          @text 'Follow Call'

   initialize: ->
     @subscribe Stacktrace, 'active-changed', (e) =>
@@ -36,8 +43,9 @@
           # Allow the already-set @frame a chance to see if it still applies.
           # This lets the caller and called navigation work properly, even if multiple frames are
           # on the same line.
-          unless @frame? and @frame.isOn(pos)
-
+          if @frame? and @frame.isOn(pos)
+            @useFrame(@frame)
+          else
             # Otherwise, scan the trace for a matching frame.
             frame = @trace.atEditorPosition(pos)
             if frame? then @useFrame(frame) else @unfocusFrame()
@@ -86,11 +94,17 @@
   navigateToCaller: ->
     return unless @trace? and @frame?

-    @trace.callerOf(@frame)?.navigateTo()
+    f = @trace.callerOf(@frame)
+    if f?
+      @frame = f
+      @frame.navigateTo()

   navigateToCalled: ->
     return unless @trace? and @frame?

-    @trace.calledFrom(@frame)?.navigateTo()
+    f = @trace.calledFrom(@frame)
+    if f?
+      @frame = f
+      @frame.navigateTo()

 module.exports = NavigationView: NavigationView


Stop unhandled rejection tracking

Stop unhandled rejection tracking

--- lib/package-manager.coffee
+++ lib/package-manager.coffee
@@ -1,6 +1,8 @@
 {BufferedNodeProcess} = require 'atom'
 {Emitter} = require 'emissary'
 Q = require 'q'
+
+Q.stopUnhandledRejectionTracking()

 module.exports =
 class PackageManager


add "interrupt julia" button to toolbar

add "interrupt julia" button to toolbar

--- lib/package/toolbar.coffee
+++ lib/package/toolbar.coffee
@@ -66,6 +66,12 @@
       iconset: 'ion'

     @bar.addButton
+      icon: 'pause'
+      callback: 'julia-client:interrupt-julia'
+      tooltip: 'Interrupt Julia'
+      iconset: 'ion'
+
+    @bar.addButton
       icon: 'stop'
       callback: 'julia-client:kill-julia'
       tooltip: 'Stop Julia'


add innerWidth

add innerWidth

--- lib/super-duplicate.coffee
+++ lib/super-duplicate.coffee
@@ -7,6 +7,7 @@
 		"W":["H","D"]
 		"width":["height","depth"]
 		"WIDTH":["HEIGHT","DEPTH"]
+		"innerWidth":["innerHeight"]
 		"scaleX":["scaleY","scaleZ","scaleW"]
 		"radiusX":["radiusY","radiusZ","radiusW"]
 		"r":["g","b","a"]


add mark to frame name when cloning

add mark to frame name when cloning

--- public/javascripts/app/src/controllers.coffee
+++ public/javascripts/app/src/controllers.coffee
@@ -109,7 +109,7 @@

   $scope.cloneFrame = ->
     cloneFrame =
-      name: $scope.frame.name
+      name: $scope.frame.name + '*'
       projects: []
     for project in $scope.frame.projects
       cloneProject =


Remove superluous function parameter.

Remove superluous function parameter.

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -86,9 +86,9 @@
 #
 # mocked_method
 #
-_build_mocked_method = (object, method_name) ->
+_build_mocked_method = (method_name) ->
   (args...) ->
-    expectation = _find_expectation(object, method_name, args...)
+    expectation = _find_expectation(@, method_name, args...)
     _throw_unknown_expectation("#{method_name}(#{args})") unless expectation?
     _check_for_duplicate_expectations()
     expectation.called = true
@@ -201,10 +201,10 @@
 _install_mock_method = (expectation, object, method_name) ->
   if typeof object == 'function'
     expectation._original_method = object.prototype[ method_name ]
-    object.prototype[ method_name ] = _build_mocked_method(object, method_name)
+    object.prototype[ method_name ] = _build_mocked_method(method_name)
   else
     expectation._original_method = object[ method_name ]
-    object[ method_name ] = _build_mocked_method(object, method_name)
+    object[ method_name ] = _build_mocked_method(method_name)

 _throw_args_usage = ->
   throw "you need to supply at least one argument to args(), e.g. my_mock.expects('my_method').args(42)"


fixed endpoints

fixed endpoints

--- src/api/statsd.coffee
+++ src/api/statsd.coffee
@@ -46,8 +46,11 @@
     for (i = 0; i < status_array.length; i++) {
       path = render_url + ".statuses." + status_array[i] + ".count,'1week'))&from=-1days&format=json";
       results[status_array[i]] = yield exports.fetchData(path)
-
-      final[status_array[i]] = 'data' in results[status_array[i]] ? results[status_array[i]].data[0][0] : 0;
+      if (results[status_array[i]]) {
+        final[status_array[i]] = 'data' in results[status_array[i]] ? results[status_array[i]].data[0][0] : 0;
+      } else {
+        final[status_array[i]] = 0 ;
+      }
     }

     data.push({


:lipstick:

:lipstick:

--- src/app/parser.coffee
+++ src/app/parser.coffee
@@ -89,17 +89,12 @@
   @forPattern: (pattern) ->
     endPattern =
       popStateStack: true
-      match: pattern.endSource
+      match: pattern.end
       captures: pattern.endCaptures
     new ParserState(scopeName: pattern.name, patterns: [endPattern])

   constructor: ({@scopeName, @patterns}) ->
     for pattern in @patterns
-      if pattern.match
-        pattern.matchSource = pattern.match
-        pattern.match = new OnigRegExp(pattern.match)
-      else if pattern.begin
-        pattern.beginSource = pattern.begin
-        pattern.begin = new OnigRegExp(pattern.begin)
-        pattern.endSource = pattern.end
-        pattern.end = new OnigRegExp(pattern.end)+      pattern.match = new OnigRegExp(pattern.match) if typeof pattern.match is 'string'
+      pattern.begin = new OnigRegExp(pattern.begin) if typeof pattern.begin is 'string'
+      pattern.end = new OnigRegExp(pattern.end) if typeof pattern.end is 'string'


comment review (cont x2)

comment review (cont x2)

--- src/arguegraph.coffee
+++ src/arguegraph.coffee
@@ -52,7 +52,7 @@
     result.push el if el in B
   result

-# returns an array whose elements are in either array A or B
+# returns an array whose elements are from either array A or B
 union = (A, B) ->
   result = A
   for el in B
@@ -60,7 +60,7 @@
   result

 # An ArgumentFramework wraps a map of defeats* (called the defeatermap) that
-# defines the argument network and provides functions for interrogating that
+# defines a network of arguments and provides functions for interrogating that
 # network. Errors are thrown for inconsistent/malformed networks and queries.
 # * The term "defeats" is widely used in the supporting literature, but it may
 # not be the best word to use, as it suggests a resolved struggle.  Alternative


to_html relations support

to_html relations support

--- src/base_model.coffee
+++ src/base_model.coffee
@@ -270,6 +270,14 @@
       tag   = obj["tag"] || "div"
       attr  = for k, v of obj when k isnt "tag" then "#{k} = '#{v}'"
       attr = if attr.length == 0 then "" else " #{attr.join(' ')}"
+
+      value = if @has_many().indexOf(key) > -1
+        for v in value then v.to_html()
+      else if @has_one().indexOf(key) > -1
+        value.to_html()
+      else
+        value
+
       "<#{tag}#{attr}>#{value}</#{tag}>"

     result.join("")


Silly js to coffee oversight

Silly js to coffee oversight

--- src/collection.coffee
+++ src/collection.coffee
@@ -49,7 +49,8 @@
 		return @items

 	upsert: (element, key, value) ->
-		if this.where("(@" + key + " ==  '" + value + "')").length > 0
+		check = @where("(@" + key + " ==  '" + value + "')")
+		if check.length > 0
 			this.update check[0].cid, element
 		else
 			this.insert element


Resize canvases properly

Resize canvases properly

--- src/controller.coffee
+++ src/controller.coffee
@@ -908,10 +908,10 @@
     @dragCanvas.width = 0
     @dragCanvas.height = 0

-    @highlightCanvas.width = @dropletElement.offsetWidth
+    @highlightCanvas.width = @dropletElement.offsetWidth - @gutterElement.offsetWidth
     @highlightCanvas.style.width = "#{@highlightCanvas.width}px"

-    @highlightCanvas.height = @dropletElement.offsetHeight
+    @highlightCanvas.height = @dropletElement.offsetHeight - @gutterElement.offsetWidth
     @highlightCanvas.style.height = "#{@highlightCanvas.height}px"

     @highlightCanvas.style.left = "#{@mainCanvas.offsetLeft}px"
@@ -2161,10 +2161,10 @@
   # Deal with resize for the lasso
   # select canvas
   Editor::resizeLassoCanvas = ->
-    @lassoSelectCanvas.width = @dropletElement.offsetWidth
+    @lassoSelectCanvas.width = @dropletElement.offsetWidth - @gutterElement.offsetWidth
     @lassoSelectCanvas.style.width = "#{@lassoSelectCanvas.width}px"

-    @lassoSelectCanvas.height = @dropletElement.offsetHeight
+    @lassoSelectCanvas.height = @dropletElement.offsetHeight - @gutterElement.offsetWidth
     @lassoSelectCanvas.style.height = "#{@lassoSelectCanvas.height}px"

     @lassoSelectCanvas.style.left = "#{@mainCanvas.offsetLeft}px"
@@ -3810,10 +3810,10 @@
     @dropletElement.appendChild @cursorCanvas

   Editor::resizeCursorCanvas = ->
-    @cursorCanvas.width = @dropletElement.offsetWidth
+    @cursorCanvas.width = @dropletElement.offsetWidth - @gutterElement.offsetWidth
     @cursorCanvas.style.width = "#{@cursorCanvas.width}px"

-    @cursorCanvas.height = @dropletElement.offsetHeight
+    @cursorCanvas.height = @dropletElement.offsetHeight - @gutterElement.offsetWidth
     @cursorCanvas.style.height = "#{@cursorCanvas.height}px"

     @cursorCanvas.style.left = "#{@mainCanvas.offsetLeft}px"


Bug fix for class hierarchy of cids

Bug fix for class hierarchy of cids

--- src/core/store.coffee
+++ src/core/store.coffee
@@ -129,7 +129,9 @@
   # @nodoc
   creatorId: (creator) ->
     create = creator.create or creator
-    create_id = create.__kb_id or= _.uniqueId('kb')
+    create.__kb_cids or= []
+    create.__kb_cids.push(match = {creator: creator, cid: _.uniqueId('kb')}) unless match = _.find(create.__kb_cids, (test) -> test.creator is creator)
+    return match.cid

   # @nodoc
   creator: (obj, options) ->


Add test for bad projects/:id/time_entries

where :id doesn't exist

--- test/routes/time_entries.coffee
+++ test/routes/time_entries.coffee
@@ -125,3 +125,9 @@
         else
           _.each b, (t)-> (new TimeEntry t).validate().should.be.true
           done()
+
+    it 'should have an appropriate error with a bad project id', (done)->
+      request.get (base "/projects/not-an-id/time_entries"), _.clone(options), (e,r,b) ->
+        r.statusCode.should.be.equal 404
+        b.error.should.not.be.equal null
+        done()


tableverse/avatar: Initial rewrite in terms of KineticThingyDelegate.

--- Oghma/tableverse/avatar.coffee
+++ Oghma/tableverse/avatar.coffee
@@ -15,203 +15,83 @@
 Oghma = @Oghma ?= {}
 Oghma.Thingy ?= {}

-# Layer for avatar.
-c_layer       = 'avatars'
-
-# Local data to tell set to not redraw.
-c_no_redraw = 'no_redraw'
+c_layer = 'avatars'

 Oghma.Thingy.Tableverse.register( ( thingyverse, O ) ->
-  thingyverse.avatar = new Heron.Index.MapIndex(
-    'owner',
-    'name',
-    'category',
-    'group'
-  )
+  thingyverse.avatar = new Heron.Index.MapIndex( 'owner', 'name' )

-  draw_layer = ->
-    O.layer[ c_layer ].draw()
+  class AvatarDelegate extends Oghma.KineticThingyDelegate
+    draw: ->
+      if ! @__k?
+        @__k =
+          a: new Kinetic.Wedge({})
+          b: new Kinetic.Wedge({})
+          label: new Kinetic.Text({})
+        @group().add( @__k.a )
+        @group().add( @__k.b )
+        @group().add( @__k.label )

-  show_labels = ->
-    thingyverse.avatar.each( ( avatar ) ->
-      avatar.show_label()
-    )
-  hide_labels = ->
-    thingyverse.avatar.each( ( avatar ) ->
-      avatar.hide_label()
-    )
+      attrs = @thingy().get()
+      @__k.a.setAttrs(
+        x: 0
+        y: 0
+        fill: 'blue'
+        angle: 180
+        radius: 25
+      )
+      @__k.b.setAttrs(
+        x: 0
+        y: 0
+        fill: 'red'
+        angle: 180
+        radius: 25
+        rotation: 180
+      )
+      @__k.label.setAttrs(
+        text:     attrs.name + ''
+        y:        25
+        fill:     'black'
+        stroke:   'black'
+        fontSize: 16
+      )

-  min_z = null
-  max_z = null
-  O.on( 'join_table', ->
-    # XXX Sort all avatars by z and then raise/lower appropriately.
+      # Center text
+      @__k.label.setOffset(
+        x: @__k.label.getWidth()  / 2
+      )

-    # XXX set min_z and max_z
-  )
-  # XXX on create/raise set z to max_z+1 and increment max_z.
-  # XXX on lower set z to min_z-1 and decrement min_z.
+    remove: ( thingy ) ->
+      thingyverse.avatar.remove( thingy )
+      super thingy

   thingyverse.define(
-    'avatar',
+     'avatar',
     [
-      'font_size',
-      'r',
-      'owner',
       'name',
-      'index',
-      'group',
-      'category',
-      'fill', 'stroke',
-      'token'
+      'color1', 'color2',
+      'owner'
     ],
     {
-      vis: ['visible_to' ]
-      loc: [ 'x', 'y' ]
+      loc:    [ 'x', 'y' ]
+      status: [ 'locked', 'visible_to', 'zindex' ]
     },
     ( attrs ) ->
-      @__ =
-        x:          attrs.x          ? 0
-        y:          attrs.y          ? 0
-        font_size:  attrs.font_size  ? 12
-        r:          attrs.r          ? O.current_table.g2k(1)
-        owner:      attrs.owner      ? O.me().gets( 'name' )
-        name:       attrs.name       ? ''
-        index:      attrs.index      ? ''
-        group:      attrs.group      ? 'undetermined'
-        category:   attrs.category   ? 'undetermined'
-        fill:       attrs.fill       ? O.me().gets( 'primary' )
-        stroke:     attrs.stroke     ? O.me().gets( 'secondary' )
-        token:      attrs.token      ? ''
-        visible_to: attrs.visible_to ? []
-        id:         attrs.id         ? Heron.Util.generate_id()
+      attrs.x          ?= 0
+      attrs.y          ?= 0
+      attrs.color1     ?= O.me().gets( 'primary' )
+      attrs.color2     ?= O.me().gets( 'secondary' )
+      attrs.owner      ?= O.me().gets( 'name' )
+      attrs.visible_to ?= []
+      attrs.name       ?= attrs.owner

       @after_construction( ->
         thingyverse.avatar.add( this )
       )

-      @is_owned = =>
-        O.me().gets('name') == @__.owner
-
-      @is_visible = =>
-        @__.visible_to.length == 0 ||
-        @__.visible_to.indexOf( O.me().gets( 'name' ) ) != -1 ||
-        O.isGM()
-
-      @show_label = =>
-        if @is_visible() && @__k?
-          tween = new Kinetic.Tween(
-            node:     @__klabel,
-            duration: 0.25,
-            opacity:  1
-          )
-          tween.play()
-      @hide_label = =>
-        if @is_visible() && @__k?
-          tween = new Kinetic.Tween(
-            node:     @__klabel,
-            duration: 0.25,
-            opacity:  0
-          )
-          tween.play()
-
-      @__redraw = =>
-        @__k.destroy() if @__k?
-        if @is_visible()
-          @__k = new Kinetic.Group(
-            x: @__.x
-            y: @__.y
-          )
-          @__kdisk = new Kinetic.Circle(
-            radius:    @__.r
-            fill:      @__.fill
-            stroke:    @__.stroke
-          )
-          @__klabel = new Kinetic.Text(
-            text:     @__.name + if @__.index? then ' ' + @__.index else ''
-            align:    'center'
-            y:        -1 * @__.r - @__.font_size
-            fill:     @__.stroke
-            stroke:   null
-            fontSize: @__.font_size
-            opacity:  0
-          )
-          @__klabel.setOffset( x: @__klabel.getWidth() / 2  )
-          @__k.add( @__kdisk )
-          @__k.add( @__klabel )
-
-          if @__.token != ''
-            image = new Image()
-            image.onload = =>
-              @__ktoken = new Kinetic.Image(
-                image:   image
-                offsetX: @__.r
-                offsetY: @__.r
-                width:   2 * @__.r
-                height:  2 * @__.r
-              )
-              @__k.add(@__ktoken)
-              draw_layer()
-            image.src = @__.token
-
-          @__kdisk.on( 'click', ( e ) =>
-            if e.which == 3 && ( @is_owned() || e.shiftKey )
-              items = [
-                {
-                  text: 'Remove'
-                  handler: => @remove()
-                }
-              ]
-              if O.isGM()
-                items.push('-')
-                items = items.concat( Oghma.SubMenu.visibility( O, this ) )
-              menu = Ext.create( 'Oghma.Ext.Menu', items: items )
-              e.stopPropagation()
-              menu.showAt( [ e.pageX, e.pageY ] )
-          )
-
-          @__k.on( 'mousedown', ( e ) =>
-            if @is_owned() || e.shiftKey
-              @__k.setDraggable(true)
-          )
-          @__k.on( 'dragend', ( e ) =>
-            @__k.setDraggable(false)
-            @set( @__k.getPosition(), c_no_redraw )
-          )
-
-          @__kdisk.on( 'mouseenter', show_labels )
-          @__kdisk.on( 'mouseleave', hide_labels )
-
-          O.layer[ c_layer ].add( @__k )
-
-      @__redraw()
-      draw_layer()
-
-      set: (thingy, attrs, local_data) ->
-        need_redraw = false
-        for k, v of attrs
-          if v != thingy.__[k]
-            thingy.__[k] = v
-            need_redraw = true
-        if need_redraw && local_data != c_no_redraw
-          thingy.__redraw()
-          draw_layer()
-
-        null
-
-      get: ( thingy, keys... ) ->
-        thingy.__
-
-      remove: ( thingy ) ->
-        thingyverse.avatar.remove( thingy )
-        thingy.__k.destroy()
-        draw_layer()
-        null
-    )
-
-  O.ui_colors.on_set( ->
-    O.tableverse.avatar.each( ( avatar ) ->
-      avatar.__redraw()
-      draw_layer()
-    )
+      new AvatarDelegate(
+        O, this, O.layer[ c_layer ], O.zindex[ c_layer ],
+        [ 'color1', 'color2', 'name' ],
+        attrs
+      )
   )
-)+)


Bug fix

Bug fix

--- Content/MAZE/src/game/game.coffee
+++ Content/MAZE/src/game/game.coffee
@@ -142,7 +142,7 @@

         # Move player
         player.state = PlayerState.TURN
-        playerMovedBrick(position)
+        @playerMovedBrick(position)

     playerMovedBrick: (position) ->


Fix TODO in interpolateString.

Fix TODO in interpolateString.

--- lexer.coffee
+++ lexer.coffee
@@ -178,7 +178,7 @@
       when '"'
         return 0 unless string = @balancedString @chunk, '"'
         if 0 < string.indexOf '#{', 1
-          @interpolateString string[1...-1], offsetInChunk: 1
+          @interpolateString string[1...-1], strOffset: 1, lexedLength: string.length
         else
           @token 'STRING', @escapeLines string, 0, string.length
       else
@@ -195,7 +195,7 @@
     quote = heredoc.charAt 0
     doc = @sanitizeHeredoc match[2], quote: quote, indent: null
     if quote is '"' and 0 <= doc.indexOf '#{'
-      @interpolateString doc, heredoc: yes, offsetInChunk: 3
+      @interpolateString doc, heredoc: yes, strOffset: 3, lexedLength: heredoc.length
     else
       @token 'STRING', @makeString(doc, quote, yes), 0, heredoc.length
     heredoc.length
@@ -246,7 +246,7 @@
     @token 'IDENTIFIER', 'RegExp', 0, 0
     @token 'CALL_START', '(', 0, 0
     tokens = []
-    for token in @interpolateString(body, regex: yes, offsetInChunk: 3)
+    for token in @interpolateString(body, regex: yes)
       [tag, value] = token
       if tag is 'TOKENS'
         tokens.push value...
@@ -491,21 +491,26 @@
   # If it encounters an interpolation, this method will recursively create a
   # new Lexer, tokenize the interpolated contents, and merge them into the
   # token stream.
+  #
+  #  - `str` is the start of the string contents (IE with the " or """ stripped
+  #    off.)
+  #  - `options.offsetInChunk` is the start of the interpolated string in the
+  #    current chunk, including the " or """, etc...  If not provided, this is
+  #    assumed to be 0.  `options.lexedLength` is the length of the
+  #    interpolated string, including both the start and end quotes.  Both of these
+  #    values are ignored if `options.regex` is true.
+  #  - `options.strOffset` is the offset of str, relative to the start of the
+  #    current chunk.
   interpolateString: (str, options = {}) ->
-    {heredoc, regex, offsetInChunk} = options
-
-    # TODO: we pass in offsetInChunk, but we've already discarded the " or the
-    # """, or the /// that got us here.  Those characters are not going to end
-    # up being part of any tokens.
-
-    originalOffsetInChunk = offsetInChunk
-    lexedLength = str.length
+    {heredoc, regex, offsetInChunk, strOffset, lexedLength} = options
+    offsetInChunk = offsetInChunk || 0
+    strOffset = strOffset || 0
+    lexedLength = lexedLength || str.length

     # Clip leading \n from heredoc
-    offsetInChunk = offsetInChunk || 0
     if heredoc and str.length > 0 and str[0] == '\n'
       str = str[1...]
-      offsetInChunk++
+      strOffset++

     # Parse the string.
     tokens = []
@@ -519,33 +524,33 @@
              (expr = @balancedString str[i + 1..], '}')
         continue
       # NEOSTRING is a fake token.  This will be converted to a string below.
-      tokens.push @makeToken('NEOSTRING', str[pi...i], offsetInChunk + pi) if pi < i
+      tokens.push @makeToken('NEOSTRING', str[pi...i], strOffset + pi) if pi < i
       inner = expr[1...-1]
       if inner.length
-        [line, column] = @getLineAndColumnFromChunk(offsetInChunk + i + 1)
+        [line, column] = @getLineAndColumnFromChunk(strOffset + i + 1)
         nested = new Lexer().tokenize inner, line: line, column: column, rewrite: off
         popped = nested.pop()
         popped = nested.shift() if nested[0]?[0] is 'TERMINATOR'
         if len = nested.length
           if len > 1
-            nested.unshift @makeToken '(', '(', offsetInChunk + i + 1, 0
-            nested.push    @makeToken ')', ')', offsetInChunk + i + 1 + inner.length, 0
+            nested.unshift @makeToken '(', '(', strOffset + i + 1, 0
+            nested.push    @makeToken ')', ')', strOffset + i + 1 + inner.length, 0
           # Push a fake 'TOKENS' token, which will get turned into real tokens below.
           tokens.push ['TOKENS', nested]
       i += expr.length
       pi = i + 1
-    tokens.push @makeToken('NEOSTRING', str[pi..], offsetInChunk + pi) if i > pi < str.length
+    tokens.push @makeToken('NEOSTRING', str[pi..], strOffset + pi) if i > pi < str.length

     # If regex, then return now and let the regex code deal with all these fake tokens
     return tokens if regex

     # If we didn't find any tokens, then just return an empty string.
-    return @token 'STRING', '""', originalOffsetInChunk, lexedLength unless tokens.length
+    return @token 'STRING', '""', offsetInChunk, lexedLength unless tokens.length

     # If the first token is not a string, add a fake empty string to the beginning.
-    tokens.unshift @makeToken('NEOSTRING', '', originalOffsetInChunk) unless tokens[0][0] is 'NEOSTRING'
-
-    @token '(', '(', originalOffsetInChunk, 0 if interpolated = tokens.length > 1
+    tokens.unshift @makeToken('NEOSTRING', '', offsetInChunk) unless tokens[0][0] is 'NEOSTRING'
+
+    @token '(', '(', offsetInChunk, 0 if interpolated = tokens.length > 1
     # Push all the tokens
     for token, i in tokens
       [tag, value] = token
@@ -569,7 +574,7 @@
         @tokens.push token
       else
         @error "Unexpected #{tag}"
-    @token ')', ')', originalOffsetInChunk + lexedLength, 0 if interpolated
+    @token ')', ')', offsetInChunk + lexedLength, 0 if interpolated
     tokens

   # Pairs up a closing token, ensuring that all listed pairs of tokens are


Use the explicit setup step

Use the explicit setup step

--- components/inquiry_questionnaire/views/specialist.coffee
+++ components/inquiry_questionnaire/views/specialist.coffee
@@ -13,11 +13,12 @@
   initialize: ->
     @feedback = new Feedback
     @representatives = new Representatives
+    super
+
+  setup: ->
     @representatives.fetch()
       .then => (@representative = @representatives.first()).fetch()
       .then => @render()
-
-    super

   serialize: (e) ->
     form = new Form model: @feedback, $form: @$('form')


Alternative replaceHTML implementation for Firefox. Fixes #4.

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -25,12 +25,27 @@
   event.initEvent 'page:change', true, true
   document.dispatchEvent event

+createDocument = do ->
+  createDocumentUsingParser = (html) ->
+    (new DOMParser).parseFromString html, "text/html"
+
+  createDocumentUsingWrite = (html) ->
+    doc = document.implementation.createHTMLDocument ""
+    doc.open "replace"
+    doc.write html
+    doc.close
+    doc
+
+  if window.DOMParser
+    testDoc = createDocumentUsingParser "<html><body><p>test"
+
+  if testDoc?.body?.childNodes.length is 1
+    createDocumentUsingParser
+  else
+    createDocumentUsingWrite
+
 replaceHTML = (html) ->
-  doc = document.implementation.createHTMLDocument ""
-  doc.open "replace"
-  doc.write html
-  doc.close()
-
+  doc = createDocument html
   originalBody = document.body
   document.documentElement.appendChild doc.body, originalBody
   document.documentElement.removeChild originalBody
@@ -39,7 +54,7 @@

 extractLink = (event) ->
   link = event.target
-  link = link.parentNode until link is document or link.nodeName is 'A'
+  link = link.parentNode until link is document or link.nodeName is 'A'
   link

 crossOriginLink = (link) ->
@@ -78,4 +93,4 @@
     handleClick event

 # Call Turbolinks.visit(url) from client code
-@Turbolinks = { visit: visit }+@Turbolinks = { visit: visit }


add destroy trigger

add destroy trigger

--- lib/client/javascripts/nali/model.js.coffee
+++ lib/client/javascripts/nali/model.js.coffee
@@ -112,6 +112,7 @@
       delete @table.index[ @id ]
       @table.splice @table.indexOf( @ ), 1
       @trigger 'destroy', @
+      @Model.trigger "destroy.#{ @_name.lower() }", @
       @onDestroy?()
       @unsubscribeAll()
     @


Correct issue with source creation when minified.

--- lib/assets/javascripts/jquery.soulmate.js.coffee
+++ lib/assets/javascripts/jquery.soulmate.js.coffee
@@ -153,9 +153,8 @@
   selectFocused: ->
     if @focusedIndex >= 0
       suggestion = @suggestions[@focusedIndex]
-      window.suggestion = suggestion
       callback =
-        if suggestion.constructor.name is 'CreateSuggestion'
+        if ~suggestion.id.indexOf('soulmate-create')
           @selectCreateCallback
         else
           @selectSuggestionCallback


omni dock panel tab switching is now reactive

--- lib/atom-sharper/atom-sharper-output-view.coffee
+++ lib/atom-sharper/atom-sharper-output-view.coffee
@@ -10,46 +10,57 @@

   # Internal: Initialize test-status output view DOM contents.
   @content: ->
+    btn = (view, text) =>
+      @button
+        'v-attr' : "class: selected | btn-selected #{view}",
+        'v-on' : "click: selectPane",
+        'pane' : view
+        text
+
     @div class: 'tool-panel panel-bottom atom-sharper-pane', outlet: 'pane', =>
       @div class: 'atom-sharper-output-resizer', outlet: 'resizeHandle'
+      #header
       @div class: "inset-panel", =>
         @div class: "panel-heading clearfix", =>
           @div class: 'btn-toolbar pull-left', =>
             @div class: 'btn-group btn-toggle', =>
-              @button class: 'btn btn-default btn-fix', dataTab:'errors-output', 'Errors'
-              @button class: 'btn btn-default btn-fix', dataTab:'build-output', 'Build output'
-              @button class: 'btn btn-default btn-fix', dataTab:'omni-sharp-output', 'Omnisharp output'
-        @div tabIndex: -1, class: 'atom-sharper-output omni-sharp-output padded', =>
+              btn "errors", "Errors"
+              btn "build", "Build output"
+              btn "omni", "Omnisharp output"
+        #tab content panels
+        @div 'v-attr' : 'class: selected | content-selected omni', =>
             @div class: 'message', outlet: 'sharpAtomOutput'
-        @div tabIndex: -1, class: 'atom-sharper-output errors-output', outlet: 'errorsOutput', =>
-        @div tabIndex: -1, class: 'atom-sharper-output build-output padded', =>
+        @div 'v-attr' : 'class: selected | content-selected errors', outlet: 'errorsOutput'
+        @div 'v-attr' : 'class: selected | content-selected build'
+
   # Internal: Initialize the test-status output view and event handlers.
   initialize: ->

+    Vue.filter 'btn-selected', (value, expectedValue) =>
+      selected = if value == expectedValue then "selected" else ""
+      "btn btn-default btn-fix #{selected}"
+
+    Vue.filter 'content-selected', (value, expectedValue) =>
+      selected = if value == expectedValue then "" else "hide"
+      "atom-sharper-output #{expectedValue}-output #{selected}"
+
     @errorsOutput.append(new AtomSharperErrorView())
     @vm = new Vue
+      el: this[0]
       data:
-        selected: "errors"
-      el: this[0]
+        selected: "omni"
+      methods:
+        selectPane: ({target}) => @selectPane $(target).attr "pane"

-    atom.workspaceView.command "atom-sharper:toggle-output", =>
-      @toggle()
+    atom.workspaceView.command "atom-sharper:toggle-output", => @toggle()

     atom.on("omni-sharp-server:out", (data) => @update data)
     atom.on("omni-sharp-server:err", (data) => @update data)
     atom.on "omni-sharp-server:start", @start

     @on 'mousedown', '.atom-sharper-output-resizer', (e) => @resizeStarted(e)
-    @on 'click', '.btn-group .btn', (e) => @selectPane(e)

-  selectPane: (e) =>
-    this.find(".btn-group .btn").removeClass("selected")
-    current = $(e.target)
-    current.addClass("selected")
-    targetOutput = current.attr("datatab");
-    this.find(".atom-sharper-output").hide();
-    this.find(".#{targetOutput}").show();
-
+  selectPane: (pane) => @vm.selected = pane

   resizeStarted: =>
     @fixedTop = @resizeHandle.offset().top


enhance: do not validate empty url

enhance: do not validate empty url

--- app/components/api-filter.coffee
+++ app/components/api-filter.coffee
@@ -1,9 +1,6 @@
 `import Ember from 'ember'`
 `import ENV from 'irene/config/environment';`
 `import { translationMacro as t } from 'ember-i18n'`
-
-hasApiFilter = (url)->
-  return !Ember.isEmpty url

 isRegexFailed = (url) ->
   reg = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/
@@ -41,8 +38,8 @@
       filterArray.forEach (filter) ->
         url = filter.value
         for url in [url]
-          return callback(that.get("notify").error tEmptyURL) if !hasApiFilter url
-          return callback(that.get("notify").error "#{url} #{tInvalidURL}") if !isRegexFailed url
+          if !Ember.isEmpty url
+            return callback(that.get("notify").error "#{url} #{tInvalidURL}") if !isRegexFailed url
         urls = that.get "urls"
         if Ember.isEmpty urls
           urls = url
@@ -53,6 +50,9 @@
       splittedArray = urls?.split ","
       uniqueArrays = splittedArray.uniq()
       urlString = uniqueArrays.join ','
+      if Ember.isEmpty urlString
+        return that.get("notify").error tEmptyURL
+      urlString = urlString.replace(/,\s*$/, "")
       apiScanOptions = [ENV.host,ENV.namespace, ENV.endpoints.apiScanOptions, project_id].join '/'
       data =
         apiUrlFilters: urlString


Do not try to set up RFB if its already setup

--- app/components/vnc-viewer.coffee
+++ app/components/vnc-viewer.coffee
@@ -22,7 +22,10 @@
       "Pop Out Modal"
   ).property "isPoppedOut"

-  didInsertElement: ->
+  setupRFB: ->
+    rfb = @get "rfb"
+    if !Ember.isEmpty rfb
+      return
     canvasEl = @element.getElementsByClassName("canvas")[0]
     that = @
     @set "rfb", new RFB
@@ -48,6 +51,12 @@

     if @get 'file.isReady'
       @send("connect")
+
+
+  didUpdate: ->
+    @setupRFB()
+  didInsertElement: ->
+    @setupRFB()

   statusChange: ( ->
     if @get 'file.isReady'


fix user_edit bug with pusher setup: The @item was not initialized if logged in and refreshing on edit page

--- app/controllers/user_edit.coffee
+++ app/controllers/user_edit.coffee
@@ -60,7 +60,7 @@
     @render()

   setupPusher: ->
-    return if @pusher
+    return if @pusher || !@item
     # Enable pusher logging - don't include this in production
     if Config.env!='production' && false
       Pusher.log = (message) ->


Add specs for new functionality

Add specs for new functionality

--- spec/whitespace-spec.coffee
+++ spec/whitespace-spec.coffee
@@ -362,17 +362,35 @@
       expect(editor.getSoftTabs()).toBe true

   describe "when the 'whitespace:convert-spaces-to-tabs' command is run", ->
-    it "removes all space characters and replaces them with hard tabs", ->
+    it "removes leading space characters and replaces them with hard tabs", ->
       editor.setTabLength(2)
-      buffer.setText("  a\n  \nb  \nc    d")
-      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
-      expect(buffer.getText()).toBe '\ta\n\t\nb\t\nc\t\td'
+      buffer.setText("   a\n  \nb  \nc    d")
+      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+      expect(buffer.getText()).toBe '\t a\n\t\nb  \nc    d'

       editor.setTabLength(3)
-      buffer.setText("   a\n   \nb   \nc      d"
-      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
-      expect(buffer.getText()).toBe '\ta\n\t\nb\t\nc\t\td')
+      buffer.setText("     a\n   \nb   \nc      d")
+      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+      expect(buffer.getText()).toBe '\t  a\n\t\nb   \nc      d'
+
+    it "replaces all space characters with hard tabs when convertLeadingSpacesOnly is disabled", ->
+      atom.config.set 'whitespace.convertLeadingSpacesOnly', false
+      editor.setTabLength(2)
+      buffer.setText("   a\n  \nb  \nc    d")
+      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+      expect(buffer.getText()).toBe '\t a\n\t\nb\t\nc\t\td'
+
+      editor.setTabLength(3)
+      buffer.setText("     a\n   \nb   \nc      d")
+      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+      expect(buffer.getText()).toBe '\t  a\n\t\nb\t\nc\t\td'

     it "changes the tab type to hard tabs", ->
       atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
       expect(editor.getSoftTabs()).toBe false
+
+    it "changes the tab length to user's tab-size", ->
+      editor.setTabLength(4)
+      buffer.setText("    ")
+      atom.commands.dispatch(workspaceElement, 'whitespace:convert-spaces-to-tabs')
+      expect(editor.getTabLength()).toBe 2


Rename .write() to writeSync()

Rename .write() to writeSync()

--- spec/whitespace-spec.coffee
+++ spec/whitespace-spec.coffee
@@ -6,7 +6,7 @@

   beforeEach ->
     path = "/tmp/atom-whitespace.txt"
-    fsUtils.write(path, "")
+    fsUtils.writeSync(path, "")
     window.rootView = new RootView
     rootView.open(path)


adding help and env

adding help and env

--- src/github-tfs.coffee
+++ src/github-tfs.coffee
@@ -28,6 +28,16 @@

 module.exports = (robot) ->
+  commandArray = [
+    'tfs build list <project>'
+    'tfs build list <project> from <collection>'
+    'tfs build queue <project> with def=<definition id>'
+    'tfs build queue <project> from <collection> with def=<definition id> branch=<branch name>'
+    'tfs build definitions <project>'
+    'tfs build definitions <project> from <collection>'
+  ]
+
+
   # Initialize environment variables
   tfsServer = process.env.HUBOT_TFS_SERVER
   tfsUsername = process.env.HUBOT_TFS_USERNAME
@@ -242,18 +252,53 @@
         tableResult = asciiTable.buildTable(tableDefinition, result)
         res.reply tableResult

-
-  ##########################################################
-  #                       COMMAND
-  # hubot tfs build list SpidersFromMars
-  # hubot tfs build list SpidersFromMars from MyCollection
+  ##########################################################
+  # HUBOT COMMAND
+  # List the command
+  # hubot tfs build help
+  ##########################################################
+  robot.respond /tfs build help/, (res) ->
+    response = "Here's what I can do with TFS : "
+    response += "\n" + command for command in commandArray
+    res.send response
+
+  ##########################################################
+  # HUBOT COMMAND
+  # Display some environment settings
+  # hubot tfs build env
+  ##########################################################
+  robot.respond /tfs build env/, (res) ->
+    if tfsPort?
+      tfsURL = "#{tfsProtocol}://#{tfsServer}:#{tfsPort}#{tfsURLPrefix}"
+    else
+      tfsURL = "#{tfsProtocol}://#{tfsServer}#{tfsURLPrefix}"
+
+    res.send "Here are my TFS settings : \nURL = #{tfsURL}\nDefault collection = #{tfsDefaultCollection}"
+
+  ##########################################################
+  # HUBOT COMMAND
+  # List the builds for a project
+  # hubot tfs build list <project>
+  # hubot tfs build list <project> from <collection>
   ##########################################################
   robot.respond /tfs build list (\S*)(?: from )?(\S*)/, (res) ->
     doRespondWithGet(res, tfsBuildListAPICall, buildListTableDefinition)

+  ##########################################################
+  # HUBOT COMMAND
+  # List the build definitions for a project
+  # hubot tfs build definitions <project>
+  # hubot tfs build definitions <project> from <collection>
+  ##########################################################
   robot.respond /tfs build definitions (\S*)(?: from )?(\S*)/, (res) ->
     doRespondWithGet(res, tfsBuildDefinitionsAPICall, buildDefinitionsTableDefinition)

+  ##########################################################
+  # HUBOT COMMAND
+  # Put a new build in the queue
+  # hubot tfs build queue <project> with def=<definition id>'
+  # hubot tfs build queue <project> from <collection> with def=<definition id> branch=<branch name>'
+  ##########################################################
   robot.respond /tfs build queue (\S*)(?: from )?(\S*) with def=(\S*)(?: branch=)?(\S*)/, (res) ->
     tfsDefinition = parseInt(res.match[3], 10)
     tfsBranch = res.match[4]
@@ -267,8 +312,6 @@
     unless tfsBranch.length is 0  #A branch was provided
       body.sourceBranch = tfsBranch

-    robot.logger.debug body
-
     doRespondWithPost(res, tfsBuildQueueAPICall, buildQueueTableDefinition, body)


Video player works

Video player works

--- Resources/webview_proxy.coffee
+++ Resources/webview_proxy.coffee
@@ -1,23 +1,23 @@
 class WebviewProxy
   constructor: ->
-    @wv = Ti.UI.createWebView(
+    @vp = Titanium.Media.createVideoPlayer(
+      movieControlMode:Titanium.Media.VIDEO_CONTROL_DEFAULT
+      fullscreen: true
       height: 1
-      width: 320
-      bottom: 0
-      left: 0
+      bottom:0
     )
-    @vp = Titanium.Media.createVideoPlayer()
     @vp.hide()
-    # @wv.addEventListener 'error', -> setTimeout((=> puts "did load"; @wv.url = "http://google.com"), 3000)
     @register_event_listener()

   view: ->
     @vp

   register_event_listener: (e) ->
+    @vp.addEventListener 'fullscreen', (e) =>
+      return if e.entering
+      @vp.stop()
+      @vp.hide()
     Ti.App.addEventListener 'view_movie', (e) =>
       @vp.url = e.url
       @vp.show()
       @vp.play()
-      # puts "Proxy opening #{e.url}"
-      # @wv.url = e.url


Remove not used usage of containment

Remove not used usage of containment

--- client/Framework/core/KDScrollView.coffee
+++ client/Framework/core/KDScrollView.coffee
@@ -127,7 +127,6 @@
     o = @getOptions()
     dragOptions =
       drag : @_drag
-      containment : "parent"
     if o.type = "vertical"
       dragOptions.axis = "y"
     else


Account: Destroy only own machines [fixes #88320408]

--- client/account/lib/deletemodalview.coffee
+++ client/account/lib/deletemodalview.coffee
@@ -1,6 +1,7 @@
 kd = require 'kd'
 KDModalViewWithForms = kd.ModalViewWithForms
 KDNotificationView = kd.NotificationView
+Machine = require 'app/providers/machine'
 remote = require('app/remote').getInstance()
 nick = require 'app/util/nick'
 mixpanel = require 'app/util/mixpanel'
@@ -113,7 +114,13 @@
       if err? or not machines? then callback()
       else

-        machines.forEach (machine)->
+        machines = machines.filter (machine) ->
+
+          container = new Machine {machine}
+          return container.isMine()
+
+        machines.forEach (machine) ->
+
           computeController.getKloud()
           .destroy { machineId: machine._id }
           .then  (res)->


Client: app: localsynccontroller: replace dash with async.parallel

--- client/app/lib/localsynccontroller.coffee
+++ client/app/lib/localsynccontroller.coffee
@@ -1,9 +1,9 @@
-kd = require 'kd'
+kd           = require 'kd'
+async        = require 'async'
 KDController = kd.Controller
-sinkrow = require 'sinkrow'
-remote = require('./remote').getInstance()
-showError = require './util/showError'
-FSHelper = require './util/fs/fshelper'
+remote       = require('./remote').getInstance()
+showError    = require './util/showError'
+FSHelper     = require './util/fs/fshelper'

 module.exports = class LocalSyncController extends KDController
@@ -28,12 +28,11 @@
       #   showError err if err

   syncLocalContentIfDiffExists: (callback)->
-    queue  = @filesToSave.map (key)=>
-      =>
-        fsfile = FSHelper.createFileInstance path: key
-        @patchFileIfDiffExist fsfile, @storage.getValue("OE-#{key}"), (res)->
-          queue.fin()
-    sinkrow.dash queue, callback
+    queue = @filesToSave.map (key) => (fin) =>
+      fsfile = FSHelper.createFileInstance path: key
+      @patchFileIfDiffExist fsfile, @storage.getValue("OE-#{key}"), (res)->
+        fin()
+    async.parallel queue, callback

   addToSaveArray: (file)->
     fileName = FSHelper.getFullPath file


remove notification after open application, refs #396

--- client/app/views/notification_view.coffee
+++ client/app/views/notification_view.coffee
@@ -58,6 +58,7 @@
             url += action.url or ''
             url = url.replace '//', '/'
             $('.right-menu').hide()
+            @model.destroy()

         else
             url = null


Allow route alteration

Allow route alteration

--- client/modules/packages/core/index.coffee
+++ client/modules/packages/core/index.coffee
@@ -4,24 +4,30 @@
 	($injector, $routeProvider, $locationProvider, pkgmanProvider) ->

 # Set up routes.
-		pkgmanProvider.invoke 'route', (path, route) ->
+		routes = {}
+		pkgmanProvider.invoke 'route', (path, route) -> routes[path] = route
+		pkgmanProvider.invoke 'routeAlter', (_, fn) -> fn routes
+
+		for path, route of routes

-			routeController = route.controller
-			route.controller = [
-				'$injector', '$scope', 'ui/title'
-				($injector, $scope, title) ->
-
-					title.setPage route.title ? ''
-
-					$injector.invoke(
-						routeController, null
-						$scope: $scope
-					)
-			]
+			do (path, route) ->

-			route.template ?= ' '
-
-			$routeProvider.when "/#{route.path ? path}", route
+				routeController = route.controller
+				route.controller = [
+					'$injector', '$scope', 'ui/title'
+					($injector, $scope, title) ->
+
+						title.setPage route.title ? ''
+
+						$injector.invoke(
+							routeController, null
+							$scope: $scope
+						)
+				]
+
+				route.template ?= ' '
+
+				$routeProvider.when "/#{route.path ? path}", route

 # Create a unique entry point.
 		$routeProvider.when '/shrub-entry-point', {}


Use new atom.package.getPackageDirPaths API

--- lib/package-generator-view.coffee
+++ lib/package-generator-view.coffee
@@ -23,7 +23,8 @@
     @previouslyFocusedElement = $(':focus')
     @message.text("Enter #{mode} path")
     placeholderName = "#{mode}-name"
-    @miniEditor.setText(path.join(_.last(config.userPackageDirPaths), placeholderName))
+    packagesDirectory = _.last(atom.packages.getPackageDirPaths())
+    @miniEditor.setText(path.join(packagesDirectory, placeholderName))
     pathLength = @miniEditor.getText().length
     @miniEditor.setSelectedBufferRange([[0, pathLength - placeholderName.length], [0, pathLength]])


Add iPad to mobile devices

Add iPad to mobile devices

--- framer/Utils.coffee
+++ framer/Utils.coffee
@@ -220,7 +220,7 @@
 	window.ontouchstart is null

 Utils.isMobile = ->
-	(/iphone|ipod|android|ie|blackberry|fennec/).test \
+	(/iphone|ipod|ipad|android|ie|blackberry|fennec/).test \
 		navigator.userAgent.toLowerCase()

 Utils.isChrome = ->


Do not use client time. Fixes #47

Do not use client time. Fixes #47

--- src/matteruser.coffee
+++ src/matteruser.coffee
@@ -170,7 +170,7 @@
         postData.root_id = envelope.message.id
         postData.parent_id = postData.root_id

-        postData.create_at = Date.now()
+        postData.create_at = 0
         postData.user_id = @self.id
         postData.filename = []
         # Check if the target room is also a user's username


rename side(s) -> edge(s)

rename side(s) -> edge(s)

--- src/mkts-table.coffee
+++ src/mkts-table.coffee
@@ -57,7 +57,7 @@
     fieldcells:           {} ### field extents in terms of cells, by field designations ###
     cellfields:           {} ### which cells belong to what fields, by cellkeys ###
     cell_dimensions:      {}
-    fieldborders:         {} ### field borders, as TikZ styles by sides ###
+    fieldborders:         {} ### field borders, as TikZ styles by edges ###
     field_dimensions:     {} ### field extents in terms of (unitwidth,unitheight), by field designations ###
     border_dimensions:    {} ### border extents in terms of (unitwidth,unitheight), by field designations ###
     pod_dimensions:       {} ### pod extents in terms of (unitwidth,unitheight), by field designations ###
@@ -164,8 +164,8 @@
 @fieldborder = ( me, text ) ->
   d = @_parse_fieldborder me, text
   for field in d.fields
-    for side in d.sides
-      ( me.fieldborders[ field ]?= {} )[ side ] = d.style
+    for edge in d.edges
+      ( me.fieldborders[ field ]?= {} )[ edge ] = d.style
   #.........................................................................................................
   return null

@@ -263,10 +263,10 @@
     throw new Error "(MKTS/TABLE µ1225) expected a text for fieldborder, got a #{rpr type}"
   unless ( groups = fieldborder.match /^(.+):(.+):(.*)$/ )?
     throw new Error "(MKTS/TABLE µ2582) expected a fieldborder like 'a1:left:sDashed,sThick', got #{rpr fieldborder}"
-  [ _, fieldhints, sides, style, ] = groups
-  #.........................................................................................................
-  sides = ( _.trim() for _ in sides.split ',' )
-  sides = [ 'top', 'left', 'bottom', 'right', ] if '*' in sides
+  [ _, fieldhints, edges, style, ] = groups
+  #.........................................................................................................
+  edges = ( _.trim() for _ in edges.split ',' )
+  edges = [ 'top', 'left', 'bottom', 'right', ] if '*' in edges
   #.........................................................................................................
   ### TAINT code duplication ###
   ### TAINT this will have to be changed to allow for named fields ###
@@ -281,15 +281,15 @@
     express that meaning FTTB. ###
     if fieldhints.has 'table'
       fieldhints.delete 'table'
-      for side in sides
-        fieldhints.add d.cellkey for d from @_walk_table_edge_cells me, side
+      for edge in edges
+        fieldhints.add d.cellkey for d from IG.GRID.walk_edge_cellrefs me.grid, edge
     cellkeys    = ( fieldhint for fieldhint from fieldhints )
     fields      = @_fieldnames_from_cellkeys me, cellkeys
   #.........................................................................................................
   style = style.trim()
   style = null if style in [ 'none', '', ]
   #.........................................................................................................
-  return { fields, sides, style, }
+  return { fields, edges, style, }

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


store facebook info

store facebook info

--- model.coffee
+++ model.coffee
@@ -43,8 +43,8 @@
 #   _id: (String) Player ID
 #   facebookId: (String) Player's Facebook ID
 #   fullName: (String) Player's full name
-#   firstName: (String) Player's first name
-#   gender: (String) Player's gender
+#   givenName: (String) Player's given name
+#   gender: (String) Player's gender, either "male" or "female"
 #   anonymousHash: (String) SHA3 hash of user's anonymous identifier
 # }
 #
@@ -210,8 +210,11 @@
     facebookAuthenticate: (facebookId, accessToken) ->
       # Only need to validate facebook token on the server
       result = Meteor.http.get "https://graph.facebook.com/me",
-          params: {fields: "id", access_token: accessToken}
-      responseUserId = JSON.parse(result.content)["id"]
+          params:
+            fields: "id,name,first_name,gender"
+            access_token: accessToken
+      response = JSON.parse(result.content)
+      responseUserId = response["id"]
       unless facebookId and responseUserId and responseUserId == facebookId
         die("Invalid access token!")

@@ -220,6 +223,9 @@
         # TODO(dthurn): Store other useful fields from facebook response here
         userId = noughts.Players.insert
           facebookId: responseUserId
+          givenName: response["first_name"]
+          fullName: response["name"]
+          gender: response["gender"]
       this.setUserId(userId)
       return userId


Revert "Remove unused var"

Revert "Remove unused var"

This reverts commit 8a2301a11cae61fe6068e995af978a5dbfa520f1.

--- app/scripts/views/box.coffee
+++ app/scripts/views/box.coffee
@@ -93,6 +93,8 @@
     distance = Math.sqrt(delta.x ** 2 + delta.y ** 2)
     dampenedDistance = 250 * (1 - Math.E ** (-0.002 * distance))

+    angle = Math.atan2 delta.y, delta.x
+
     if @grabDistance > 10
       centerDelta =
         x: e.clientX - @boxStartPos.x


Groups: while importing data old ones are deleted if they already exist

--- workers/productimport/main.coffee
+++ workers/productimport/main.coffee
@@ -20,54 +20,72 @@

 importProducts = (callback) ->
   data = require(__dirname + '/products');
-
   queue = []
   insertProducts = race (i, product, fin) ->
+    {JPaymentProduct} = worker.models
+    kreate = ->
+      JPaymentProduct.create "koding", product, (err) ->
+        console.log "#{product.title} product added successfully" unless err
+        fin()
+
     {title} = product
-    {JPaymentProduct} = worker.models
     JPaymentProduct.one title: title, (err, paymentProduct) ->
-      return console.error err if err
+      if err
+        console.error err
+        return fin()
+
       if paymentProduct?
-        console.log "#{product.title} product is already added"
-        fin()
+        paymentProduct.remove (err) ->
+          if err
+            console.error "#{product.title} cannot be added"
+            fin()
+          else
+            kreate()
       else
-        JPaymentProduct.create "koding", product, (err) ->
-          console.log "#{product.title} product added successfully" unless err
-          fin()
+        kreate()
   , -> callback null

   insertProducts product for product in data

 importPacks = (callback) ->
   data = require(__dirname + '/packs');
-
   queue = []
   fetchAllProducts (err, productPlanCodes) ->
     return console.error err if err
     insertPacks = race (i, pack, fin) ->
       {title} = pack
       {JPaymentPack, JPaymentProduct} = worker.models
+
+      kreate = ->
+        JPaymentPack.create "koding", pack, (err, pack) ->
+          if err
+            console.error err
+            return fin()
+
+          console.log "#{pack.title} pack added successfully"
+
+          quantities = {}
+          quantities[productPlanCodes[pack.title]] = 1
+          pack.updateProducts quantities, (err) ->
+            return console.error err if err
+            console.log "#{pack.title} pack products are added"
+            fin()
+
       JPaymentPack.one title: title, (err, paymentPack) ->
-        return console.error err if err
-        if paymentPack?
-          console.log "#{pack.title} pack is already added"
+        if err
+          console.error err
           fin()
+
+        if paymentPack
+          paymentPack.remove (err) ->
+            if err
+              console.error err
+              console.error "#{pack.title} cannot be added"
+              fin()
+            else
+              kreate()
         else
-          JPaymentPack.create "koding", pack, (err, pack) ->
-            return console.error err if err
-            console.log "#{pack.title} pack added successfully"
-
-            quantities = {}
-            if pack.title is "VM"
-              quantities[productPlanCodes["CPU"]] = 1
-              quantities[productPlanCodes["RAM"]] = 1
-              quantities[productPlanCodes["VM"]] = 1
-            else
-              quantities[productPlanCodes[pack.title]] = 1
-            pack.updateProducts quantities, (err) ->
-              return console.error err if err
-              console.log "#{pack.title} pack products are added"
-              fin()
+          kreate()

     , -> callback null

@@ -89,40 +107,54 @@

   fetchAllProducts (err, productPlanCodes) ->
     return console.error err if err
+
     queue = []
     insertPlans = race (i, plan, fin) ->
+      kreate = ->
+        JPaymentPlan.create "koding", plan, (err, newPlan) ->
+          if err
+            console.error err
+            return fin()
+
+          console.log "#{plan.title} plan added successfully"
+          quantities = {}
+          if plan.title is "Team Plan"
+            quantities[productPlanCodes["CPU"]] = 4
+            quantities[productPlanCodes["RAM"]] = 2
+            quantities[productPlanCodes["Disk"]] = 50
+            quantities[productPlanCodes["Always On"]] = 1
+            quantities[productPlanCodes["Max VM"]] = 10
+            quantities[productPlanCodes["User"]] = 1
+            quantities[productPlanCodes["Group"]] = 1
+          else
+            {count} = plan
+            quantities[productPlanCodes["CPU"]] = count * 4
+            quantities[productPlanCodes["RAM"]] = count * 2
+            quantities[productPlanCodes["Disk"]] = count * 50
+            quantities[productPlanCodes["Always On"]] = count
+            quantities[productPlanCodes["Max VM"]] = count * 10
+
+          console.log 'quantities', quantities
+          newPlan.updateProducts quantities, (err) ->
+            if err then console.error err
+            else console.log "#{plan.title} plan products are added"
+            fin()
+
       {title} = plan
       JPaymentPlan.one title: title, (err, paymentPlan) ->
-        return console.error err if err
+        if err
+          console.error err
+          return fin()
+
         if paymentPlan?
-          console.log "#{plan.title} plan is already added"
-          fin()
+          paymentPlan.remove (err) ->
+            if err
+              console.error "#{plan.title} cannot be added"
+              fin()
+            else
+              kreate()
         else
-          JPaymentPlan.create "koding", plan, (err, newPlan) ->
-            return console.error err if err
-            console.log "#{plan.title} plan added successfully"
-            quantities = {}
-            if plan.title is "Custom Plan"
-              quantities[productPlanCodes["CPU"]] = 1
-              quantities[productPlanCodes["RAM"]] = 1
-              quantities[productPlanCodes["Disk"]] = 1
-              quantities[productPlanCodes["Always On"]] = 1
-              quantities[productPlanCodes["VM"]] = 5
-              quantities[productPlanCodes["User"]] = 1
-              quantities[productPlanCodes["Group"]] = 1
-            else
-              {count} = plan
-              quantities[productPlanCodes["CPU"]] = count
-              quantities[productPlanCodes["RAM"]] = count
-              quantities[productPlanCodes["Disk"]] = count
-              quantities[productPlanCodes["Always On"]] = count
-              quantities[productPlanCodes["VM"]] = count * 5
-
-            console.log 'quantities', quantities
-            newPlan.updateProducts quantities, (err) ->
-              return console.error err if err
-              console.log "#{plan.title} plan products are added"
-              fin()
+          kreate()
     , -> callback null

     insertPlans plan for plan in data
@@ -137,10 +169,10 @@
     lastName  : " "

   JUser.createUser userInfo, (err) ->
-    return console.log err if err
+    return callback err if err
     JUser.one username : "bot", (err, user) ->
       user.confirmEmail (err) ->
-        return console.error err if err
+        return callback err if err
         JAccount.update "profile.nickname" : "bot", {$set: type: "registered"}, \
           {multi: no}, (err, account) ->
             return callback err if err
@@ -160,14 +192,14 @@
       -> importPacks ->
         console.log 'All Packs are added'
         queue.next()
-      -> createBot ->
+      -> createBot (err) ->
+        console.error err  if err
         queue.next()
       -> process.exit(1)
     ]

     daisy queue

-
 initProducts()


rewritten validateGroup function

rewritten validateGroup function

--- servers/lib/server/handlers/createteam.coffee
+++ servers/lib/server/handlers/createteam.coffee
@@ -125,8 +125,9 @@
     client.sessionToken        = result.newToken
     client.connection.delegate = result.account

-    if (validationResult = validateGroupData body, res) isnt yes
-      return res.status(400).send(validationResult)
+    if validationError = validateGroupDataAndReturnError body
+      { statusCode, errorMessage } = validationError
+      return res.status(statusCode).send errorMessage

     JGroup.create client,
       slug            : slug
@@ -167,15 +168,15 @@
         res.redirect 301, redirect

-validateGroupData = (body, res) ->
+validateGroupDataAndReturnError = (body) ->

   if not body.slug
-    return 'Group slug can not be empty.'
+    return { statusCode : 400, errorMessage : 'Group slug can not be empty.' }

   else if not body.companyName
-    return 'Company name can not be empty.'
-
-  else true
+    return { statusCode : 400, errorMessage : 'Company name can not be empty.' }
+
+  else null

 # convertToArray converts given comma separated string value into cleaned,
 # trimmed, lowercased, unified array of string


updates route to /terminal

updates route to /terminal

--- apps/exhibition/index.coffee
+++ apps/exhibition/index.coffee
@@ -9,4 +9,4 @@
 app = module.exports = express()
 app.set "views", __dirname + "/templates"
 app.set "view engine", "jade"
-app.get "/exhibition/index", routes.index
+app.get "/terminal/index", routes.index


Use location and protocol from setup to set allowed origin

--- src/script/app.coffee
+++ src/script/app.coffee
@@ -4,6 +4,7 @@
 window.giftCardsProviders = ko.observableArray()
 setup = (location, route) ->
   window.paymentData = new PaymentDataViewModel({route: route, location: location});
+  window.allowedOrigin = location.protocol + '//' + location.host
   ko.components.register('payment-data', {
     viewModel: {instance: window.paymentData},
     template: paymentDataTemplate
@@ -14,6 +15,8 @@
 Listens to events by the parent window
 ###
 $(window).on "message onmessage", (e) ->
+  if window.allowedOrigin? and e.originalEvent?.origin isnt window.allowedOrigin
+    return console.log('Received message from different origin', e.originalEvent?.origin)
   console.log 'Payment data received message', e.originalEvent?.data
   event = e.originalEvent.data.event
   args = e.originalEvent.data.arguments
@@ -40,18 +43,17 @@
 ###
 Converts events sent by the component to messages to the parent window.
 ###
-origin = '*'
 $(window).on "sendAttachment.vtex", (e, attachmentName, attachmentData) ->
-  parent.postMessage({"event": "sendAttachment.vtex", "arguments": [attachmentName, attachmentData]}, origin)
+  parent.postMessage({"event": "sendAttachment.vtex", "arguments": [attachmentName, attachmentData]}, window.allowedOrigin)

 $(window).on "componentValidated.vtex", (e, validationResults) ->
-  parent.postMessage({"event": "componentValidated.vtex", "arguments": [validationResults]}, origin)
+  parent.postMessage({"event": "componentValidated.vtex", "arguments": [validationResults]}, window.allowedOrigin)

 $(window).on "startTransaction.vtex", (e, value, referenceValue, payments) ->
-  parent.postMessage({"event": "startTransaction.vtex", "arguments": [value, referenceValue, payments]}, origin)
+  parent.postMessage({"event": "startTransaction.vtex", "arguments": [value, referenceValue, payments]}, window.allowedOrigin)

 $(window).on "removeAccount.vtex", (e, accountId) ->
-  parent.postMessage({"event": "removeAccount.vtex", "arguments": [accountId]}, origin)
+  parent.postMessage({"event": "removeAccount.vtex", "arguments": [accountId]}, window.allowedOrigin)

 $(window).on "authenticateUser.vtexid", (e, options) ->
-  parent.postMessage({"event": "authenticateUser.vtexid", "arguments": [options]}, origin)
+  parent.postMessage({"event": "authenticateUser.vtexid", "arguments": [options]}, window.allowedOrigin)


fix use of conditional expression in coffeescript demo

--- notes/node/chat/lib.coffee
+++ notes/node/chat/lib.coffee
@@ -8,11 +8,7 @@
 form = $('#first form')

 print = (m, p) ->
-    if p == undefined
-        p = ""
-    else
-        p = JSON.stringify(p)
-    div.append $("<code>").text("#{m} #{p}")
+    div.append $("<code>").text("#{m} #{if p? then JSON.stringify(p) else ''}")
     div.append $("<br>")
     div.scrollTop (div.scrollTop() + 10000)


reworking Stan's nodes.coffee type/children work a bit for issue 386

--- nodes.coffee
+++ nodes.coffee
@@ -28,17 +28,6 @@
 # being requested by the surrounding function), information about the current
 # scope, and indentation level.
 exports.BaseNode: class BaseNode
-
-  # If `is_statement` is passed, marks the node as a JavaScript *statement*,
-  # or as a *pure_statement* if `is_pure_statement`. Statements must be
-  # wrapped in a closure when used as an expression, and nodes tagged as
-  # *pure_statement* cannot be closure-wrapped without losing their meaning.
-  constructor: (o) ->
-    o: or {}
-    @constructor_name:        o.name     if o.name
-    @children_attributes:     o.children if o.children
-    (@is_statement:        -> true)      if o.is_statement
-    (@is_pure_statement:   -> true)      if o.is_pure_statement

   # Common logic for determining whether to wrap this node in a closure before
   # compiling it, or to compile directly. We need to wrap if this node is a
@@ -118,18 +107,18 @@
   # This is what `coffee --nodes` prints out.
   toString: (idt) ->
     idt: or ''
-    '\n' + idt + @constructor_name + (child.toString(idt + TAB) for child in @children()).join('')
-
-  children: ->
+    '\n' + idt + @type + (child.toString(idt + TAB) for child in @collect_children()).join('')
+
+  each_child: (func) ->
+    return unless @children
+    for attr in @children when this[attr]
+      for child in flatten [this[attr]]
+        return if func(child) is false
+
+  collect_children: ->
     nodes: []
     @each_child (node) -> nodes.push node
     nodes
-
-  each_child: (func) ->
-    return unless @children_attributes
-    for attr in @children_attributes when this[attr]
-      for child in flatten [this[attr]]
-        return if func(child) is false

   traverse_children: (cross_scope, func) ->
     @each_child (child) ->
@@ -138,13 +127,13 @@

   # Default implementations of the common node properties and methods. Nodes
   # will override these with custom logic, if needed.
-  constructor_name:        'BaseNode'
-  children_attributes:     []
-
-  unwrap:               -> this
-  is_statement:         -> false
-  is_pure_statement:    -> false
-  top_sensitive:        -> false
+  type:     'BaseNode'
+  children: []
+
+  unwrap:            -> this
+  is_statement:      -> no
+  is_pure_statement: -> no
+  top_sensitive:     -> no

 #### Expressions

@@ -153,8 +142,11 @@
 # `if`, `switch`, or `try`, and so on...
 exports.Expressions: class Expressions extends BaseNode

+  type:         'Expressions'
+  children:     ['expressions']
+  is_statement: -> yes
+
   constructor: (nodes) ->
-    super {name: 'Expressions', is_statement: yes, children: ['expressions']}
     @expressions: compact flatten nodes or []

   # Tack an expression on to the end of this expression list.
@@ -232,8 +224,9 @@
 # `true`, `false`, `null`...
 exports.LiteralNode: class LiteralNode extends BaseNode

+  type: 'LiteralNode'
+
   constructor: (value) ->
-    super {name: 'LiteralNode'}
     @value: value

   # Break and continue must be treated as pure statements -- they lose their
@@ -256,8 +249,12 @@
 # make sense.
 exports.ReturnNode: class ReturnNode extends BaseNode

+  type:               'ReturnNode'
+  is_statement:       -> yes
+  is_pure_statement:  -> yes
+  children:           ['expression']
+
   constructor: (expression) ->
-    super {name: 'ReturnNode', is_statement: yes, is_pure_statement: yes, children: ['expression']}
     @expression: expression

   top_sensitive: ->
@@ -276,11 +273,13 @@
 # or vanilla.
 exports.ValueNode: class ValueNode extends BaseNode

-  SOAK: " == undefined ? undefined : "
+  SOAK:     " == undefined ? undefined : "
+
+  type:     'ValueNode'
+  children: ['base', 'properties']

   # A **ValueNode** has a base and a list of property accesses.
   constructor: (base, properties) ->
-    super {name: 'ValueNode', children: ['base', 'properties']}
     @base: base
     @properties: (properties or [])

@@ -357,16 +356,18 @@
 # same position.
 exports.CommentNode: class CommentNode extends BaseNode

-  constructor: (lines, type) ->
-    super {name: 'CommentNode', is_statement: yes}
+  type: 'CommentNode'
+  is_statement: -> yes
+
+  constructor: (lines, kind) ->
     @lines: lines
-    @type: type
+    @kind: kind

   make_return: ->
     this

   compile_node: (o) ->
-    if @type is 'herecomment'
+    if @kind is 'herecomment'
       sep: '\n' + @tab
       "$@tab/*$sep${ @lines.join(sep) }\n$@tab*/"
     else
@@ -378,8 +379,10 @@
 # calls against the prototype's function of the same name.
 exports.CallNode: class CallNode extends BaseNode

+  type:     'CallNode'
+  children: ['variable', 'args']
+
   constructor: (variable, args) ->
-    super {name: 'CallNode', children: ['variable', 'args']}
     @is_new:   false
     @is_super: variable is 'super'
     @variable: if @is_super then null else variable
@@ -437,8 +440,10 @@
 # Underscore's `bind` functions.
 exports.CurryNode: class CurryNode extends CallNode

+  type:     'CurryNode'
+  children: ['meth', 'context', 'args']
+
   constructor: (meth, args) ->
-    super {name: 'CurryNode', children: ['meth', 'context', 'args']}
     @meth: meth
     @context: args[0]
     @args: (args.slice(1) or [])
@@ -461,8 +466,10 @@
 # [Closure Library](http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.html).
 exports.ExtendsNode: class ExtendsNode extends BaseNode

+  type:     'ExtendsNode'
+  children: ['child', 'parent']
+
   constructor: (child, parent) ->
-    super {name: 'ExtendsNode', children: ['child', 'parent']}
     @child: child
     @parent: parent

@@ -477,8 +484,10 @@
 # an accessor into the object's prototype.
 exports.AccessorNode: class AccessorNode extends BaseNode

+  type:     'AccessorNode'
+  children: ['name']
+
   constructor: (name, tag) ->
-    super {name: 'AccessorNode', children: ['name']}
     @name: name
     @prototype: tag is 'prototype'
     @soak_node: tag is 'soak'
@@ -493,8 +502,10 @@
 # A `[ ... ]` indexed accessor into an array or object.
 exports.IndexNode: class IndexNode extends BaseNode

+  type:     'IndexNode'
+  children: ['index']
+
   constructor: (index, tag) ->
-    super {name: 'IndexNode', children: ['index']}
     @index: index
     @soak_node: tag is 'soak'

@@ -510,8 +521,10 @@
 # corresponding array of integers at runtime.
 exports.RangeNode: class RangeNode extends BaseNode

+  type:     'RangeNode'
+  children: ['from', 'to']
+
   constructor: (from, to, exclusive) ->
-    super {name: 'RangeNode', children: ['from', 'to']}
     @from: from
     @to: to
     @exclusive: !!exclusive
@@ -553,8 +566,10 @@
 # is the index of the beginning.
 exports.SliceNode: class SliceNode extends BaseNode

+  type:     'SliceNode'
+  children: ['range']
+
   constructor: (range) ->
-    super {name: 'SliceNode', children: ['range']}
     @range: range

   compile_node: (o) ->
@@ -568,8 +583,10 @@
 # An object literal, nothing fancy.
 exports.ObjectNode: class ObjectNode extends BaseNode

+  type:     'ObjectNode'
+  children: ['properties']
+
   constructor: (props) ->
-    super {name: 'ObjectNode', children: ['properties']}
     @objects: @properties: props or []

   # All the mucking about with commas is to make sure that CommentNodes and
@@ -595,8 +612,10 @@
 # An array literal.
 exports.ArrayNode: class ArrayNode extends BaseNode

+  type:     'ArrayNode'
+  children: ['objects']
+
   constructor: (objects) ->
-    super {name: 'ArrayNode', children: ['objects']}
     @objects: objects or []
     @compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects

@@ -624,10 +643,13 @@
 # The CoffeeScript class definition.
 exports.ClassNode: class ClassNode extends BaseNode

+  type:         'ClassNode'
+  children:     ['variable', 'parent', 'properties']
+  is_statement: -> yes
+
   # Initialize a **ClassNode** with its name, an optional superclass, and a
   # list of prototype property assignments.
   constructor: (variable, parent, props) ->
-    super {name: 'ClassNode', is_statement: yes, children: ['variable', 'parent', 'properties']}
     @variable: variable
     @parent: parent
     @properties: props or []
@@ -686,8 +708,10 @@
   PROTO_ASSIGN: /^(\S+)\.prototype/
   LEADING_DOT:  /^\.(prototype\.)?/

+  type:     'AssignNode'
+  children: ['variable', 'value']
+
   constructor: (variable, value, context) ->
-    super {name: 'AssignNode', children: ['variable', 'value']}
     @variable: variable
     @value: value
     @context: context
@@ -783,8 +807,10 @@
 # has no *children* -- they're within the inner scope.
 exports.CodeNode: class CodeNode extends BaseNode

+  type:     'CodeNode'
+  children: ['params', 'body']
+
   constructor: (params, body, tag) ->
-    super {name: 'CodeNode', children: ['params', 'body']}
     @params:  params or []
     @body:    body or new Expressions()
     @bound:   tag is 'boundfunc'
@@ -837,7 +863,7 @@

   toString: (idt) ->
     idt: or ''
-    children: (child.toString(idt + TAB) for child in @children()).join('')
+    children: (child.toString(idt + TAB) for child in @collect_children()).join('')
     "\n$idt$children"

 #### SplatNode
@@ -846,8 +872,10 @@
 # or as part of a destructuring assignment.
 exports.SplatNode: class SplatNode extends BaseNode

+  type:     'SplatNode'
+  children: ['name']
+
   constructor: (name) ->
-    super {name: 'SplatNode', children: ['name']}
     name: literal(name) unless name.compile
     @name: name

@@ -902,8 +930,11 @@
 # flexibility or more speed than a comprehension can provide.
 exports.WhileNode: class WhileNode extends BaseNode

+  type:         'WhileNode'
+  children:     ['condition', 'guard', 'body']
+  is_statement: -> yes
+
   constructor: (condition, opts) ->
-    super {name: 'WhileNode', is_statement: yes, children: ['condition', 'guard', 'body']}
     if opts and opts.invert
       condition: new ParentheticalNode condition if condition instanceof OpNode
       condition: new OpNode('!', condition)
@@ -964,8 +995,10 @@
   # Operators must come before their operands with a space.
   PREFIX_OPERATORS: ['typeof', 'delete']

+  type:     'OpNode'
+  children: ['first', 'second']
+
   constructor: (operator, first, second, flip) ->
-    super {name: "OpNode $operator", children: ['first', 'second']}
     @first: first
     @second: second
     @operator: @CONVERSIONS[operator] or operator
@@ -1024,8 +1057,11 @@
 # A classic *try/catch/finally* block.
 exports.TryNode: class TryNode extends BaseNode

+  type:         'TryNode'
+  children:     ['attempt', 'recovery', 'ensure']
+  is_statement: -> yes
+
   constructor: (attempt, error, recovery, ensure) ->
-    super {name: 'TryNode', is_statement: true, children: ['attempt', 'recovery', 'ensure']}
     @attempt: attempt
     @recovery: recovery
     @ensure: ensure
@@ -1052,8 +1088,11 @@
 # Simple node to throw an exception.
 exports.ThrowNode: class ThrowNode extends BaseNode

+  type:         'ThrowNode'
+  children:     ['expression']
+  is_statement: -> yes
+
   constructor: (expression) ->
-    super {name: 'ThrowNode', is_statement: true, children: ['expression']}
     @expression: expression

   # A **ThrowNode** is already a return, of sorts...
@@ -1070,8 +1109,10 @@
 # table.
 exports.ExistenceNode: class ExistenceNode extends BaseNode

+  type:     'ExistenceNode'
+  children: ['expression']
+
   constructor: (expression) ->
-    super {name: 'ExistenceNode', children: ['expression']}
     @expression: expression

   compile_node: (o) ->
@@ -1096,8 +1137,10 @@
 # Parentheses are a good way to force any statement to become an expression.
 exports.ParentheticalNode: class ParentheticalNode extends BaseNode

+  type:     'ParentheticalNode'
+  children: ['expression']
+
   constructor: (expression) ->
-    super {name: 'ParentheticalNode', children: ['expression']}
     @expression: expression

   is_statement: ->
@@ -1124,8 +1167,11 @@
 # you can map and filter in a single pass.
 exports.ForNode: class ForNode extends BaseNode

+  type:         'ForNode'
+  children:     ['body', 'source', 'guard']
+  is_statement: -> yes
+
   constructor: (body, source, name, index) ->
-    super {name: 'ForNode', is_statement: yes, children: ['body', 'source', 'guard']}
     @body:    body
     @name:    name
     @index:   index or null
@@ -1205,8 +1251,10 @@
 # because ternaries are already proper expressions, and don't need conversion.
 exports.IfNode: class IfNode extends BaseNode

+  type:     'IfNode'
+  children: ['condition', 'switch_subject', 'body', 'else_body', 'assigner']
+
   constructor: (condition, body, tags) ->
-    super {name: 'IfNode', children: ['condition', 'switch_subject', 'body', 'else_body', 'assigner']}
     @condition: condition
     @body:      body
     @else_body: null


simplified splatting `new` compilation

simplified splatting `new` compilation

--- nodes.coffee
+++ nodes.coffee
@@ -534,20 +534,13 @@
         fun = ref = base.compile o
         fun += name.compile o if name
       return "#{fun}.apply(#{ref}, #{splatargs})"
-    call = 'call(this)'
-    argvar = (node) -> node instanceof Literal and node.value is 'arguments'
-    for arg in @args when arg.contains argvar
-      call = 'apply(this, arguments)'
-      break
-    ctor   = o.scope.freeVariable 'ctor'
-    ref    = o.scope.freeVariable 'ref'
-    result = o.scope.freeVariable 'result'
+    idt = @idt 1
     """
-    (function() {
-    #{idt = @idt 1}var ctor = function() {};
-    #{idt}#{utility 'extends'}(ctor, #{ctor} = #{ @variable.compile o });
-    #{idt}return typeof (#{result} = #{ctor}.apply(#{ref} = new ctor, #{splatargs})) === "object" ? #{result} : #{ref};
-    #{@tab}}).#{call}
+    (function(func, args, ctor) {
+    #{idt}ctor.prototype = func.prototype;
+    #{idt}var child = new ctor, result = func.apply(child, args);
+    #{idt}return typeof result === "object" ? result : child;
+    #{@tab}})(#{ @variable.compile o }, #{splatargs}, function() {})
     """

 #### Extends


Fixed highlighting of `\ `, `\-`, and `\/`

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -664,7 +664,7 @@
   texPrimitives: {
     comment: 'This took a long time to write </joke>. Really though, dont even bother trying to edit it. Just add more primitives to the list in ../lib/resources, and recompile it.'
     name: 'entity.name.function.primitive.latex'
-    match: '(\\\\)(\\s|\\-|\\/|a(bove(displays(hortskip|kip)|withdelims)?|ccent|d(jdemerits|vance)|fter(assignment|group)|top(withdelims)?)|b(a(dness|selineskip|tchmode)|e(gingroup|lowdisplays(hortskip|kip))|inoppenalty|o(tmark|x(maxdepth)?)|rokenpenalty)|c(atcode|har(def)?|l(eaders|ose(in|out)|ubpenalty)|o(py|unt(def)?)|r(cr)?|sname)|d(ay|e(adcycles|f(ault(hyphenchar|skewchar))?|l(code|imiter(factor|shortfall)?))|i(men(def)?|s(cretionary|play(indent|limits|style|wid(owpenalty|th)))|vide)|oublehyphendemerits|p|ump)|e(def|lse|mergencystretch|nd(csname|group|input|linechar)?|qno|rr(help|message|or(contextlines|stopmode))|scapechar|very(cr|display|hbox|job|math|par|vbox)|x(hyphenpenalty|pandafter))|f(am|i(nalhyphendemerits|rstmark)?|loatingpenalty|ont(dimen|name)?|uturelet)|g(def|lobal(defs)?)|h(a(lign|ng(after|indent))|b(adness|ox)|f(il(l|neg)?|uzz)|o(ffset|ldinginserts)|rule|s(ize|kip|s)|t|yphen(ation|char|penalty))|i(f(ca(se|t)|dim|eof|false|h(box|mode)|inner|mmode|num|odd|true|v(box|mode|oid)|x)?|gnorespaces|mmediate|n(dent|put(lineno)?|sert(penalties)?|terlinepenalty))|jobname|kern|l(a(nguage|st(box|kern|penalty|skip))|ccode|e(aders|ft(hyphenmin|skip)?|qno|t)|i(mits|ne(penalty|skip(limit)?))|o(ng|oseness|wer(case)?))|m(a(g|rk|th(accent|bin|c(h(ar(def)?|oice)|lose|ode)|inner|o(p(en)?|rd)|punct|rel|surround)|xde(adcycles|pth))|e(aning|dmuskip|ssage)|kern|o(nth|ve(left|right))|skip|u(ltiply|skip(def)?))|n(ewlinechar|o(align|boundary|expand|indent|limits|ns(cript|topmode))|u(ll(delimiterspace|font)|mber))|o(mit|pen(in|out)|r|ut(er|put(penalty)?)|ver(fullrule|line|withdelims)?)|p(a(ge(depth|fil(l(lstretch|stretch)|stretch)|goal|s(hrink|tretch)|total)|r(fillskip|indent|s(hape|kip))?|tterns|using)|enalty|ostdisplaypenalty|re(display(penalty|size)|tolerance|v(depth|graf)))|r(a(dical|ise)|e(ad|l(ax|penalty))|ight(hyphenmin|skip)?|omannumeral)|s(cr(ipt(font|s(cript(font|style)|pace|tyle))|ollmode)|et(box|language)|fcode|h(ipout|ow(box(breadth|depth)?|lists|the)?)|k(ewchar|ip(def)?)|p(a(ce(factor|skip)|n)|ecial|lit(botmark|firstmark|maxdepth|topskip))|tring)|t(abskip|ext(font|style)|h(e|i(ckmuskip|nmuskip))|ime|o(ks(def)?|lerance|p(mark|skip))|racing(commands|lostchars|macros|o(nline|utput)|pa(ges|ragraphs)|restores|stats))|u(c(code|hyph)|n(derline|h(box|copy)|kern|penalty|skip|v(box|copy))|ppercase)|v(a(djust|lign)|b(adness|ox)|center|f(il(l|neg)?|uzz)|offset|rule|s(ize|kip|plit|s)|top)|w(d|idowpenalty|rite)|x(def|leaders|spaceskip)|year)(?=[^a-zA-Z])'
+    match: '(\\\\)(((a(bove(displays(hortskip|kip)|withdelims)?|ccent|d(jdemerits|vance)|fter(assignment|group)|top(withdelims)?)|b(a(dness|selineskip|tchmode)|e(gingroup|lowdisplays(hortskip|kip))|inoppenalty|o(tmark|x(maxdepth)?)|rokenpenalty)|c(atcode|har(def)?|l(eaders|ose(in|out)|ubpenalty)|o(py|unt(def)?)|r(cr)?|sname)|d(ay|e(adcycles|f(ault(hyphenchar|skewchar))?|l(code|imiter(factor|shortfall)?))|i(men(def)?|s(cretionary|play(indent|limits|style|wid(owpenalty|th)))|vide)|oublehyphendemerits|p|ump)|e(def|lse|mergencystretch|nd(csname|group|input|linechar)?|qno|rr(help|message|or(contextlines|stopmode))|scapechar|very(cr|display|hbox|job|math|par|vbox)|x(hyphenpenalty|pandafter))|f(am|i(nalhyphendemerits|rstmark)?|loatingpenalty|ont(dimen|name)?|uturelet)|g(def|lobal(defs)?)|h(a(lign|ng(after|indent))|b(adness|ox)|f(il(l|neg)?|uzz)|o(ffset|ldinginserts)|rule|s(ize|kip|s)|t|yphen(ation|char|penalty))|i(f(ca(se|t)|dim|eof|false|h(box|mode)|inner|mmode|num|odd|true|v(box|mode|oid)|x)?|gnorespaces|mmediate|n(dent|put(lineno)?|sert(penalties)?|terlinepenalty))|jobname|kern|l(a(nguage|st(box|kern|penalty|skip))|ccode|e(aders|ft(hyphenmin|skip)?|qno|t)|i(mits|ne(penalty|skip(limit)?))|o(ng|oseness|wer(case)?))|m(a(g|rk|th(accent|bin|c(h(ar(def)?|oice)|lose|ode)|inner|o(p(en)?|rd)|punct|rel|surround)|xde(adcycles|pth))|e(aning|dmuskip|ssage)|kern|o(nth|ve(left|right))|skip|u(ltiply|skip(def)?))|n(ewlinechar|o(align|boundary|expand|indent|limits|ns(cript|topmode))|u(ll(delimiterspace|font)|mber))|o(mit|pen(in|out)|r|ut(er|put(penalty)?)|ver(fullrule|line|withdelims)?)|p(a(ge(depth|fil(l(lstretch|stretch)|stretch)|goal|s(hrink|tretch)|total)|r(fillskip|indent|s(hape|kip))?|tterns|using)|enalty|ostdisplaypenalty|re(display(penalty|size)|tolerance|v(depth|graf)))|r(a(dical|ise)|e(ad|l(ax|penalty))|ight(hyphenmin|skip)?|omannumeral)|s(cr(ipt(font|s(cript(font|style)|pace|tyle))|ollmode)|et(box|language)|fcode|h(ipout|ow(box(breadth|depth)?|lists|the)?)|k(ewchar|ip(def)?)|p(a(ce(factor|skip)|n)|ecial|lit(botmark|firstmark|maxdepth|topskip))|tring)|t(abskip|ext(font|style)|h(e|i(ckmuskip|nmuskip))|ime|o(ks(def)?|lerance|p(mark|skip))|racing(commands|lostchars|macros|o(nline|utput)|pa(ges|ragraphs)|restores|stats))|u(c(code|hyph)|n(derline|h(box|copy)|kern|penalty|skip|v(box|copy))|ppercase)|v(a(djust|lign)|b(adness|ox)|center|f(il(l|neg)?|uzz)|offset|rule|s(ize|kip|plit|s)|top)|w(d|idowpenalty|rite)|x(def|leaders|spaceskip)|year)(?=[^a-zA-Z]))|(\\s|\\-|\\/))'
   }
   pdfTexPrimitives: {
     comment: 'These dont apply on all engines, but I feel the names are specific enough and pdfLaTeX is used enough to justify it.'


pulled fixes from master.dnode = WIP

pulled fixes from master.dnode = WIP

--- node_modules_koding/koding-kite/kite.coffee
+++ node_modules_koding/koding-kite/kite.coffee
@@ -61,7 +61,6 @@

     @ws.on 'message', (data, flags)->
       # now we descrub message and call our callback function
-      data = data.replace(/withArgs/ig, 'withArgs')
       scrubbed = JSON.parse data
       scrubber = new Scrubber self.localStore
       unscrubbed = scrubber.unscrub scrubbed, (callbackId)->
@@ -159,7 +158,6 @@
     @wss.on 'connection', (client)->
       client.on 'message', (data)->
         console.log('received: %s', data)
-        data = data.replace(/withArgs/ig, 'withArgs') # <- TODO: we'll delete this after merging dnode branch
         scrubbed = JSON.parse data
         scrubber = new Scrubber self.localStore
         unscrubbed = scrubber.unscrub scrubbed, (callbackId)->


Updated propagation event handlers

Updated propagation event handlers

--- scripts/mixins/tree.coffee
+++ scripts/mixins/tree.coffee
@@ -41,8 +41,8 @@
         delete child._tree_root
         @trigger 'tree:remove', child, collection, options

-      @_tree_children.on 'change', (child, collection, options) =>
-        @trigger 'tree:change', child, collection, options
+      @_tree_children.on 'change', (child, options) =>
+        @trigger 'tree:change', child, @_tree_children, options

       trickleEvents = (name) =>
         @_tree_children.on name, (model, collection, options) =>
@@ -81,7 +81,7 @@
         children.remove(realModel)
         realModel._tree_parent = null

-      # Before adding the model make sure it's a Tree Node (does it have `._children`.
+      # Before adding the model make sure it's a Tree Node (does it have `._tree_children`.
       # If not, wrap it in a node
       if ! (model._tree_children)
         model = @_tree_root.newNode {model:model}


Update formatting of fs check message

Update formatting of fs check message

--- server-ce/Gruntfile.coffee
+++ server-ce/Gruntfile.coffee
@@ -324,10 +324,10 @@
 						Could not find directory "#{Settings.filestore.stores.user_files}".
 						Please check your configuration.
 						"""
+					callback()
 			else
 				grunt.log.writeln "Filestore other than FS configured. Not checking FS."
-			callback()
-
+				callback()

 		checkMake: (callback = (error) ->) ->
 			grunt.log.write "Checking make is installed... "


updated converter

updated converter

--- historyToCSV.coffee
+++ historyToCSV.coffee
@@ -1,17 +1,19 @@
 fs = require 'fs'
 path = require 'path'

-fileName = process.argv[2]
-outFile = path.join(path.dirname(fileName), path.basename(fileName, path.extname fileName) + '.csv')
-console.log "writing to " + outFile
+fileNames = process.argv[2...]
+for fileName in fileNames
+  do (fileName) ->
+    outFile = path.join(path.dirname(fileName), path.basename(fileName, path.extname fileName) + '.csv')
+    console.log "writing to " + outFile

-fs.unlink outFile, ->
-  fs.readFile fileName, (err, historyString) ->
-    history = JSON.parse historyString
+    fs.unlink outFile, ->
+      fs.readFile fileName, (err, historyString) ->
+        history = JSON.parse historyString

-    keys = Object.keys(history)
-    fs.appendFileSync outFile, keys.join('\t') + '\n'
+        keys = Object.keys(history)
+        fs.appendFileSync outFile, keys.join('\t') + '\n'

-    for i in [0...history[keys[0]].length]
-      rowValues = keys.map (key) -> history[key][i]
-      fs.appendFileSync outFile, rowValues.join('\t') + '\n'
+        for i in [0...history[keys[0]].length]
+          rowValues = keys.map (key) -> history[key][i]
+          fs.appendFileSync outFile, rowValues.join('\t') + '\n'


Add open menu under File

Add open menu under File

--- src/atom-application.coffee
+++ src/atom-application.coffee
@@ -107,6 +107,12 @@
         { label: 'Quit', accelerator: 'Command+Q', click: -> app.quit() }
       ]

+    fileMenu =
+      label: 'File'
+      submenu: [
+        { label: 'Open...', accelerator: 'Command+O', click: => @promptForPath() }
+      ]
+
     editMenu =
       label: 'Edit'
       submenu:[
@@ -135,14 +141,10 @@
         { label: 'Bring All to Front', selector: 'arrangeInFront:' }
       ]

-    @menu = Menu.buildFromTemplate [atomMenu, viewMenu, editMenu, windowMenu]
+    @menu = Menu.buildFromTemplate [atomMenu, fileMenu, editMenu, viewMenu, windowMenu]
     Menu.setApplicationMenu @menu

   handleEvents: ->
-    # Quit when all windows are closed.
-    app.on 'window-all-closed', ->
-      app.quit()
-
     # Clean the socket file when quit normally.
     app.on 'will-quit', =>
       fs.unlinkSync socketPath if fs.existsSync(socketPath)
@@ -164,8 +166,7 @@
       if pathsToOpen?.length > 0
         @openPaths(pathsToOpen)
       else
-        pathsToOpen = dialog.showOpenDialog title: 'Open', properties: ['openFile', 'openDirectory', 'multiSelections', 'createDirectory']
-        @openPaths(pathsToOpen)
+        @promptForPath()

     ipc.on 'new-window', =>
       @open()
@@ -229,3 +230,7 @@
       isSpec: true

     specWindow.show()
+
+  promptForPath: ->
+    pathsToOpen = dialog.showOpenDialog title: 'Open', properties: ['openFile', 'openDirectory', 'multiSelections', 'createDirectory']
+    @openPaths(pathsToOpen)


Use React editor in Atom

Use React editor in Atom

--- atom/config.cson
+++ atom/config.cson
@@ -11,6 +11,7 @@
   ]
   'disabledPackages': []
   'destroyEmptyPanes': false
+  'useReactEditor': true
 'editor':
   'fontSize': 13
   'hideGitIgnoredFiles': true


Theme

Theme

--- atom/config.cson
+++ atom/config.cson
@@ -23,7 +23,7 @@
     telemetryConsent: "limited"
     themes: [
       "atom-material-ui"
-      "base16-ocean-dark-spacegray"
+      "base16-syntax"
     ]
   editor:
     fontFamily: "Hack"


Revert "Re-enable "Auto Indent on Paste" in Atom"

This reverts commit d85e7ffdc444d9f6b27a0595243ac69df454fe86.

--- atom/config.cson
+++ atom/config.cson
@@ -94,6 +94,7 @@
     align_tags: "shallow"
     extend_double_slash: false
   editor:
+    autoIndentOnPaste: false
     fontFamily: "Monaco"
     fontSize: 16
     showCursorOnSelection: false


Add dash to other non-word character lists