Remove unneeded _.clone call

Remove unneeded _.clone call

This is no longer needed after upgrading underscore which
fixed a bug with object equality across objects created in
different contexts.

--- src/app/git.coffee
+++ src/app/git.coffee
@@ -107,7 +107,7 @@
     headCheckedOut

   getDiffStats: (path) ->
-    _.clone(@getRepo().getDiffStats(@relativize(path)))
+    @getRepo().getDiffStats(@relativize(path))

   isSubmodule: (path) ->
     @getRepo().isSubmodule(@relativize(path))


remixerView: cancel link change if field is empty

unless empty fields are permitted

--- coffee/src/views/remixer_view.coffee
+++ coffee/src/views/remixer_view.coffee
@@ -224,7 +224,12 @@
     if link is @model.link?()
       return

-    if link is '' and @options.allowEmptyLink
+    if link is ''
+      # cancel link change if no empty links
+      unless @options.allowEmptyLink
+        @$('input#link').val @model.link?()
+        return
+
       @model.link link
       @remixSubview.render()


able to limit hn results

able to limit hn results

--- zero_privacy_hacker_news/app/assets/javascripts/backbone/apps/main/show/show_view.js.coffee
+++ zero_privacy_hacker_news/app/assets/javascripts/backbone/apps/main/show/show_view.js.coffee
@@ -2,6 +2,9 @@

 App.module "MainApp.Show", (Show, App, Backbone, Marionette, $, _) ->
     TOP_STORIES_URL = "https://hacker-news.firebaseio.com/v0/topstories.json"
+    ITEM_URL = "https://hacker-news.firebaseio.com/v0/item"
+    NUM_SHOWN = 10
+
     Show.Controller =
         showMain: ->
             mainView = @getMainView()
@@ -14,29 +17,47 @@
             main = new Show.Main collection: posts

             main.collection.add new Show.PostModel 2
-            main.collection.fetch
+            main.collection.fetch()
             main

     console.log "This is mainapp.show"

     class Show.PostModel extends Backbone.Model
-            initialize: (id) -> @id id
+            url: () ->
+                    u = ITEM_URL + "/" + @id + ".json"
+                    console.log u
+                    u
+
+            initialize: (id) ->
+                    console.log id
+                    @id id
+                    @fetched = true
+                    @fetch()
+
+            fetched: false

             id: (id) -> @set id: id
+

     class Show.PostsModel extends Backbone.Collection
             url: TOP_STORIES_URL
             model: Show.PostModel
+            parse: (data) ->
+                    _.take(data, NUM_SHOWN)

     class Show.Post extends Marionette.ItemView
-            template: (model) -> "
 item #{model.id}
"
-
-
+            template: (model) ->
+                "
+

+                   #{model.title}
+

+

+                  #{model.by}
+

+                "

     class Show.Main extends Marionette.CollectionView
         childView: Show.Post
         collectionEvents:
                 "sync": "render"

-
-


components: GioFileLoadContent: make component asynchronous

--- components/GioFileLoadContent.coffee
+++ components/GioFileLoadContent.coffee
@@ -18,14 +18,20 @@
     in: 'uri'
     out: 'content'
     forwardGroups: true
-  , (data, groups, out) ->
+    async: true
+  , (data, groups, out, callback) ->
     return unless out.isAttached()
-    try
-      file = Gio.File.new_for_uri data
-      [status, content, etag] = file.load_contents null
-      out.send
-        data: content
-        length: content.length
-        toString = -> "[C Buffer - length=#{@length}]" # prevent warnings
-    catch e
-      c.error e, groups
+    file = Gio.File.new_for_uri data
+    file.load_contents_async null, (src, res) ->
+      try
+        [status, content, etag] = file.load_contents_finish res
+        out.send
+          data: content
+          length: content.length
+          toString = -> "[C Buffer - length=#{@length}]" # prevent warnings
+        do callback
+      catch e
+        c.error e, groups
+        do callback
+
+  c


Removed form group class from text input as no one else had it

--- components/default-components.coffee
+++ components/default-components.coffee
@@ -338,7 +338,7 @@
             """
         viewerTemplate:
             """
-

+

                 {{label}}

                     {{inputText}}


Disabled calling setY method for modals when position.top is passed as config option.

--- components/modals/KDModalView.coffee
+++ components/modals/KDModalView.coffee
@@ -36,7 +36,7 @@

     KDView.appendToDOMBody @

-    @setModalWidth options.width
+    @setModalWidth  options.width
     @setModalHeight options.height                if options.height

     if options.buttons
@@ -149,7 +149,7 @@
     @setPositions()
     {winHeight} = @getSingleton('windowController')
     @$('.kdmodal-content').css 'max-height', winHeight - 200
-    @setY (winHeight - @getHeight())/2
+    @setY (winHeight - @getHeight()) / 2 unless @getOptions().position.top

   putOverlay:->
     @$overlay = $ "<div/>",


TabView: fixed persisting tabpane scrolltops on tab change

--- components/tabs/KDTabPaneView.coffee
+++ components/tabs/KDTabPaneView.coffee
@@ -11,9 +11,10 @@

     @name = options.name
     @lastScrollTops =
-      window : 0
-      parent : 0
-      self   : 0
+      window        : 0
+      parent        : 0
+      self          : 0
+      body          : 0

     @on "KDTabPaneActive",        @bound "setMainView"
@@ -31,16 +32,21 @@
     @active = yes
     @emit "KDTabPaneActive"
     KD.utils.defer =>
-      document.documentElement.scrollTop = @lastScrollTops.window
-      @getElement().scrollTop            = @lastScrollTops.self
-      @parent?.getElement().scrollTop    = @lastScrollTops.parent
+      {body, documentElement}         = document
+      documentElement.scrollTop       = @lastScrollTops.window
+      body.scrollTop                  = @lastScrollTops.body
+      @getElement().scrollTop         = @lastScrollTops.self
+      @parent?.getElement().scrollTop = @lastScrollTops.parent

   hide:->

     return  unless @active

-    @lastScrollTops.window = document.documentElement.scrollTop
+    {body, documentElement} = document
+
+    @lastScrollTops.window = documentElement.scrollTop
+    @lastScrollTops.body   = body.scrollTop
     @lastScrollTops.parent = @parent.getElement().scrollTop
     @lastScrollTops.self   = @getElement().scrollTop


Use smaller mapping table. Extract match logic.

--- src/coffee/stockxmlimport.coffee
+++ src/coffee/stockxmlimport.coffee
@@ -46,18 +46,19 @@

 exports.StockXmlImport.prototype.createOrUpdate = (stocks, callback) ->
   @rest.GET "/inventory?limit=0", (error, response, body) =>
-    if response.statusCode is not 200
+    if error
+      @returnResult false, 'Problem on getting existing stock information.', callback
+      return
+    if response.statusCode != 200
       @returnResult false, 'Can not fetch stock information.', callback
       return
     existingStocks = JSON.parse(body).results
-    sku2entry = {}
-    for es in existingStocks
-      sku2entry[es.sku] = es
+    sku2index = @match(existingStocks)
     posts = []
     bar = new ProgressBar 'Updating stock [:bar] :percent done', { width: 50, total: stocks.length }
     for s in stocks
-      if sku2entry[s.sku]
-        posts.push @update(s, sku2entry[s.sku], bar)
+      if sku2index[s.sku] >= 0
+        posts.push @update(s, existingStocks[sku2index[s.sku]], bar)
       else
         posts.push @create(s, bar)
     Q.all(posts).then (v) =>
@@ -68,6 +69,12 @@
       @returnResult true, v, callback
     .fail (v) =>
       @returnResult false, v, callback
+
+exports.StockXmlImport.prototype.match = (existingStocks) ->
+  sku2index = {}
+  for es, i in existingStocks
+    sku2index[es.sku] = i
+  sku2index

 exports.StockXmlImport.prototype.update = (s, es, bar) ->
   deferred = Q.defer()


Effects: Change SSAOEffect constructor to accept a single options object.

Add samples option.

--- engine/effects/SSAO.coffee
+++ engine/effects/SSAO.coffee
@@ -8,9 +8,8 @@
 NOISE_SIZE = 32

 class SSAOFilter extends BaseFilter
-    constructor: (context, @radius, @zrange, @strength) ->
+    constructor: (context, @radius, @zrange, @strength, @samples) ->
         super context, 'ssao'
-        @samples = 32
         @disk_texture_uniform = {varname: 'disk_texture', value: null}
         @noise_texture_uniform = {varname: 'noise_texture', value: null}
         @make_textures()
@@ -149,9 +148,16 @@

 class SSAOEffect extends FilterEffect
-    constructor: (context, @radius=2.5, @zrange=2, @strength=1) ->
+    constructor: (context, options={}) ->
         super context
-        @filter = new SSAOFilter(@context, @radius, @zrange, @strength)
+        {
+            @radius=2.5
+            @zrange=2
+            @strength=1
+            @samples=32
+        } = options
+        @filter = new SSAOFilter(@context,
+            @radius, @zrange, @strength, @samples)
         @blur = new SSAOBlur @context

     set_radius: (@radius) ->


Closes #63. Twitter specific class added to the markable elements

--- extension/packages/marker.coffee
+++ extension/packages/marker.coffee
@@ -16,6 +16,7 @@
   "@role='link'"
   "@role='button'"
   "contains(@class, 'button')"
+  "contains(@class, 'js-new-tweets-bar')"
   "@contenteditable='' or translate(@contenteditable, 'TRUE', 'true')='true'"
 ]


Export TextEditor

Export TextEditor

--- exports/atom.coffee
+++ exports/atom.coffee
@@ -6,6 +6,7 @@
   BufferedNodeProcess: require '../src/buffered-node-process'
   BufferedProcess: require '../src/buffered-process'
   GitRepository: require '../src/git-repository'
+  TextEditor: require '../src/text-editor'
   Point: Point
   Range: Range
   Emitter: Emitter


:art: Better wording on specs

:art: Better wording on specs

--- spec/atom-environment-spec.coffee
+++ spec/atom-environment-spec.coffee
@@ -179,19 +179,21 @@
         atom.loadState().then (state) ->
           expect(state).toEqual({stuff: 'cool'})

-    it "saves state on keydown and mousedown events when the editor window hasn't been unloaded", ->
+    it "saves state on keydown, mousedown, and when the editor window unloads", ->
       spyOn(atom, 'saveState')

       keydown = new KeyboardEvent('keydown')
       atom.document.dispatchEvent(keydown)
       advanceClock atom.saveStateDebounceInterval
       expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false})
+      expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: true})

       atom.saveState.reset()
       mousedown = new MouseEvent('mousedown')
       atom.document.dispatchEvent(mousedown)
       advanceClock atom.saveStateDebounceInterval
       expect(atom.saveState).toHaveBeenCalledWith({isUnloading: false})
+      expect(atom.saveState).not.toHaveBeenCalledWith({isUnloading: true})

       atom.saveState.reset()
       atom.unloadEditorWindow()


🔥unnecessary debug logging

🔥unnecessary debug logging

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -482,7 +482,6 @@

       runs ->
         spyOn(atom, 'showSaveDialogSync').andReturn(outputPath)
-        console.log(outputPath)
         atom.commands.dispatch workspaceElement, 'markdown-preview:save-as-html'

       waitsFor ->


actually set the project you're watching...

--- scripts/jira-linkifier.coffee
+++ scripts/jira-linkifier.coffee
@@ -18,6 +18,7 @@
   robot.respond /watch jira project ?(.+)?/i, (msg) ->
     projects = robot.brain.get('jira-projects') or []
     projects.push msg.match[1]
+    robot.brain.set 'jira-projects', projects

     msg.send "Watching that project for you"


reduced max size for base64

reduced max size for base64

--- gulp/tasks/styles/styles_build.coffee
+++ gulp/tasks/styles/styles_build.coffee
@@ -16,7 +16,7 @@
         ))
         .pipe($.base64(
             extensions: ['png', 'svg', 'jpg']
-            maxImageSize: 1024 * 30 # 30 kb
+            maxImageSize: 1024 * 10 # 10 kb
         ))
         .pipe($.cssUrlAdjuster(
             replace: ['../../app/frontend/img/', '../img/']


Remove unused options "tree"

Remove unused options "tree"

--- src/code/app.coffee
+++ src/code/app.coffee
@@ -20,7 +20,6 @@
     simplified: getParameterByName 'simplified'

   opts.codapConnect = CodapConnect.instance 'building-models'
-  opts.tree = (require './stores/image-dialog-store').tree
   appView = AppView opts
   elem = '#app'


use period id from sorted periods as initial period_id as opposed to accidentally trying to use it as actual scores data

--- src/components/scores/index.cjsx
+++ src/components/scores/index.cjsx
@@ -28,7 +28,9 @@
   mixins: [ResizeListenerMixin]

   getInitialState: ->
-    period_id: null
+    sortedPeriods = CourseStore.getPeriods(@props.courseId)
+
+    period_id: _.first(sortedPeriods).id
     periodIndex: 1
     sortIndex: 0
     tableWidth: 0
@@ -92,13 +94,12 @@
   getStudentRowData: ->
     # The period may not have been selected. If not, just use the 1st period
     {sort, period_id, firstDataColumn, displayAs} = @state
-    sortedPeriods = CourseStore.getPeriods(@props.courseId)

     data = ScoresStore.get(@props.courseId)
     scores = if period_id
       _.findWhere(data, {period_id})
     else
-      sortedPeriods[0].id
+      _.first(data)

     sortData = _.sortBy(scores.students, (d) =>
       if _.isNumber(sort.key)


Style.

Style.

--- example/client/base.coffee
+++ example/client/base.coffee
@@ -102,7 +102,7 @@
       translateY: [0]
     ,
       duration: 1000
-      complete: ->
+      complete: (complete) =>
         $node.css(
           # After it finishes, we remove display and z-index.
           position: ''


[fix] Returning 304 not modified when no If-None-Match header

--- index.coffee
+++ index.coffee
@@ -159,7 +159,7 @@
     res.set("Content-Type": if req.accepts(file.mime) then file.mime else "text/plain")
     res.set("ETag", file.etag)

-    if req.get("if-none-match") is file.etag then return res.send(304)
+    if (etag = req.get("if-none-match")) and etag is file.etag then return res.send(304)

     return res.send(200, file.content)

@@ -196,6 +196,7 @@
                   run_url: plunk.run_url + filename
                   etag: genid(16)

+                found.children ||= []
                 found.children.push(file)
                 found.children.push(smap) if smap


fix lucky precision

fix lucky precision

--- app/js/controllers/dice.coffee
+++ app/js/controllers/dice.coffee
@@ -40,7 +40,7 @@
                         tx.jackpot.payouts = tx.dice.payouts;
                         tx.jackpot.roll_high = tx.dice.roll_high;
                     else
-                        tx.jackpot.lucky_number/= 10
+                        tx.jackpot.lucky_number/= tx.precision
                         tx.jackpot.jackpot_received/= $scope.precision
                     tx.jackpot.play_amount /= $scope.precision;
                     computeCondition(tx)


catch JSON parse error

catch JSON parse error

--- server/code/model/user.coffee
+++ server/code/model/user.coffee
@@ -64,7 +64,10 @@
               form:
                 keys: JSON.stringify boxKeys
             , (err, res, body) ->
-              obj = JSON.parse body
+              try
+                obj = JSON.parse body
+              catch e
+                return boxCb e
               return boxCb obj.error if obj.error?
               return boxCb err
       , callback


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/bounded.coffee
+++ src/bounded.coffee
@@ -44,7 +44,7 @@
   Get the object closest to this one.

   @name closest
-  @me
+  @methodOf Bounded#
   @param {Object|Array|String} selector An object or set of objects to find the closest from.
   ###
   closest: (selector) ->


Remove extra quote.

Remove extra quote.

--- framer/Layer.coffee
+++ framer/Layer.coffee
@@ -19,7 +19,7 @@
 NoCacheDateKey = Date.now()

 layerValueTypeError = (name, value) ->
-	throw new Error("Layer.#{name}: value '#{value}' of type '#{typeof(value)}'' is not valid")
+	throw new Error("Layer.#{name}: value '#{value}' of type '#{typeof(value)}' is not valid")

 layerProperty = (obj, name, cssProperty, fallback, validator, transformer, options={}, set) ->
 	result =


Add cleanupImageLoader

Add cleanupImageLoader

--- framer/Layer.coffee
+++ framer/Layer.coffee
@@ -639,6 +639,10 @@
 	##############################################################
 	## IMAGE

+	cleanupImageLoader: ->
+		@imageLoader = null
+
+
 	@define "image",
 		default: ""
 		get: ->
@@ -671,7 +675,7 @@

 				if @imageLoader?
 					@emit Events.ImageLoadCancelled, @imageLoader
-					@imageLoader = null
+					@cleanupImageLoader()

 				return

@@ -699,11 +703,11 @@
 				@imageLoader.onload = =>
 					@style["background-image"] = "url('#{imageUrl}')"
 					@emit Events.ImageLoaded, @imageLoader
-					@imageLoader = null
+					@cleanupImageLoader()

 				@imageLoader.onerror = =>
 					@emit Events.ImageLoadError, @imageLoader
-					@imageLoader = null
+					@cleanupImageLoader()

 			else
 				@style["background-image"] = "url('#{imageUrl}')"


Client: Activity: Feed: Updated ensureThread method to add  comment as a thread

--- client/activity/lib/flux/stores/messagethreadssstore.coffee
+++ client/activity/lib/flux/stores/messagethreadssstore.coffee
@@ -32,7 +32,7 @@

     @on actions.LOAD_COMMENT_SUCCESS, @handleLoadSuccess

-    @on actions.CREATE_COMMENT_BEGIN, @handleCreateBegin
+    @on actions.CREATE_COMMENT_BEGIN, @handleCreateCommentBegin
     @on actions.CREATE_COMMENT_SUCCESS, @handleCreateSuccess
     @on actions.CREATE_COMMENT_FAIL, @handleCreateFail

@@ -50,7 +50,10 @@
   ensureThread: (threads, { message }) ->

     unless threads.has message.id
-      return threads = initThread threads, message.id
+      threads = initThread threads, message.id
+
+    message.replies.forEach (reply) ->
+      threads = addComment threads, message.id, reply._id

     return threads

@@ -78,7 +81,7 @@
    * @param {string} clientRequestId
    * @return {IMThreadCollection} nextState
   ###
-  handleCreateBegin: (threads, { messageId, clientRequestId }) ->
+  handleCreateCommentBegin: (threads, { messageId, clientRequestId }) ->

     return addComment threads, messageId, clientRequestId


New IE detection for forward compatibility

--- src/main/webapp/coffeescripts-hidden/load.coffee
+++ src/main/webapp/coffeescripts-hidden/load.coffee
@@ -96,6 +96,20 @@
   else
     callback()

+isBrowserIe = ->
+  div = document.createElement("div")
+  div.innerHTML = ""
+  isIe = (div.getElementsByTagName("i").length == 1)
+
+  return isIe
+
+isBrowserIe8OrLess = ->
+  div = document.createElement("div")
+  div.innerHTML = ""
+  isIeLessThan9 = (div.getElementsByTagName("i").length == 1)
+
+  return isIeLessThan9
+
 ##
 ## ANCHOR TAB LOADING AND DISPLAY
 ##
@@ -239,10 +253,9 @@
           .text("Success!")
       )

-  if $.browser.msie
-    # Bail if IE < 9.
-    if $.browser.version.split(".")[0]? < 9
-      return
+  if isBrowserIe()
+    if isBrowserIe8OrLess()
+      return # Bail, we don't work in IE <= 8.

     _gaq.push ["at._trackEvent", "Bootstrap", "MSIE", navigator.userAgent]
     anchorTab.addClass "msie"


Don't send any personally identifiable information to Snowplow

--- app/core/Tracker.coffee
+++ app/core/Tracker.coffee
@@ -166,6 +166,10 @@
       delete properties.cachedEssentialResources
       delete properties.totalEssentialResources

+    # Remove personally identifiable data
+    delete properties.name
+    delete properties.email
+
     # SnowPlow
     snowplowAction = event.toLowerCase().replace(/[^a-z0-9]+/ig, '_')
     properties.user = me.id


Fix typo

Fix typo

--- src/model/associations/plural_association.coffee
+++ src/model/associations/plural_association.coffee
@@ -55,7 +55,7 @@
     @index ||= new Batman.AssociationSetIndex(this, @[@indexRelatedModelOn])
     @index

-  indexValueForRecord: (record) -> record.get(thisprimaryKey)
+  indexValueForRecord: (record) -> record.get(this.primaryKey)

   reset: ->
     super


Call npm install during muffin install, if using the nodejs stack.

--- src/command.coffee
+++ src/command.coffee
@@ -3,6 +3,7 @@
 fs = require 'fs-extra'
 sysPath = require 'path'
 async = require 'async'
+{spawn} = require 'child_process'
 logging = require './utils/logging'
 optparse = require './utils/optparse'
 project = require './project'
@@ -148,14 +149,10 @@
         from = sysPath.join(__dirname, '../skeletons/_gitignore')
         to = sysPath.join(projectDir, '.gitignore')
         fs.copy from, to, done
-      when 'nodejs'
-        from = sysPath.join(__dirname, '../skeletons/nodejs/_gitignore')
+      when 'nodejs', 'gae'
+        from = sysPath.join(projectDir, 'server/_gitignore')
         to = sysPath.join(projectDir, 'server/.gitignore')
-        fs.copy from, to, done
-      when 'gae'
-        from = sysPath.join(__dirname, '../skeletons/gae/_gitignore')
-        to = sysPath.join(projectDir, 'server/.gitignore')
-        fs.copy from, to, done
+        fs.rename from, to, done

   # Print the completion message
   printMessage = (done) ->
@@ -261,6 +258,10 @@
     for repo, version of project.clientConfig.dependencies
       pkgmgr.install repo, version

+    # Call `npm install` in the serverDir if using the Node.js stack
+    if project.config.serverType is 'nodejs'
+      spawn 'npm', ['install'], {cwd: project.serverDir, stdio: 'inherit'}
+
 # Task - update packages
 task 'update', 'update packages', ->


Annotated command.coffee.

Annotated command.coffee.

--- src/command.coffee
+++ src/command.coffee
@@ -349,9 +349,9 @@
 # Task - deploy the app
 task 'deploy', 'deploy the app', ->
   dest = opts.arguments[1]
-  platforms = ['heroku', 'amazon', 'nodejitsu']
+  platforms = ['heroku', 'jitsu', 'gae', 'gh-pages']
   unless dest and dest.toLowerCase() in platforms
-    logging.fatal "Must choose a platform from the following: heroku, amazon, nodejitsu"
+    logging.fatal "Must choose a platform from the following: heroku, jitsu, gae, gh-pages"

 # Print the `--help` usage message and exit.
 usage = ->
@@ -359,5 +359,6 @@

 # Print the `--version` message and exit.
 version = ->
-  json = JSON.parse(fs.readFileSync("#{__dirname}/../package.json"))
+  path = sysPath.join(__dirname, '../package.json')
+  json = JSON.parse(fs.readFileSync(path))
   console.log "muffin.io - version #{json.version}"


Started work on frontend package management.

--- src/command.coffee
+++ src/command.coffee
@@ -29,8 +29,11 @@
       * muffin destroy view UserListView
       * muffin destroy scaffold user --app auth

-    Install reusable apps:
-      * muffin install app auth
+    Package management:
+      * muffin install <package-name>
+      * muffin install (installs all the frontend dependencies specified in package.json)
+      * muffin update <package-name>
+      * muffin update (updates all the frontend dependencies)

     muffin watch
       - watch the current project and recompile as needed
@@ -269,26 +272,11 @@
   ]
   removeFiles(files)

-# Task - install reusable apps
-task 'install', 'install reusable apps', ->
-  installApp = (app) ->
-    fs.copy sysPath.join(muffinDir, "framework/apps/#{app}/client"), sysPath.join(clientDir, "apps/#{app}"), -> {}
-    fs.copy sysPath.join(muffinDir, "framework/apps/#{app}/server"), sysPath.join(serverDir, "apps/#{app}"), -> {}
-    readme = sysPath.join(muffinDir, "framework/apps/#{app}/README.md")
-    if fs.existsSync(readme)
-      logging.info '\n' + fs.readFileSync(readme).toString()
-
-  if opts.arguments.length is 1
-    # Install all the apps as specified in config.coffee
-    installApp(app) for app in config.installed_apps
-  else
-    switch opts.arguments[1]
-      when 'app'
-        app = opts.arguments[2]
-        fatalError "Must specify the app to install" unless app
-        installApp(app)
-      else
-        fatalError "Unknown type"
+# Task - install packages
+task 'install', 'install packages', ->
+
+# Task - update packages
+task 'update', 'update packages', ->

 # Task - watch files and compile as needed
 task 'watch', 'watch files and compile as needed', ->


Added id to  name

Added id to  name

--- snippets/addons.cson
+++ snippets/addons.cson
@@ -16,7 +16,7 @@
     'prefix': 'linkfield'
     'body': """
     LinkField::create(
-    \t\'${1:name}\',
+    \t\'${1:name}ID\',
     \t\'${2:title}\'
     )
     $0


Deleted a file to change its name

Deleted a file to change its name


fixing mentionsArgs for accesses.

fixing mentionsArgs for accesses.

--- nodes.coffee
+++ nodes.coffee
@@ -557,6 +557,7 @@
 # an access into the object's prototype.
 exports.Access = class Access extends Base
   constructor: (@name, tag) ->
+    @name.accessed = yes
     @proto = if tag is 'proto' then '.prototype' else ''
     @soak  = tag is 'soak'

@@ -1671,9 +1672,11 @@
     call = new Call func, args
     if statement then Expressions.wrap [call] else call

-  literalArgs: (node) -> node instanceof Literal and node.value is 'arguments'
-  literalThis: (node) -> node instanceof Literal and node.value is 'this' or
-                         node instanceof Code    and node.bound
+  literalArgs: (node) ->
+    node instanceof Literal and node.value is 'arguments' and not node.accessed
+  literalThis: (node) ->
+    (node instanceof Literal and node.value is 'this' and not node.accessed) or
+      (node instanceof Code and node.bound)

 # Unfold a node's child if soak, then tuck the node under created `If`
 unfoldSoak = (o, parent, name) ->


Link to Ace of Coders

Link to Ace of Coders

Changed "torneir" to "torneio" and  "Era dos Programadores" to "Ás dos Programadores"

--- app/locale/pt-BR.coffee
+++ app/locale/pt-BR.coffee
@@ -1347,7 +1347,7 @@
     no_changes: "Sem Alterações"

   temp:
-    ace_of_coders_tournament: "Novo: jogue no torneir Era dos Programadores agora!"
+    ace_of_coders_tournament: "Novo: jogue no torneio Ás dos Programadores agora!"

   multiplayer:
     multiplayer_title: "Configurações de Multijogador" # We'll be changing this around significantly soon. Until then, it's not important to translate.


Transition to homepage just once

Transition to homepage just once

--- app/pages/question.cjsx
+++ app/pages/question.cjsx
@@ -18,7 +18,7 @@
     questionsRef.child(@props.params.questionSlug).child(i).transaction (currentVotes) ->
       (currentVotes || 0) + 1

-    setInterval =>
+    setTimeout =>
       @transitionTo 'app'
     , 2000


drawable no longer should resize object to sprite

--- src/drawable.coffee
+++ src/drawable.coffee
@@ -14,13 +14,13 @@
       width: 5
       height: 5
       sprite: "my_cool_sprite"
-
+
     engine.bind 'draw', (canvas) ->
-      player.draw(canvas)
+      player.draw(canvas)
     # => Uncaught TypeError: Object has no method 'draw'
-
+
     player.include(Drawable)
-
+
     engine.bind 'draw', (canvas) ->
       player.draw(canvas)
     # => if you have a sprite named "my_cool_sprite" in your images folder
@@ -36,14 +36,14 @@

 ###*
 Triggered every time the object should be drawn. A canvas is passed as
-the first argument.
+the first argument.

     player = Core
       x: 0
       y: 10
       width: 5
       height: 5
-
+
     player.bind "draw", (canvas) ->
       # Text will be drawn positioned relatively to the object.
       canvas.drawText
@@ -87,15 +87,11 @@
     scaleY: 1
     zIndex: 0

-  setSizeCallback = (sprite) ->
-    I.width = sprite.width
-    I.height = sprite.height
-
   if I.sprite?.isString?()
     if I.sprite.indexOf("data:") is 0
-      I.sprite = Sprite.fromURL(I.sprite, setSizeCallback)
+      I.sprite = Sprite.fromURL(I.sprite)
     else
-      I.sprite = Sprite.loadByName(I.sprite, setSizeCallback)
+      I.sprite = Sprite.loadByName(I.sprite)

   self.bind 'draw.Drawable', (canvas) ->
     if I.alpha? and I.alpha != 1
@@ -103,7 +99,7 @@
       canvas.context().globalAlpha = I.alpha

     if sprite = I.sprite
-      if sprite.draw?
+      if sprite.draw?
         sprite.draw(canvas, -sprite.width / 2, -sprite.height / 2)
       else
         warn?("Sprite has no draw method!")
@@ -164,5 +160,3 @@
       transform = transform.concat(Matrix.translation(I.spriteOffset.x, I.spriteOffset.y))

     return transform
-
-Drawable.setSizeCallback = (sprite) ->


Save group on create

Save group on create

--- core/app/backbone/views/users/react_user_groups_edit.coffee
+++ core/app/backbone/views/users/react_user_groups_edit.coffee
@@ -25,7 +25,12 @@
     group: new Group

   _submit: ->
-    alert('TODO: ' + JSON.stringify(@state.group.toJSON()))
+    @state.group.save creator: @props.user.get('username'),
+      success: (o)=>
+        Factlink.notificationCenter.success "Group #{o.get('groupname')} created."
+      error: (o)=>
+        Factlink.notificationCenter.error  "Group #{o.get('groupname')} could not be created!"
+
     @setState @_freshState()

   render: ->


Tests for the bin-tic-tac-toe operations

--- src/games/bin-tic-tac-toe.coffee
+++ src/games/bin-tic-tac-toe.coffee
@@ -134,7 +134,7 @@
   empty
   bin, at, rows, columns, diagonals, lines
   isFull, isWin, isTerminal
-  allPlays
+  openPositions, allPlays, changedOn
   utility, evaluate
   BinTicTacToe
 }


Fix callback in renameRoutes

Fix callback in renameRoutes

--- server/models/template.coffee
+++ server/models/template.coffee
@@ -35,8 +35,5 @@
   makePrimary(@primary, next)

 Template.statics.renameRoutes = (oldName, newName, callback) ->
-  Route.update({ template: oldName }, { template: newName }, (err, n) ->
-    callback(err)
-  )
-
+  Route.update({ template: oldName }, { template: newName }, callback)
 module.exports = db.model('Template', Template)


Disable view cache by default, attempt to fix hbs issue on Heroku

--- server/routes/frontend.coffee
+++ server/routes/frontend.coffee
@@ -13,6 +13,8 @@
 require('../lib/renderer')(hbs)

 app.set 'views', tplPath
+
+app.set 'view cache', false

 app.get '*', (req, res, next) ->


Extract router into its own class

Extract router into its own class

--- app/Router.coffee
+++ app/Router.coffee
@@ -9,7 +9,7 @@
 httpConfig = require('../config/HTTPConfig')
 client = new Client(config: httpConfig)
 handlebarsCompiler = new HandlebarsCompiler
-attributes =
+attributes =
   client: client
   compiler: handlebarsCompiler


Missing parameters

Missing parameters

--- resources/assets/coffee/react/profile-page/header.coffee
+++ resources/assets/coffee/react/profile-page/header.coffee
@@ -84,7 +84,7 @@
             el ProfilePage.HeaderInfo, user: @props.user, currentMode: @props.currentMode, coverUrl: @state.coverUrl

             if !@props.user.is_bot
-              el React.Fragment,
+              el React.Fragment, null,
                 el ProfilePage.DetailMobile,
                   stats: @props.stats
                   userAchievements: @props.userAchievements


Correct reference to carousel on experiments page

--- apps/about/client/index.coffee
+++ apps/about/client/index.coffee
@@ -1,7 +1,7 @@
 loggedOutNav = require '../../../components/logged_out_nav/client/index.coffee'
 slides = require './experiments.coffee'
 { mountWithApolloProvider } = require '../../../react/apollo/index.js'
-{ default: DescriptiveCarousel } = require '../../../react/components/ExperimentsCarousel/index.js'
+{ default: DescriptiveCarousel } = require '../../../react/components/DescriptiveCarousel/index.js'
 { CURRENT_PATH } = require('sharify').data

 module.exports = ->


Only pass through keys to redis that are explicitly set in the config

--- services/document-updater/app/coffee/RedisBackend.coffee
+++ services/document-updater/app/coffee/RedisBackend.coffee
@@ -113,8 +113,11 @@
 				rclient = new Redis.Cluster(config.cluster)
 				driver = "ioredis"
 			else
-				{host, port, password, endpoints, masterName} = config
-				rclient = require("redis-sharelatex").createClient({host, port, password, endpoints, masterName})
+				redis_config = {}
+				for key in ["host", "port", "password", "endpoints", "masterName"]
+					if config[key]?
+						redis_config[key] = config[key]
+				rclient = require("redis-sharelatex").createClient(redis_config)
 				driver = "redis"
 			return {
 				rclient: rclient


fix getDocTimestamps for multiple docs

fix getDocTimestamps for multiple docs

--- services/document-updater/app/coffee/RedisManager.coffee
+++ services/document-updater/app/coffee/RedisManager.coffee
@@ -4,6 +4,7 @@
 metrics = require('./Metrics')
 Errors = require "./Errors"
 crypto = require "crypto"
+async = require "async"
 ProjectHistoryRedisManager = require "./ProjectHistoryRedisManager"

 # Sometimes Redis calls take an unexpectedly long time.  We have to be
@@ -289,10 +290,9 @@

 	getDocTimestamps: (doc_ids, callback = (error, result) ->) ->
 		# get lastupdatedat timestamps for an array of doc_ids
-		multi = rclient.multi()
-		for doc_id in doc_ids
-			multi.get keys.lastUpdatedAt(doc_id: doc_id)
-		multi.exec callback
+		async.mapSeries doc_ids, (doc_id, cb) ->
+			rclient.get keys.lastUpdatedAt(doc_id: doc_id), cb
+		, callback

 	queueFlushAndDeleteProject: (project_id, callback) ->
 		# store the project id in a sorted set ordered by time


Do call unref()

Do call unref()

--- gitcommander.coffee
+++ gitcommander.coffee
@@ -54,7 +54,7 @@
   console.log "* Connected to IRC."
   console.log "* Starting timer with timout #{TIMEOUT}."
   timer = setInterval timerCallback, TIMEOUT
-  timer.unref
+  do timer.unref

 eventTeller =
   "PushEvent": (channel, event) ->


in ascii regex, color as illegal all "\." that aren't accepted with Stata's parser

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -1336,13 +1336,16 @@
   'ascii-regex-character-class':
     'patterns': [
       {
+        'match': '\\\\[\\*\\+\\?\\-\\.\\^\\$\\|\\[\\]\\(\\)\\\\]'
+        'name': 'constant.character.escape.backslash.stata'
+      }
+      {
         'match': '\\.'
         'name': 'constant.character.character-class.stata'
       }
       {
         'match': '\\\\.'
-        'name': 'constant.character.escape.backslash.stata'
-        'comment': 'this changes the color of an escaped character'
+        'name': 'illegal.invalid.character-class.stata'
       }
       {
         'begin': '(\\[)(\\^)?'


NPM - repository added

NPM - repository added

--- art.build.config.coffee
+++ art.build.config.coffee
@@ -19,6 +19,9 @@
       blanket:
         pattern: "source"

+    repository:
+      type: "git"
+      url: "git@github.com:shanebdavis/caffeine-script.git"

   webpack:
     common:


less chatty, better "support update"

less chatty, better "support update"

--- scripts/merlin-support.coffee
+++ scripts/merlin-support.coffee
@@ -1,28 +1,26 @@
 # Track Merlin support person
 #
+# support update Rick Flair, 2125551212 or ping on Twitter
 # <person> has support this sprint - tell lefay who is doing support
-# support can be reach at <phone number> - tell lefay how the support person can be reached
+# support can be reached at <phone number> - tell lefay how the support person can be reached
 # who is support?              - find out who is covering merlin support

 whoHasSupport = (robot) ->
   "#{robot.brain.data.support['person']} has Merlin support this sprint: #{robot.brain.data.support['contact']}."

 module.exports = (robot) ->
-  robot.respond /support update (\w+) (.*)/i, (msg) ->
+  robot.respond /support update ([^,]+), (.*)/i, (msg) ->
     robot.brain.data.support = {person: msg.match[1], contact: msg.match[2]}
-    msg.send whoHasSupport(robot)
     msg.topic whoHasSupport(robot)

   robot.respond /(.*) has support this sprint/i, (msg) ->
     robot.brain.data.support or= {}
     robot.brain.data.support['person'] = msg.match[1]
-    msg.send whoHasSupport(robot)
     msg.topic whoHasSupport(robot)

   robot.respond /support (can be reached at|contact info\w* is) (.*)/i, (msg) ->
     robot.brain.data.support or= {}
     robot.brain.data.support['contact'] = msg.match[2]
-    msg.send whoHasSupport(robot)
     msg.topic whoHasSupport(robot)

   robot.hear /(who (has|is)|who\'s)?\s*support\?/, (msg) ->


reactivity: chatpane: test fix

reactivity: chatpane: test fix

--- client/activity/lib/components/chatpane/test.coffee
+++ client/activity/lib/components/chatpane/test.coffee
@@ -12,13 +12,15 @@

 describe 'ChatPane', ->

-  thread = toImmutable mockingjay.getMockThread { channelId : 1 }
-  thread = thread.setIn [ 'channel', 'unreadCount' ], 1
-  threadWithFlags = toImmutable mockingjay.getMockThread { channelId : 2, flags : { reachedFirstMessage : yes } }
+  getMockThread = (args...) -> toImmutable mockingjay.getMockThread(args...)
+
+  thread = getMockThread { channelId : 1 }
+  threadWithUnreadCount = getMockThread({ channelId : 2 }).setIn [ 'channel', 'unreadCount' ], 1
+  threadWithFlags = getMockThread { channelId : 3, flags : { reachedFirstMessage : yes } }

   describe '::render', ->

-    it 'renders ChannelInfo depending in reachedFirstMessage flag', ->
+    it 'renders ChannelInfo depending on reachedFirstMessage flag', ->

       result = TestUtils.renderIntoDocument(
         <ChatPane thread={thread} />
@@ -37,16 +39,16 @@
     it 'renders ChatList', ->

       result = TestUtils.renderIntoDocument(
-        <ChatPane thread={thread} showItemMenu=yes isMessagesLoading=yes selectedMessageId=1 />
+        <ChatPane thread={threadWithUnreadCount} showItemMenu=yes isMessagesLoading=yes selectedMessageId=1 />
       )

       chatList = TestUtils.findRenderedComponentWithType result, ChatList
       expect(chatList).toExist()
-      expect(chatList.props.messages).toBe thread.get 'messages'
-      expect(chatList.props.channelId).toBe thread.getIn ['channel', 'id']
+      expect(chatList.props.messages).toBe threadWithUnreadCount.get 'messages'
+      expect(chatList.props.channelId).toBe threadWithUnreadCount.getIn ['channel', 'id']
       expect(chatList.props.isMessagesLoading).toBe yes
       expect(chatList.props.showItemMenu).toBe yes
-      expect(chatList.props.unreadCount).toBe thread.getIn ['channel', 'unreadCount']
+      expect(chatList.props.unreadCount).toBe threadWithUnreadCount.getIn ['channel', 'unreadCount']
       expect(chatList.props.selectedMessageId).toBe 1


date, timestmap, interval, ::

date, timestmap, interval, ::

--- src/grammar.coffee
+++ src/grammar.coffee
@@ -258,12 +258,15 @@

   Value: [
     o 'Literal'
+    o 'DATE Value', -> new DateValue($2)
+    o 'TIMESTAMP Value', -> new Timestamp($2)
+    o 'INTERVAL Value', -> new Interval($2)
     o 'Number'
     o 'String'
-    o 'Function'
     o 'UserFunction'
     o 'Boolean'
     o 'Parameter'
+    o 'Value COLON COLON Literal', -> new Cast($1, $4, true)
   ]

   List: [


Log the body of the sign_certificate response, it'd be very useful for debugging.

--- src/bootstrap.coffee
+++ src/bootstrap.coffee
@@ -82,7 +82,7 @@
 		if response.statusCode >= 400
 			throw body

-		console.log('Configuring VPN..')
+		console.log('Configuring VPN..', JSON.stringify(body))
 		vpnConf = fs.readFileAsync(__dirname + '/openvpn.conf.tmpl', 'utf8')
 			.then (tmpl) ->
 				fs.writeFileAsync('/data/client.conf', _.template(tmpl)(body))


Make projections argument of rebuild method first class

Providing projections is not an _option_

--- source/server/infrastructure/projection-rebuilder.coffee
+++ source/server/infrastructure/projection-rebuilder.coffee
@@ -8,16 +8,16 @@
     mongo: 'Mongo'
   }

-  rebuild: (options) ->
+  rebuild: (projections, options) ->

-    unless options.projections?
+    unless projections?
       throw new Error 'You have to provide an array of projection qualifiers.'

     realCollectionsBackups = {}
     queue = []

     # Loop over all projections that should be rebuilt
-    for projectionId in options.projections
+    for projectionId in projections
       projection = @injector.get projectionId
       # Save backups of the real collections to restore them later and
       # override the real collections with in-memory pendants


Use TomDoc

Use TomDoc

--- src/install.coffee
+++ src/install.coffee
@@ -185,8 +185,8 @@

   # Get the path to the package from the local cache.
   #
-  #  * packageName: The string name of the package.
-  #  * packageVersion: The string version of the package.
+  #  packageName - The string name of the package.
+  #  packageVersion - The string version of the package.
   #
   # Returns a path to the cached tarball or undefined when not in the cache.
   getPackageCachePath: (packageName, packageVersion) ->


More tidying

More tidying

--- server/methods/account.coffee
+++ server/methods/account.coffee
@@ -1,14 +1,3 @@
 # Meteor.methods
-# 	'updatePassword': (doc)->
-# 		console.log doc
-
-# 		console.log 'updating password'
-
-# 		r =
-# 			success: false
-
-# 		if doc.new != doc.confirm
-# 			console.log 'passwords do not match'
-# 			new Meteor.Error 500, 'Passwords do not match'
-
-# 		return 'hi'+# 	'changeEmail': (email)->
+# 		#...


bugfix in publish

bugfix in publish

--- server/publish/reports.coffee
+++ server/publish/reports.coffee
@@ -5,9 +5,13 @@
 			lastDay = parseInt moment(month, 'YYYY[M]MM').endOf('month').format('YYYYDDDD')

 			Shifts.find
-				projectId: projectId
-				date: $gte: firstDay
-				date: $lte: lastDay
+				$and: [
+					projectId: projectId
+				,
+					date: $gte: firstDay
+				,
+					date: $lte: lastDay
+				]
 			,
 				fields:
 					date: 1


Simplify the way .TP titles clamp their formatting

This is an attempt to get 93402be's fix working in Lightshow.

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -1478,20 +1478,18 @@

 			# .TP: Titled paragraph
 			begin: "^([.'])[ \t]*(TP)\\b(.*)?$\\n?"
-			end:   "$"
+			end:   "^(.*)(?<!\\\\)$"
+			patterns: [
+				match: ".+"
+				captures: 0: patterns: [include: "$self"]
+			]
 			beginCaptures:
 				0: {name: "meta.function.titled-paragraph.man.macro.roff"}
 				1: {name: "punctuation.definition.macro.roff"}
 				2: {name: "entity.function.name.roff"}
 				3: {patterns: [include: "#param-group"]}
-			patterns: [{
-
-				# Stop fonts spilling across the first line
-				begin: "^(.+)"
-				end: "(?<!\\\\)$"
-				beginCaptures:
-					1: patterns: [include: "$self"]
-			}]
+			endCaptures:
+				1: {patterns: [include: "$self"]}
 		},{

 			# .TQ: Header continuation for .TP (GNU extension)


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -220,7 +220,7 @@
           xw = target.width/2
           yw = target.height/2

-          # Convert from
+          # Convert from bound
           return Collision.rayRectangle source, direction,
             x: target.x + xw
             y: target.y + yw


Fixes updateLayout to make antiscroll update its dimensions

--- src/component.coffee
+++ src/component.coffee
@@ -152,7 +152,7 @@
   updateLayout: ->
     # updating antiscroll
     return unless @get('state') is 'inDOM'
-    this.$('.antiscroll-wrap').antiscroll()
+    this.$('.antiscroll-wrap').antiscroll().data('antiscroll').rebuild();
     @doForceFillColumns() if @get('forceFillColumns')

   doForceFillColumns: ->


Moved some lines around

Moved some lines around

--- src/creatures.coffee
+++ src/creatures.coffee
@@ -1,16 +1,15 @@
 Q = require 'q'
+_ = require 'lodash'

 {Entity} = require './entities'
-
-class exports.Creature extends Entity
-
-_ = require 'lodash'

 directions =
 	up: [0, -1]
 	down: [0, 1]
 	left: [-1, 0]
 	right: [1, 0]
+
+class exports.Creature extends Entity

 class exports.Dummy extends exports.Creature
 	symbol: 'D'


isNextEpisodeForItemAired: check if the next seasons to see actually exists. Fixes #1.

--- src/js/menus.coffee
+++ src/js/menus.coffee
@@ -35,10 +35,11 @@
   e.menu.item e.sectionIndex, e.itemIndex, e.item

 isNextEpisodeForItemAired = (item) ->
-  return false unless item.next_episode?
-  if item.next_episode.season > item.seasons.length
+  if not item.next_episode?
     return false
   season = s for s in item.seasons when s.number == item.next_episode.season
+  if not season?
+    return false
   if item.next_episode.number > season.aired
     return false
   true


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -136,6 +136,7 @@
     position - An x, y object representing the position of the meter
     radius - Border radius of the meter
     showName - Boolean to toggle whether or not to show the attribute associated with the meter
+    text
   ###
   meter: (options={}) ->
     Object.reverseMerge options,


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -29,10 +29,6 @@
 # => Sets up a turbo meter that will be drawn during the someOtherObject overlay event.
 # Since neither turbo maxTurbo were provided, they are both set to 100.

-
-# now player has all the methods provided by this module
-player.position()
-# => {x: 10, y: 50}
 </pre></code>

 @see GameObject


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -129,6 +129,7 @@
   @param {Object} options The meter configuration options
     borderColor - The color of the meter's border
     borderWidth - The width of the meter's border
+
   ###
   meter: (options={}) ->
     Object.reverseMerge options,


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -31,7 +31,7 @@

 </pre></code>

-M module
+Metered module
 @name Bounded
 @module
 @constructor


no longer have debug.coffee

no longer have debug.coffee

--- grunt/build.coffee
+++ grunt/build.coffee
@@ -48,7 +48,7 @@
     coverage:
       expand: true
       dest: 'build/'
-      src: ['src/**/*.coffee', '!src/debug.coffee']
+      src: ['src/**/*.coffee']
       ext: '.js'
   )


Focus inner a when highlighting a search result

--- lineman/app/components/navbar/navbar_search.coffee
+++ lineman/app/components/navbar/navbar_search.coffee
@@ -22,6 +22,7 @@
       $scope.highlighted = index
       _.map highlightables(), (element) -> element.classList.remove("is-active")
       if $scope.highlightedSelection()?
+        $scope.highlightedSelection().firstChild.focus()
         $scope.highlightedSelection().classList.add("is-active")
         # scroll to newly highlighted element?


local_hub -- band-aid around something that could lock the local_hub server, which I found based on user feedback; will fix right later

--- salvus/local_hub.coffee
+++ salvus/local_hub.coffee
@@ -1232,7 +1232,12 @@
         winston.debug("sage_update")#: opts=#{misc.to_json(opts)}")
         i = 0
         prev_ids = {}
+        z = 0
         while true
+            z += 1
+            if z > 5000
+                winston.debug("sage_update: ERROR -- hit a possible infinite loop; opts=#{misc.to_json(opts)}")
+                break
             i = @content.indexOf(diffsync.MARKERS.cell, i)
             if i == -1
                 break


fix d2l regression

fix d2l regression

--- src/opcodes.coffee
+++ src/opcodes.coffee
@@ -429,11 +429,11 @@
   143: new root.Opcode 'd2l', { execute: (rs) ->
     d_val = rs.pop2();
     if d_val is Number.POSITIVE_INFINITY
-      rs.push gLong.MAX_VALUE
+      rs.push gLong.MAX_VALUE, null
     else if d_val is Number.NEGATIVE_INFINITY
-      rs.push gLong.MIN_VALUE
+      rs.push gLong.MIN_VALUE, null
     else
-      rs.push gLong.fromNumber(d_val, null) }
+      rs.push gLong.fromNumber(d_val), null }
   144: new root.Opcode 'd2f', { execute: (rs) -> rs.push wrap_float rs.pop2() }
   145: new root.Opcode 'i2b', { execute: (rs) -> rs.push util.truncate rs.pop(), 8 }
   146: new root.Opcode 'i2c', { execute: (rs) -> rs.push rs.pop()&0xFFFF }  # 16-bit unsigned integer


MediaElement doesn't need the document to be loaded to be set with the theme path to find its flash/silverlight stuff.

--- js/media/mediaelement_defaults/mediaelement_defaults.coffee
+++ js/media/mediaelement_defaults/mediaelement_defaults.coffee
@@ -1 +1 @@
-LOAD(-> mejs.MediaElementDefaults.pluginPath = HThemeManager.themePaths.mejs )
+(-> mejs.MediaElementDefaults.pluginPath = HThemeManager.themePaths.mejs )()


--- spec/api/recursor_spec.coffee
+++ spec/api/recursor_spec.coffee
@@ -152,7 +152,7 @@

-        it 'it recurses no further if function callback with body or statusCode',
+        it 'recurses no further if function callback with body or statusCode',

             ipso (facto, subject, config, options) ->

@@ -184,7 +184,17 @@

-
-
-
-
+        it 'calls back with the accompanying $api hash',
+
+            ipso (facto, subject) ->
+
+                root = module: function: (opts, callback) -> callback null, statusCode: 404
+                root.module.function.$api = configKey: 'configValue'
+
+                subject.recurse {}, ['module', 'function'], root, (error, result, api) ->
+
+                    api.should.eql configKey: 'configValue'
+                    facto()
+
+
+


Increase wait time in spec

Increase wait time in spec

This kinda sucks, but it’s not the end of the world.

--- spec/menu-manager-spec.coffee
+++ spec/menu-manager-spec.coffee
@@ -71,7 +71,7 @@
       atom.keymaps.add 'test', 'atom-workspace': 'ctrl-b': 'b'
       atom.keymaps.add 'test', 'atom-text-editor': 'ctrl-b': 'unset!'

-      waits 1
+      waits 50

       runs -> expect(menu.sendToBrowserProcess.argsForCall[0][1]['b']).toBeUndefined()


Add specs for message, options, and detail

--- spec/notification-spec.coffee
+++ spec/notification-spec.coffee
@@ -2,6 +2,22 @@

 describe "Notification", ->
   [notification] = []
+
+  it "throws an error when created with a non-string message", ->
+    expect(-> new Notification('error', null)).toThrow()
+    expect(-> new Notification('error', 3)).toThrow()
+    expect(-> new Notification('error', {})).toThrow()
+    expect(-> new Notification('error', false)).toThrow()
+
+  it "throws an error when created with non-object options", ->
+    expect(-> new Notification('error', 'message', 'foo')).toThrow()
+    expect(-> new Notification('error', 'message', 3)).toThrow()
+    expect(-> new Notification('error', 'message', false)).toThrow()
+
+  it "throws an error when created with a non-string detail", ->
+    expect(-> new Notification('error', 'message', detail: 3)).toThrow()
+    expect(-> new Notification('error', 'message', detail: false)).toThrow()
+    expect(-> new Notification('error', 'message', detail: {})).toThrow()

   describe "::getTimestamp()", ->
     it "returns a Date object", ->


Remove jQuery use from results-view-spec

--- spec/results-view-spec.coffee
+++ spec/results-view-spec.coffee
@@ -1,8 +1,6 @@
+_ = require 'underscore-plus'
 path = require 'path'
-_ = require 'underscore-plus'
-{$} = require 'atom-space-pen-views'
 temp = require "temp"
-
 ResultsPaneView = require '../lib/project/results-pane'
 FileIcons = require '../lib/file-icons'

@@ -26,7 +24,7 @@
     jasmine.attachToDOM(workspaceElement)
     atom.config.set('core.excludeVcsIgnoredPaths', false)
     atom.project.setPaths([path.join(__dirname, 'fixtures')])
-    promise = atom.packages.activatePackage("find-and-replace").then ({mainModule}) ->
+    activationPromise = atom.packages.activatePackage("find-and-replace").then ({mainModule}) ->
       mainModule.createViews()
       {projectFindView} = mainModule
       spy = spyOn(projectFindView, 'confirm').andCallFake ->
@@ -35,7 +33,7 @@
     atom.commands.dispatch workspaceElement, 'project-find:show'

     waitsForPromise ->
-      promise
+      activationPromise

   describe "result sorting", ->
     beforeEach ->
@@ -788,22 +786,8 @@
         expect(fileIconClasses).not.toContain('third-icon-class fourth-icon-class icon')
         expect(fileIconClasses).toContain('icon-file-text icon')

-  # Keep. Useful for debugging.
-  logSelectedIndex = ->
-    paths = resultsView.find('.path')
-    selectedView = resultsView.find('.selected')
-
-    if selectedView.hasClass('path')
-      console.log 'PATH', paths.index(selectedView)
-    else
-      for pathElement, pathIndex in paths
-        index = $(pathElement).find('.search-result').index(selectedView)
-        console.log pathIndex, index if index > -1
-        break
-
 buildMouseEvent = (type, properties...) ->
-  properties = _.extend({bubbles: true, cancelable: true}, properties...)
-  properties.detail ?= 1
+  properties = _.extend({bubbles: true, cancelable: true, detail: 1}, properties...)
   event = new MouseEvent(type, properties)
   Object.defineProperty(event, 'which', get: -> properties.which) if properties.which?
   if properties.target?


Add another test case for bufferRow tracking

--- spec/symbol-store-spec.coffee
+++ spec/symbol-store-spec.coffee
@@ -77,6 +77,16 @@
     expect(getSymbolBufferRows('multipleLines')).toEqual [2, 3]
     expect(store.getSymbol('yeah')).toBeUndefined()
     expect(getSymbolBufferRows('ok')).toEqual [2, 3]
+
+    editor.insertText("\n\nomg = 'ok'; multipleLines += 'wow'\n\n")
+
+    expect(getSymbolBufferRows('abc')).toEqual [0]
+    expect(getSymbolBufferRows('onetwo')).toEqual [1]
+    expect(getSymbolBufferRows('one')).toEqual [1]
+    expect(getSymbolBufferRows('two')).toEqual [1]
+    expect(getSymbolBufferRows('wow')).toEqual [4]
+    expect(getSymbolBufferRows('multipleLines')).toEqual [2, 4, 7]
+    expect(getSymbolBufferRows('ok')).toEqual [2, 4, 7]

   describe "::symbolsForConfig(config)", ->
     it "gets a list of symbols matching the passed in configuration", ->


Moved more default settings to presets.

Moved more default settings to presets.

--- src/presets.coffee
+++ src/presets.coffee
@@ -17,6 +17,13 @@
         direction: 1
         once: false
         delay: 5000
+      radius:
+        x: 220
+      controls:
+        margin:
+          x: 20
+          y: 190
+      currentLayer: 1
       funcSize: (layerDiff, rondell) ->
         (rondell.maxItems / Math.abs(layerDiff)) / rondell.maxItems

@@ -26,9 +33,19 @@
       visibleItems: 4
       itemProperties:
         delay: 0
+        size:
+          width: 100
+          height: 200
+        sizeFocused:
+          width: 300
+          height: 200
       center:
         left: 400
         top: 100
+      controls:
+        margin:
+          x: 210
+          y: 158
       funcTop: (layerDiff, rondell) ->
         0
       funcDiff: (layerDiff, rondell) ->
@@ -46,6 +63,13 @@
       visibleItems: 1
       controls:
         enabled: false
+      center:
+        left: 200
+        top: 200
+      itemProperties:
+        size:
+          width: 400
+          height: 400
       funcTop: (layerDiff, rondell) ->
           rondell.center.top - rondell.itemProperties.size.height / 2
       funcLeft: (layerDiff, rondell) ->
@@ -54,6 +78,21 @@
           Math.abs(layerDiff) + 0.5

     cubic:
+      center:
+        left: 400
+        top: 200
+      visibleItems: 5
+      itemProperties:
+        size:
+          width: 350
+          height: 350
+        sizeFocused:
+          width: 350
+          height: 350
+      controls:
+        margin:
+          x: 10
+          y: 190
       funcTop: (layerDiff, rondell) ->
           rondell.center.top - rondell.itemProperties.size.height / 2 + Math.pow(layerDiff / 2, 3) * rondell.radius.x
       funcLeft: (layerDiff, rondell) ->
@@ -84,7 +123,7 @@
       funcDiff: (layerDiff, rondell) ->
         Math.abs(layerDiff) - 0.5
       funcLeft: (layerDiff, rondell) ->
-        rondell.center.left + (layerDiff - 0.5) * rondell.itemProperties.size.width
+        rondell.center.left + (layerDiff - 0.5) * (rondell.itemProperties.size.width + 5)
       funcOpacity: (layerDist, rondell) ->
         0.8


added spacing to presets which was currently missing and made the font unable to load

--- src/presets.coffee
+++ src/presets.coffee
@@ -28,6 +28,7 @@
 		curviness: 0.6
 		opticThickness: 1
 		serifBall: 1
+		spacing: 1

 	'Modern':
 		xHeight: 500
@@ -58,6 +59,7 @@
 		curviness: 0.6
 		opticThickness: 1
 		serifBall: 1
+		spacing: 1

 	'Slab':
 		xHeight: 500
@@ -88,6 +90,7 @@
 		curviness: 0.6
 		opticThickness: 1
 		serifBall: 1
+		spacing: 1

 	'Sans-serif':
 		xHeight: 500
@@ -118,6 +121,7 @@
 		curviness: 0.6
 		opticThickness: 1
 		serifBall: 1
+		spacing: 1

 	'Blackletter':
 		xHeight: 500
@@ -148,3 +152,4 @@
 		curviness: 0.6
 		opticThickness: 1
 		serifBall: 1
+		spacing: 1


don't mutate options

don't mutate options

--- src/preview.coffee
+++ src/preview.coffee
@@ -12,12 +12,17 @@
   async.map dirs, api.linkGadget.bind(api), (err, results) ->
     if err then return callback err

-    if options.player
-      options.playerPath = path.resolve(options.player)
-    else
-      options.playerPath = path.join(HTML_PATH, 'player')
+    if options.port
+      serverOptions =
+        port: options.port
+        apiMiddleware: api.middleware()
+        playerPath: path.join(HTML_PATH, 'player')

-    if options.port then startServer api, options
+      if options.player
+        serverOptions.playerPath = path.resolve(options.player)
+
+      startServer api, serverOptions
+
     callback null, results

 startServer = (api, options) ->


fix: no need to do asc

fix: no need to do asc

--- app/models/user.coffee
+++ app/models/user.coffee
@@ -29,7 +29,7 @@
   sortProperties: ["lastFileCreatedOn:desc"]
   sortedProjects: Ember.computed.sort 'projects', 'sortProperties'

-  sortPricingProperties: ['id:asc']
+  sortPricingProperties: ['id']
   sortedPricings: Ember.computed.sort 'pricings', 'sortPricingProperties'

   projectCount: Ember.computed.alias 'projects.length'


Rearrange snippets

Rearrange snippets

--- snippets/language-csound.cson
+++ snippets/language-csound.cson
@@ -1,28 +1,28 @@
 '.source.csound':
+  'else':
+    'prefix': 'else'
+    'body': 'else\n\t${1:/* statements */}'
+  'elseif':
+    'prefix': 'elseif'
+    'body': 'elseif ${1:/* condition */} then\n\t${2:/* statements */}'
+  'if':
+    'prefix': 'if '
+    'body': 'if ${1:/* condition */} then\n\t${2:/* statements */}\nendif'
   'instrument block':
     'prefix': 'instr'
     'body': 'instr ${1:name}\n\t${2:/* statements */}\nendin'
+  'i-time while loop':
+    'prefix': 'iwhile'
+    'body': 'i${1:Index} = ${2:0}\nwhile i${1:Index} < ${3:/* count */} do\n\t${4:/* statements */}\n\ti${1:Index} += 1\nod'
+  'k-rate while loop':
+    'prefix': 'kwhile'
+    'body': 'k${1:Index} = ${2:0}\nwhile k${1:Index} < ${3:/* count */} do\n\t${4:/* statements */}\n\tk${1:Index} += 1\nod'
   'opcode':
     'prefix': 'opcode'
     'body': 'opcode ${1:name}, ${2:/* output types */ 0}, ${3:/* input types */ 0}\n\t${4:/* statements */}\nendop'
-  'if':
-    'prefix': 'if '
-    'body': 'if ${1:/* condition */} then\n\t${2:/* statements */}\nendif'
-  'elseif':
-    'prefix': 'elseif'
-    'body': 'elseif ${1:/* condition */} then\n\t${2:/* statements */}'
-  'else':
-    'prefix': 'else'
-    'body': 'else\n\t${1:/* statements */}'
-  'k-rate while loop':
-    'prefix': 'kwhile'
-    'body': 'k${1:Index} = ${2:0}\nwhile k${1:Index} < ${3:/* count */} do\n\t${4:/* statements */}\n\tk${1:Index} += 1\nod'
-  'i-rate while loop':
-    'prefix': 'iwhile'
-    'body': 'i${1:Index} = ${2:0}\nwhile i${1:Index} < ${3:/* count */} do\n\t${4:/* statements */}\n\ti${1:Index} += 1\nod'
+  'until loop':
+    'prefix': 'until'
+    'body': 'until ${1:/* condition */} do\n\t${2:/* statements */}\nod'
   'while loop':
     'prefix': 'while'
     'body': 'while ${1:/* condition */} do\n\t${2:/* statements */}\nod'
-  'until loop':
-    'prefix': 'until'
-    'body': 'until ${1:/* condition */} do\n\t${2:/* statements */}\nod'


Remove account tag from imports

Remove account tag from imports

--- app/src/imports.coffee
+++ app/src/imports.coffee
@@ -224,7 +224,6 @@
         'models/operation'
         'models/account'
         'models/configuration'
-        'models/account_tag'

         ## Dialog Management
         'utils/dialogs'


don't clean validator classes

don't clean validator classes

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -328,6 +328,7 @@
                 new RegExp('^.LicenseSpecs.*')
                 new RegExp('^.Blog-nav.*')
                 new RegExp('^.loading.*')
+                new RegExp('^.parsley-.*')
                 ]
                 ))
     .pipe(gulp.dest('build/css'))


fix(build): tag log

fix(build): tag log

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -103,8 +103,9 @@
 	gulp.src ['./package.json','./bower.json','./dist/*']
 		# commit the changed version number
 		.pipe git.commit 'chore(release): Bump Version Number'
+		# Filter down to only one file
+		.pipe filter 'package.json'
 		# **tag it in the repository**
-		.pipe gulp.src ['./package.json']
 		.pipe tag_version()

 gulp.task 'release:prerel', -> releaseVersion 'prerelease'


update coffee-script registration for mocha

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -26,7 +26,7 @@
     .pipe istanbul({includeUntested: true}) # Covering files
     .on 'finish', ->
       gulp.src ['spec/**/*.spec.coffee']
-        .pipe mocha reporter: 'spec', compilers: 'coffee:coffee-script'
+        .pipe mocha reporter: 'spec', compilers: 'coffee:coffee-script/register'
         .pipe istanbul.writeReports() # Creating the reports after tests run

 gulp.task 'default', ['clean', 'coffee']


Add gulp task for copy plugins templates.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -170,7 +170,6 @@
         .pipe(concat("libs.js"))
         .pipe(gulp.dest("dist/js/"))

-
 gulp.task "locales", ->
     gulp.src("app/locales/en/app.json")
         .pipe(wrap("angular.module('taigaLocales').constant('localesEnglish', <%= contents %>);"))
@@ -194,6 +193,9 @@

     gulp.src("#{paths.app}/images/**/*")
         .pipe(gulp.dest("#{paths.dist}/images/"))
+
+    gulp.src("#{paths.app}/plugins/**/templates/*")
+        .pipe(gulp.dest("#{paths.dist}/plugins/"))

 gulp.task "connect", ->


update

update

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -8,7 +8,6 @@

 gulp.task 'example', ->
 	htmlOptimizer = require './lib/index'
-	through = require 'through2'
 	gulp.src('example/src/**/*.src.html')
 		.pipe htmlOptimizer
 			beautifyTemplate: true


using is_feedback_available to check for task display

--- src/helpers/policies/utils.coffee
+++ src/helpers/policies/utils.coffee
@@ -9,7 +9,7 @@
 utils =
   _dueState: (task) ->
     state = 'before'
-    state = 'after' if task.due_at? and TaskStore.isTaskPastDue(task.id)
+    state = 'after' if task.is_feedback_available or (task.due_at? and TaskStore.isTaskPastDue(task.id))

     state


less confusing set of characters (mode symbols)?

--- graphics.coffee
+++ graphics.coffee
@@ -9,10 +9,10 @@
       width: @block*3
       height: @block*10
     @mode_appearance = [
-      {x: 0, y: 0, invert: false, circle: true},
-      {x: @block*2, y: 0, invert: true, circle: true},
-      {x: 0, y: @block*6, invert: false, circle: false},
-      {x: @block*2, y: @block*6, invert: true, circle: false}]
+      {x: 0, y: 0, shape: 'circle'}
+      {x: @block*2, y: 0, shape: 'diamond'}
+      {x: 0, y: @block*6, shape: 'clover'}
+      {x: @block*2, y: @block*6, shape: 'pinch'}]
     @record_dims =
       x: @mode_dims.x + @mode_dims.width + @block
       y: 10
@@ -479,18 +479,12 @@
     if radius == 0
       return
     mode_appearance = @mode_appearance[mode]
-    if mode_appearance.invert
-      @ctx.strokeStyle = 'black'
-      @ctx.fillStyle = 'white'
-    else
-      @ctx.strokeStyle = 'white'
-      @ctx.fillStyle = 'black'
+
+    @ctx.strokeStyle = 'white'
+    @ctx.fillStyle = 'black'

     @ctx.lineWidth = 1.5
-    if mode_appearance.circle
-      @renderShape('circle', radius*.4, true)
-    else
-      @renderShape('diamond', radius*.4, true)
+    @renderShape(mode_appearance.shape, radius*.4, true)

   # record sprite insertion behaviors
   # normal: pop in
@@ -758,6 +752,21 @@
         @ctx.lineTo(cb, ics)
         @ctx.lineTo(0, ics-cb)
         @ctx.closePath()
+      when 'clover'
+        r = radius*.75
+        r2 = r/2
+        @ctx.moveTo(0,-r2)
+        @ctx.arc( r2,-r2, r2,     Math.PI, -1.5*Math.PI)
+        @ctx.arc( r2, r2, r2, -.5*Math.PI,      Math.PI)
+        @ctx.arc(-r2, r2, r2,           0,  -.5*Math.PI)
+        @ctx.arc(-r2,-r2, r2,-1.5*Math.PI,    0)
+      when 'pinch'
+        r = radius*.75
+        @ctx.moveTo(-r,-r)
+        @ctx.quadraticCurveTo(0,0, r,-r)
+        @ctx.quadraticCurveTo(0,0, r, r)
+        @ctx.quadraticCurveTo(0,0,-r, r)
+        @ctx.quadraticCurveTo(0,0,-r,-r)

     if fill
       @ctx.fill()


reserve space for clues

reserve space for clues

--- graphics.coffee
+++ graphics.coffee
@@ -25,6 +25,11 @@
       y: @record_dims.y+@record_dims.height+@block
       width: @block*10
       height: @block*10
+    @clues_dims =
+      x: 10
+      y: @board_dims.y+@board_dims.height+@block
+      width: @block*14
+      height: @block*4

     @program_fill_style = '#404040'
     @program_stroke_style = '#000000'
@@ -41,7 +46,7 @@
     # construct the canvas
     @cnv = document.createElement('canvas')
     @cnv.width = @board_dims.x + @board_dims.width + @block
-    @cnv.height = @board_dims.y + @board_dims.height + @block
+    @cnv.height = @clues_dims.y + @clues_dims.height + @block
     @parent_div.appendChild(@cnv)
     @ctx = @cnv.getContext('2d')

@@ -183,6 +188,7 @@
     @ctx.save()

     @renderWalls()
+    @renderClues()

     @ctx.restore()

@@ -581,6 +587,11 @@
         ]

     @advanceNextRecordSprite(0)
+
+  renderClues: ->
+    @ctx.save()
+
+    @ctx.restore()

   onAnimComplete: (fcn) ->
     @anim_complete_callbacks.push(fcn)


discard the largest and smallest values to get a more even min/max distribution

--- source/javascripts/all.coffee
+++ source/javascripts/all.coffee
@@ -16,7 +16,6 @@
   '#fff'
 ]

-
 intensity   = d3.scale.quantile()
 projection  = d3.geo.albers().rotate [120]
 path        = d3.geo.path().projection projection
@@ -39,9 +38,8 @@
   </table>
   "

-d3.json 'data/neighborhoods.json', (pdx) ->
+d3.json 'data/neighborhoods-simplified.json', (pdx) ->
   neighborhoods = topojson.feature pdx, pdx.objects.neighborhoods
-
   projection.scale(1).translate [0, 0]

   b = path.bounds(neighborhoods)
@@ -126,10 +124,14 @@
 # type    - Index of type (2000, 2010, total change, % growth)
 highlight = (subject, type) ->
   colorRange = __mappings[subject][2] ?= colors
-  [min, max] = d3.extent places, (d) -> d.value[subject][type]
+  values = places.map((d) -> parseFloat(d.value[subject][type]))
+    .sort (a, b) -> d3.ascending(a, b)
+
+  # Discard larges and smallest numbers
+  min = values[1]
+  max = values[values.length - 2]

   updateInfo subject, type, __mappings[subject]
-
   intensity.domain([min, max]).range colorRange

   vis.selectAll('.neighborhood:not(.shared):not(.unclaimed)')


Remove theme menu assertion from panel spec

themes are no longer installed from this panel.

--- spec/themes-panel-spec.coffee
+++ spec/themes-panel-spec.coffee
@@ -66,30 +66,6 @@
         expect(panel.uiMenu.val()).toBe 'atom-light-ui'
         expect(panel.syntaxMenu.val()).toBe 'atom-light-syntax'

-  describe "when a theme is installed", ->
-    it "adds it to the menu", ->
-      expect(panel.syntaxMenu.find('option[value=a-theme]').length).toBe 0
-
-      themeView = null
-      waitsFor ->
-        themeView = panel.find('.available-package-view').view()
-        themeView?
-
-      runs ->
-        expect(themeView.settingsButton.css('display')).toBe 'none'
-        spyOn(packageManager, 'runCommand').andCallFake (args, callback) ->
-          process.nextTick -> callback(0)
-        themeView.installButton.click()
-        expect(themeView.installButton.prop('disabled')).toBe true
-
-      waitsFor ->
-        panel.syntaxMenu.find('option[value=a-theme]').length is 1
-
-      runs ->
-        expect(themeView.status).toHaveClass 'icon-check'
-        expect(themeView.installButton.prop('disabled')).toBe false
-        expect(themeView.settingsButton.css('display')).not.toBe 'none'
-
   describe "when a theme fails to install", ->
     it "displays an error", ->
       expect(panel.syntaxMenu.find('option[value=a-theme]').length).toBe 0


some fixes of deployerkite

some fixes of deployerkite

--- kites/Deployer.kite/index.coffee
+++ kites/Deployer.kite/index.coffee
@@ -24,28 +24,41 @@

   createLxc: (callback) ->
     cmd = spawn "create-lxc", [@name]
+    console.log 'create lxc'
     cmd.stdout.on 'data', (data) ->
       console.log 'stdout: ', data
     cmd.stderr.on 'data', (data) ->
       console.log 'stderr: ', data
     cmd.on 'close', (code) ->
-      console.log 'child process exited with code ', code
+      console.log 'create lxc process exited with code ', code
       callback()

 class Deployment
   constructor: (@zipUrl, @name, @lxc) ->
     console.log "......Deployment constructor",  @lxc
-    @kitePath = path.join @lxc.pathToContainers, @lxc.name, "overlay", "opt", "kites", @lxc.name
+    @kitePath = path.join @lxc.pathToContainers, @lxc.name, "overlay", "opt", "kites"

   downloadAndExtractKite: (callback) ->
       fs.mkdirsSync(@kitePath) ## TODO mkdir creates 0777, exists check
-      file = fs.createWriteStream @kitePath
+      file = fs.createWriteStream path.join @kitePath, "#{name}.zip"
       request = https.get @zipUrl, (response) ->
         response.pipe file
-      callback()
+        response.on "close", () ->
+          if response.statusCode is 200
+            process.chdir @kitePath
+            cmd = spawn "unzip", ["-v", "#{name}.zip"]
+            console.log 'unziping kite'
+            cmd.stdout.on 'data', (data) ->
+              console.log 'stdout: ', data
+            cmd.stderr.on 'data', (data) ->
+              console.log 'stderr: ', data
+            cmd.on 'close', (code) ->
+              console.log 'unzip process exited with code ', code
+              callback()

   runKite: () ->
-    cmd = spawn "/usr/bin/lxc-execute /bin/bash -c \" cd #{@kitePath} && /usr/bin/kd kite run #{@name}\""
+    process.chdir path.join @kitePath, @name
+    cmd = spawn "/usr/bin/lxc-execute && /usr/bin/kd kite run #{@name}\""
     cmd.stdout.on 'data', (data) ->
       console.log 'stdout: ', data
     cmd.stderr.on 'data', (data) ->
@@ -56,9 +69,7 @@
 kite.worker manifest,
   # This is a dummy method of the kite.
   deploy: (options, callback) ->
-    console.log options
     {zipUrl, name} = options
-    console.log name, zipUrl
     lxc = new LXC(name)
     lxc.createLxc () ->
       deployment = new Deployment(zipUrl, name, lxc)


edited option buttons' text

edited option buttons' text

--- client/listview.coffee
+++ client/listview.coffee
@@ -15,9 +15,9 @@
   'click [data-action=showActionSheet]': (e, t) ->
     IonActionSheet.show
       buttons: [
-        { text: 'Mass Edit' }
+        { text: 'Edit All Items' }
       ]
-      destructiveText: 'Remove all checked'
+      destructiveText: 'Delete All Checked Items'
       buttonClicked: (index) ->
         if index == 0
           t.edit.set true


use custom helper instead of "clone"

use custom helper instead of "clone"

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -333,7 +333,7 @@
                      # add draggable functionality to the image after it has been dropped
                     imageInsert.draggable
                         cursor: "move"
-                        helper: "clone"
+                        helper: dnd.createHelper
                         drag: dnd.handleDragEvent
                         stop: dnd.handleStopEvent


fix #225 docpad skeleton blocks instead of ending

--- src/lib/interfaces/console.coffee
+++ src/lib/interfaces/console.coffee
@@ -275,6 +275,7 @@
 		# Select
 		console.log cliColor.bold locale.skeletonSelectionPrompt
 		commander.choose skeletonNames, (i) ->
+			process.stdin.destroy()
 			return next(null, skeletonsCollection.at(i))

 		# Chain


invoke append through delay api and do it right (use $.add for root)

--- src/dt-jquery.coffee
+++ src/dt-jquery.coffee
@@ -1,32 +1,31 @@

 # TODO i think this should work with asyncxml as well
-# FIXME  this should be in an own package
+# TODO use requestAnimationFrame to update dom
 # TODO listen on data and use innerHTML to create all dom elems at once
 #       http://blog.stevenlevithan.com/archives/faster-than-innerhtml

 jqueryify = (tpl) ->
-    tpl.xml._children = []
-    tpl.on 'add', (el) ->
-        el._children = [] unless el._jquery?
+    tpl.xml._jquery = $()

     tpl.on 'close', (el) ->
         el._jquery = $(el.toString())
-        # insert all children jquery parts
-        if el._children
-            # wtf? jquery's append doesnt eat a list???
-            for child in el._children
-                el._jquery.append child
-            delete el._children
-        # insert into parent
-        if el.parent._children?
-            el.parent._children.push el._jquery
-        else
-            el.parent._jquery.append el._jquery
-
+        # invoke all delayed jquery work
         if el._jquery_delay?
             for delay in el._jquery_delay
                 delay?()
             delete el._jquery_delay
+        # insert into parent
+        append = ->
+            if el.parent is tpl.xml
+                el.parent._jquery = el.parent._jquery.add(el._jquery)
+            else
+                el.parent._jquery.append(el._jquery)
+        # only when parent is ready
+        if el.parent._jquery?
+            append()
+        else
+            el.parent._jquery_delay ?= []
+            el.parent._jquery_delay.push(append)

         el.on 'newListener', (type) ->
             return if el._events?[type]?.length # dont bind two times for the same type
@@ -35,13 +34,15 @@
                 return # dont return emit result (which is either true or false)

     tpl.on 'text', (el, text) ->
-        callback = ->
-            el._jquery?.text(text)
+        settext = ->
+            el._jquery.text(text)
         # only when tag is ready
         if el._jquery?
-            callback()
+            settext()
         else
-            (el._jquery_delay ?= []).push callback
+            el._jquery_delay ?= []
+            el._jquery_delay.push(settext)
+

     tpl.on 'attr', (el, key, value) ->
         el._jquery?.attr key, value
@@ -53,8 +54,7 @@
         el._jquery?.remove()

     tpl.on 'end', ->
-        tpl.jquery = tpl.xml._jquery = $(tpl.xml._children)
-        delete tpl.xml._children
+        tpl.jquery = tpl.xml._jquery

     old_query = tpl.xml.query
     tpl.xml.query = (type, tag, key) ->


Re-enable auto-open on gulp

Re-enable auto-open on gulp

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -45,7 +45,7 @@
     server:
       baseDir: ["#{dir}"]
     files:  ["#{dir}/**/*.js", "#{dir}/**/*.css", "#{dir}/**/*.html"]
-    open:   false
+    open:   true

 gulp.task 'sync', -> sync_to dest


did not compile ie.js

did not compile ie.js

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -67,6 +67,10 @@
     .pipe plumber.stop()
     .pipe gulp.dest(paths.build)

+  gulp.src ["#{paths.js.base}/ie.js"]
+    .pipe gulpif(production, uglify())
+    .pipe gulp.dest(paths.build)
+
 gulp.task "css", ->
   gulp.src ["./assets/stylesheets/less/index.less", "./assets/stylesheets/less/admin.less"]
     .pipe plumber()


Inject to index.html new JS files.

Inject to index.html new JS files.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -83,11 +83,12 @@
     .pipe gulp.dest paths.dest

 gulp.task 'clean', (done) ->
+  cache.caches = {}
   del [paths.dest], done

 gulp.task 'sass-watch', ['sass'], -> browserSync.reload()
-gulp.task 'coffee-watch', ['coffee'], -> browserSync.reload()
 gulp.task 'jade-watch', ['jade'], -> browserSync.reload()
+gulp.task 'coffee-watch', ['coffee']

 gulp.task 'serve', ->
   browserSync.init
@@ -95,8 +96,12 @@
       baseDir: 'www'

   gulp.watch paths.sass, ['sass-watch']
-  gulp.watch paths.coffee, ['coffee-watch']
   gulp.watch paths.jade, ['jade-watch']
+  gulp.watch paths.coffee, (event) ->
+    if event.type is 'added' or event.type is 'deleted'
+      runSequence 'coffee-watch', 'index'
+    else runSequence 'coffee-watch'
+    browserSync.reload()

 gulp.task 'bowerInstall',  ->
   bower.commands.install()


language_in: 'ECMASCRIPT5'

language_in: 'ECMASCRIPT5'

 IE8 is dead anyway.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -101,16 +101,18 @@
         'goog.style.GET_BOUNDING_CLIENT_RECT_ALWAYS_EXISTS=true'
       ]
       externs: paths.externs
+      language_in: 'ECMASCRIPT5'

 gulp.task 'compile-serverapp', ->
   este.compile paths.js, 'app/server/build',
     compilerPath: paths.compiler
     compilerFlags:
       closure_entry_point: 'server.main'
-      externs: paths.externs.concat este.getNodeJsExterns()
       # NOTE(steida): To have compiled code readable, so we can trace errors.
       debug: true
+      externs: paths.externs.concat este.getNodeJsExterns()
       formatting: 'PRETTY_PRINT'
+      language_in: 'ECMASCRIPT5'

 gulp.task 'concat-all', ->
   este.concatAll


Fix the wrap filter.

Fix the wrap filter.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -54,10 +54,14 @@
         .replace /^.*\/bower_components\//, ''
         .replace /\.js$/, ''
   })
+
+  wrapMatcher = (file) ->
+    pattern = /commonjs-require.*/
+    !file.path.match(pattern)

   code = merge(coffeePipe, gulp.src(source.js))
     .pipe(sourcemaps.init({ loadMaps: true }))
-    .pipe(gulpIf(!/.*commonjs-require.*/, commonWrapper))
+    .pipe(gulpIf(wrapMatcher, commonWrapper))
     .pipe(sourcemaps.write())

   merge(bowerPipe, code)


flash mentions on scroll-to and on append

--- scripts/mentions.coffee
+++ scripts/mentions.coffee
@@ -5,6 +5,12 @@
     at <time class="gg-timestamp">#{timestamp}</time>
   </li>
 '''
+
+flash = (el) ->
+  $(el).css
+    webkitAnimationName: 'fx-flash'
+    webkitAnimationDelay: '200ms'
+    webkitAnimationDuration: '200ms'

 $(window).bind 'adium:message', (event) ->
   message = event.message
@@ -21,6 +27,8 @@
       displayName: message.find('.gg-messageSender').text()
       timestamp: message.find('.gg-messageTimestamp').text()
     $('#mentions .ui-menuContent').append html
+
+    flash message

 $('.gg-mention a').live 'click', (event) ->
   event.preventDefault()
@@ -32,3 +40,10 @@
     duration: 700
     easing: 'swing'
     offset: { top: -height / 3 }
+    onAfter: -> flash selector
+
+$('.mention').live 'webkitAnimationEnd', (event) ->
+  $(this).css
+    webkitAnimationName: ''
+    webkitAnimationDelay: ''
+    webkitAnimationDuration: ''


chore(service): fix internal naming

chore(service): fix internal naming

--- src/service.coffee
+++ src/service.coffee
@@ -137,8 +137,8 @@
     loginPromise = null
     # internal store of buffered messages
     messageQueue = new Queue(messageBuffer)
-    # internal map of deconstructors
-    deconstructors = new SimpleMap()
+    # internal map of callbacks
+    callbackMap = new SimpleMap()

     if enabled and vertxEventBus
       vertxEventBus.onopen = ->
@@ -194,19 +194,19 @@
       registerHandler : (address, callback) ->
         return unless typeof callback is 'function'
         $log.debug("[Vert.x EB Service] Register handler for #{address}") if debugEnabled
-        deconstructor = (message, replyTo) ->
+        callbackWrapper = (message, replyTo) ->
           callback(message, replyTo)
           $rootScope.$digest()
           return #void
-        deconstructor.displayName = "#{CONSTANTS.MODULE}/#{CONSTANTS.COMPONENT}: util.registerHandler (deconstructor)"
-        deconstructors.put(callback, deconstructor)
-        vertxEventBus.registerHandler address, deconstructors.get(callback)
+        callbackWrapper.displayName = "#{CONSTANTS.MODULE}/#{CONSTANTS.COMPONENT}: util.registerHandler (callback wrapper)"
+        callbackMap.put(callback, callbackWrapper)
+        vertxEventBus.registerHandler address, callbackWrapper
       # Remove a callback handler for the specified address match.
       unregisterHandler : (address, callback) ->
         return unless typeof callback is 'function'
         $log.debug("[Vert.x EB Service] Unregister handler for #{address}") if debugEnabled
-        vertxEventBus.unregisterHandler address, deconstructors.get(callback)
-        deconstructors.remove(callback)
+        vertxEventBus.unregisterHandler address, callbackMap.get(callback)
+        callbackMap.remove(callback)
         return #void
       # Send a message to the specified address (using EventBus.send).
       # @param address a required string for the targeting address in the bus


Added FTP Help

Added FTP Help

--- help/ftp.coffee
+++ help/ftp.coffee
@@ -2,5 +2,20 @@
 # # FTP Help
 #
 module.exports = """
-Help Coming Soon
+FTP is not enabled by default, but can be installed with the following command:
+
+  sudo apt-get install pure-ftpd
+
+When prompted for a password, enter your Koding Password.
+
+After PureFTPd is installed, you can connect to this VM by entering the
+following information into your FTP Program:
+
+  Host: ftp.koding.com
+  User: #{userdata.username}@#{userdata.hostname}
+
+All other settings should be left in their defaults in most cases. For
+additional help please see the Koding University at:
+
+  http://learn.koding.com
 """


koding payments: bugfix: remove "wrong" string interpolation delimiters

--- node_modules_koding/koding-payment/lib/main.coffee
+++ node_modules_koding/koding-payment/lib/main.coffee
@@ -471,7 +471,6 @@
       if err or not account?.username
         post 'accounts', xml, callback
       else
-        console.log 'does this ever happen?', xml, callback
         put "accounts/#{accountCode}", xml, callback

   @deleteAccount: (accountCode, callback)->
@@ -520,8 +519,8 @@
         <first_name>#{data.cardFirstName}</first_name>
         <last_name>#{data.cardLastName}</last_name>
         <address1>#{data.address}</address1>
-        #{if data.city then #{"<state>#{data.city}</state>"} else ''}
-        #{if data.state then #{"<state>#{data.state}</state>"} else ''}
+        #{if data.city then "<city>#{data.city}</city>" else ''}
+        #{if data.state then "<state>#{data.state}</state>" else ''}
         <zip>#{data.zip}</zip>
         <country>#{data.country}</country>


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_over.coffee
+++ src/game_over.coffee
@@ -19,6 +19,7 @@

 @name overlay
 @methodOf GameOver#
+@param {
 @event
 ###
 GameOver = (I={}) ->


Added back some shortcuts like PrintC, PrintD and DBPrintC

--- grammars/geck.cson
+++ grammars/geck.cson
@@ -693,7 +693,7 @@
       Con_SetGameSetting|\
       Con_SetINISetting|\
       Con_SetVel|\
-      DebugPrint|\
+      DebugPrint|DBPrintC|\
       DisableControl|\
       DisableKey|\
       EnableControl|\
@@ -833,7 +833,7 @@
       MenuTapKey|\
       Pow|\
       PrintActiveTile|\
-      PrintToConsole|\
+      PrintToConsole|PrintC|\
       ReleaseKey|\
       RemoveScript|\
       RightShift|\
@@ -1081,7 +1081,7 @@
       NumToHex|\
       PickOneOf|\
       Print|\
-      PrintDebug|\
+      PrintDebug|PrintD|\
       QFromAxisAngle|\
       QFromEuler|\
       QInterpolate|\


Fix grammar not loading

Fix grammar not loading

--- grammars/rust.cson
+++ grammars/rust.cson
@@ -618,7 +618,7 @@
       '2': { 'name': 'entity.name.lifetime.rust' }
     }
   }
-
+}
 'patterns': [
   # Comments
   { 'include': '#comments' }


Fix order and orderable by.

Fix order and orderable by.


removing debug line

removing debug line

--- public/angular/directives.coffee
+++ public/angular/directives.coffee
@@ -90,7 +90,6 @@
 						aircraft.infoWindow = new google.maps.InfoWindow
 						  content: code
 						aircraft.icon.on 'click', =>
-							$log.info "click fired"
 							aircraft.infoWindow.open @getMap()

 					if aircraft.shouldTween


hubot: replace spaces by hyphens in scenario name

This allows one to query fleet with more natural sentences.

--- hubot/fleet.coffee
+++ hubot/fleet.coffee
@@ -49,9 +49,12 @@

   fleet_url = process.env.HUBOT_FLEET_URL

-  robot.respond /fleet me (\S+)( to (\S+))?( with (.*))?/i, (msg) ->
+  robot.respond /fleet me (.*?)( to (\S+))?( with (.*))?$/i, (msg) ->

     scenario = msg.match[1]
+      .split(/\ +/)
+      .filter((a) -> a)
+      .join("-")
     args = []
     if msg.match[3]
       args.push('profile=' + encodeURIComponent(msg.match[3]))


fix class names

fix class names

--- imports/charts/Axes.coffee
+++ imports/charts/Axes.coffee
@@ -120,12 +120,12 @@
         padding = 45
       @xLabel =  @plot.container
         .append('g')
-          .attr('class', 'x d3cf-axis-label')
+          .attr('class', 'x scatterPlot-axis-label')
           .attr('transform', "translate(#{@plot.margins.left}, #{@plot.getHeight() + padding})")
         .append('text')
           .attr('dx', (@plot.width / 2) - (@plot.margins.right + @plot.margins.left) / 2)
           .attr('dy', @plot.margins.bottom)
-          .attr('class', 'd3cf-axis-label')
+          .attr('class', 'scatterPlot-axis-label')
           .style('text-anchor', 'middle')
           .text( =>
             @options.x.title || ''
@@ -135,13 +135,13 @@
     if !@yLabel
       @yLabel = @plot.container
         .append('g')
-          .attr('class', 'y d3cf-axis-label')
+          .attr('class', 'y scatterPlot-axis-label')
           .attr('transform', "translate(#{@plot.margins.left}, 0)")
         .append('text')
           .attr('transform', 'rotate(-90)')
           .attr('dx', -(@plot.height / 2) + (@plot.margins.top + @plot.margins.bottom) / 2)
           .attr('dy', -@plot.margins.left)
-          .attr('class', 'd3cf-axis-label')
+          .attr('class', 'scatterPlot-axis-label')
           .style('text-anchor', 'middle')
           .text( =>
             @options.y.title || ''


error handling

error handling

--- src/hubot-cah.coffee
+++ src/hubot-cah.coffee
@@ -199,11 +199,13 @@

 module.exports = (robot) ->
   robot.error (err, res) ->
-    robot.logger.error robot.brain.data.cah
-
     if res?
-      res.reply "Someone broke me again: #{err.message}"
-
+      res.reply "Someone broke me again: #{err.message}\n#{err.stack}\n#{robot.brain.data.cah}"
+    else
+      robot.logger.error err.message
+      robot.logger.error err.stack
+      robot.logger.error robot.brain.data.cah
+
   robot.brain.on "loaded", =>
     if !robot.brain.data.cah
       robot.brain.data.cah = db


add missing requirement

add missing requirement

--- server/lib/proxy.coffee
+++ server/lib/proxy.coffee
@@ -1,3 +1,4 @@
+http = require 'http'
 httpProxy = require 'http-proxy'
 async = require 'async'
 passport = require 'passport'


fix errors for new node versions

fix errors for new node versions

--- src/startup.coffee
+++ src/startup.coffee
@@ -22,8 +22,9 @@
 Config  = require './common/config'

 WriteLog  = (fd, data) =>
-    toLog = '[' + ((do Moment).format 'YYYY MMM DD hh:mm:ssa') + '] ' + data
-    Fs.writeSync fd, toLog, 0, toLog.length
+    if data?
+        toLog = '[' + ((do Moment).format 'YYYY MMM DD hh:mm:ssa') + '] ' + data
+        Fs.writeSync fd, (new Buffer toLog), 0, toLog.length

 processes = []

@@ -33,7 +34,7 @@
 if Config.Voicious.Enabled
     voiciousAccessLog = Fs.openSync (Path.join Config.Paths.Logs, 'voicious.access.log'), 'a+'
     voiciousErrorLog  = Fs.openSync (Path.join Config.Paths.Logs, 'voicious.error.log'), 'a+'
-    voicious          = spawn 'node', [(Path.join Config.Paths.Approot, 'lib', 'core', 'voicious.js')]
+    voicious          = spawn 'node', [(Path.join Config.Paths.Root, 'lib', 'core', 'voicious.js')]
     voicious.stdout.on 'data', (data) =>
         process.stdout.write "#{data}"
         WriteLog voiciousAccessLog, data
@@ -45,7 +46,7 @@
 if Config.Websocket.Enabled
     wsAccessLog = Fs.openSync (Path.join Config.Paths.Logs, 'ws.access.log'), 'a+'
     wsErrorLog  = Fs.openSync (Path.join Config.Paths.Logs, 'ws.error.log'), 'a+'
-    ws          = spawn 'node', [(Path.join Config.Paths.Approot, 'lib', 'ws', 'websocket.js')]
+    ws          = spawn 'node', [(Path.join Config.Paths.Root, 'lib', 'ws', 'websocket.js')]
     ws.stdout.on 'data', (data) =>
         process.stdout.write "#{data}"
         WriteLog wsAccessLog, data


fix download and delete in widget panel

fix download and delete in widget panel

--- firefox/data/content/task.coffee
+++ firefox/data/content/task.coffee
@@ -32,12 +32,12 @@
 		download = document.createElement 'div'
 		download.setAttribute 'class', 'download'
 		download.onclick = ->
-			self.port.emit 'download', page_tasks[@parentNode.parentNode.getAttribute 'task-index']
+			self.port.emit 'download', page_tasks[@parentNode.getAttribute 'task-index']
 		task.appendChild download
 		remove = document.createElement 'div'
 		remove.setAttribute 'class', 'delete'
 		remove.onclick = ->
-			self.port.emit 'delete', parseInt @parentNode.parentNode.getAttribute 'task-id'
+			self.port.emit 'delete', parseInt @parentNode.getAttribute 'task-id'
 		task.appendChild remove
 		tasks_element.appendChild task


Implemented the new Readmill X-Response header

This allows access to the Location header via the response body for browsers
that treat is as an unsafe header. Yes you Chrome and Safari.

--- src/annotator.readmill.coffee
+++ src/annotator.readmill.coffee
@@ -57,16 +57,16 @@
     @error "Unable to fetch user info from Readmill"

   _onCreateReadingSuccess: (body, status, jqXHR) =>
-    location = jqXHR.getResponseHeader "Location"
-    location = location.replace /http:\/\/[^\/]+/, ""
-
-    request = @client.request(url: location, type: "GET")
-    request.then @_onGetReadingSuccess, @_onGetReadingError
+    {location} = JSON.parse jqXHR.responseText
+
+    if location
+      request = @client.request(url: location, type: "GET")
+      request.then @_onGetReadingSuccess, @_onGetReadingError
+    else
+      @_onGetReadingError()

   _onCreateReadingError: (jqXHR) =>
-    if jqXHR.status == 409
-      location = jqXHR.getResponseHeader "Location"
-      @_onCreateReadingSuccess(null, null, jqXHR)
+    @_onCreateReadingSuccess(null, null, jqXHR) if jqXHR.status == 409

   _onGetReadingSuccess: (reading) =>
     @book.reading = reading
@@ -148,6 +148,8 @@
       options.data = jQuery.extend {client_id: @clientId}, options.data or {}

     options.beforeSend = (jqXHR) =>
+      # Set the X-Response header to return the Location header in the body.
+      jqXHR.setRequestHeader "X-Response", "Body"
       jqXHR.setRequestHeader "Accept", "application/json"
       jqXHR.setRequestHeader "Authorization", "OAuth #{@accessToken}" if @accessToken


Add pattern-matching for ".me" headers and footers

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -891,6 +891,21 @@
 				2: {name: "entity.function.name.roff"}
 				3: {name: "variable.parameter.roff", patterns: [include: "#params"]}
 			patterns: [include: "#bold-first"]
+		},{
+
+			# Headers and footers
+			name: "meta.function.${2:/downcase}.me.macro.roff"
+			contentName: "function-call.arguments.roff"
+			begin: "^([.'])[ \t]*(of|oh|he|eh|fo|ef)\\b"
+			end:   "(?<!\\\\)(?=\n)|(?=\\\\\")"
+			beginCaptures:
+				1: {name: "punctuation.definition.macro.roff"}
+				2: {name: "entity.function.name.roff"}
+			patterns: [
+				{include: "#3-part-title"}
+				{include: "#escapes"}
+				{include: "#string"}
+			]
 		}]


Extend inline container.

Extend inline container.

--- grammars/sifu.cson
+++ grammars/sifu.cson
@@ -4052,6 +4052,15 @@
             'include': '#params'
           }
           {
+            'include': '#loadEndpointSetting'
+          }
+          {
+            'include': '#modelDtoSetting'
+          }
+          {
+            'include': '#visible'
+          }
+          {
             'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
             'name': 'invalid.illegal'
           }


Default soft wrap to millionth column

Default soft wrap to millionth column

This is because peer.js cannot encode Infinity
but it should be ideally controlled via a boolean
flag instead of column number.

--- src/app/display-buffer.coffee
+++ src/app/display-buffer.coffee
@@ -9,6 +9,8 @@
 Token = require 'token'
 DisplayBufferMarker = require 'display-buffer-marker'
 Subscriber = require 'subscriber'
+
+DefaultSoftWrapColumn = 1000000

 module.exports =
 class DisplayBuffer
@@ -38,7 +40,7 @@
         deserializer: @constructor.name
         id: @id
         tokenizedBuffer: @tokenizedBuffer.getState()
-        softWrapColumn: softWrapColumn ? Infinity
+        softWrapColumn: softWrapColumn ? DefaultSoftWrapColumn

     @markers = {}
     @foldsByMarkerId = {}


IE9 support added

IE9 support added

--- impls/browser/index.coffee
+++ impls/browser/index.coffee
@@ -1,6 +1,10 @@
 'use strict'

-performance = window.performance or Date
+performance = do ->
+	if window.performance?.now
+		window.performance
+	else
+		Date

 log = console.log


return is data is undefined

return is data is undefined

--- lib/atom-ternjs-reference.coffee
+++ lib/atom-ternjs-reference.coffee
@@ -46,6 +46,7 @@
     cursor = editor.getLastCursor()
     position = cursor.getBufferPosition()
     @manager.client.refs(editor.getURI(), {line: position.row, ch: position.column}).then (data) =>
+      return unless data
       @references = data
       for ref in data.refs
         ref.file = ref.file.replace(/^.\//, '')


fix bug

fix bug

--- lib/carte/client/views/card.cjsx
+++ lib/carte/client/views/card.cjsx
@@ -46,7 +46,7 @@
               </ModalTrigger>

-
+


update

update

--- lib/carte/client/views/list.cjsx
+++ lib/carte/client/views/list.cjsx
@@ -9,7 +9,7 @@

   componentWillReceiveProps: (nextProps)->
     console.log 'List: component will receive props'
-    nextProps.cards.on 'add remove change', @forceUpdate.bind(@, null)
+    nextProps.cards.on 'sync', @forceUpdate.bind(@, null)

   getInitialState: ()->
     searchText: ''


fix total entries style

fix total entries style

--- lib/carte/client/views/list.cjsx
+++ lib/carte/client/views/list.cjsx
@@ -58,7 +58,7 @@

-
+
                 {
                   if @props.cards.pagination
                     @props.cards.pagination.total_entries


Prep Ports for decaf

Prep Ports for decaf

--- src/lib/Ports.coffee
+++ src/lib/Ports.coffee
@@ -10,9 +10,9 @@
 # Ports collection classes for NoFlo components. These are
 # used to hold a set of input or output ports of a component.
 class Ports extends EventEmitter
-  model: InPort
-  constructor: (ports) ->
+  constructor: (ports, model) ->
     super()
+    @model = model
     @ports = {}
     return unless ports
     for name, options of ports
@@ -37,7 +37,7 @@

     @emit 'add', name

-    @ # chainable
+    return @ # chainable

   remove: (name) ->
     throw new Error "Port #{name} not defined" unless @ports[name]
@@ -45,34 +45,45 @@
     delete @[name]
     @emit 'remove', name

-    @ # chainable
+    return @ # chainable

 exports.InPorts = class InPorts extends Ports
+  constructor: (ports) ->
+    super ports, InPort
+
   on: (name, event, callback) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].on event, callback
+    return
   once: (name, event, callback) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].once event, callback
+    return

 exports.OutPorts = class OutPorts extends Ports
-  model: OutPort
+  constructor: (ports) ->
+    super ports, OutPort

   connect: (name, socketId) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].connect socketId
+    return
   beginGroup: (name, group, socketId) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].beginGroup group, socketId
+    return
   send: (name, data, socketId) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].send data, socketId
+    return
   endGroup: (name, socketId) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].endGroup socketId
+    return
   disconnect: (name, socketId) ->
     throw new Error "Port #{name} not available" unless @ports[name]
     @ports[name].disconnect socketId
+    return

 # Port name normalization:
 # returns object containing keys name and index for ports names in


actually reply

actually reply

--- src/uapanfw.coffee
+++ src/uapanfw.coffee
@@ -113,7 +113,7 @@
       #console.log obj
       arr.push "#{obj.type} `#{obj.val}` #{expires.fromNow()}"

-    robot.reply arr.join "\n"
+    msg.reply arr.join "\n"

     logmsg = "#{modulename}: robot responded to #{msg.envelope.user.name}: " +
       "displayed blacklist items and expirations"


handle AutoLaunch path parameter when running in mocha tests

I just cribbed the code that AutoLaunch uses to detect electron/nw.
That way we know that it will behave in exactly the same way.

--- src/ui/util.coffee
+++ src/ui/util.coffee
@@ -192,8 +192,14 @@
         range.text = text
         range.select()

+vesrions = process?.versions
+if versions? and (versions.nw? or versions['node-webkit']? or versions.electron?)
+    autoLaunchPath = undefined
+else
+    autoLaunchPath = process.cwd()
 autoLauncher = new AutoLaunch({
-    name: 'YakYak'
+    name: 'YakYak',
+    path: autoLaunchPath
 });

 module.exports = {nameof, initialsof, nameofconv, linkto, later,


remove path parameter from auto launcher

[The docs](https://www.npmjs.com/package/auto-launch) say that it’s
optional for electron apps.

--- src/ui/util.coffee
+++ src/ui/util.coffee
@@ -193,8 +193,7 @@
         range.select()

 autoLauncher = new AutoLaunch({
-    name: 'YakYak',
-    path: '/Applications/YakYak.app'
+    name: 'YakYak'
 });

 module.exports = {nameof, initialsof, nameofconv, linkto, later,


Update watch task to use variables and new naming scheme

--- grunt/watch.coffee
+++ grunt/watch.coffee
@@ -3,6 +3,6 @@
     livereload: true
   all:
     files: ['assets/**/*', 'stylus/**/*.styl', 'template/**/*.html', 'src/**/*.js', 'bower_components/*/**/*.js', 'bower_components/*/**/*.css']
-    tasks: ['development']
+    tasks: ['build:debug']
   grunt:
     files: ['gruntfile.coffee', 'grunt/*.coffee']