Use the talk-api projects resource for talk project links

--- app/talk/lib/project-linker.cjsx
+++ app/talk/lib/project-linker.cjsx
@@ -1,91 +1,52 @@
 React = require 'react'
-apiClient = require 'panoptes-client/lib/api-client'
+talkClient = require 'panoptes-client/lib/talk-client'
 {Link} = require 'react-router'
 Loading = require '../../components/loading-indicator'
-FEATURED_PRODUCT_IDS = require '../../lib/featured-projects'
-
-take = (n, arr) -> arr.slice(0, n)
-
-filterNonRedirected = (projects) ->
-  projects.filter (p) -> p and (not p.redirect)

 module?.exports = React.createClass
   displayName: 'ProjectLinker'

   getInitialState: ->
     projects: []
-    projectsMeta: {}
+    meta: {}
     loading: true
-    open: false

   componentDidMount: ->
-    @loadMoreProjects().then(@setState.bind(this))
+    @loadMoreProjects()

-  loadMoreProjects: (page = 1, newProjects = [], load = 10) ->
-    apiClient.type('projects').get({
-      launch_approved: true,
-      cards: true
-      page: page,
-      page_size: 20
-    })
-    .then (projects) =>
-      projectsMeta = projects[0]?.getMeta()
-      newProjects = newProjects.concat(filterNonRedirected(projects))
-
-      if (newProjects.length < load) and (projectsMeta.page < projectsMeta.page_count)
-        @loadMoreProjects((page + 1), newProjects)
-      else
-        return {projects: @state.projects.concat(take(load, newProjects)), projectsMeta}
-
-  shouldComponentUpdate: (nextProps, nextState) ->
-    (nextState.projects.length > @state.projects.length) or
-    (nextState.open isnt @state.open) or
-    (nextState.projectsMeta isnt @state.projectsMeta)
+  loadMoreProjects: (page = 1) ->
+    talkClient.type('projects').get(page: page).then (projects) =>
+      meta = projects[0]?.getMeta() or {}
+      projects = @state.projects.concat projects
+      @setState {projects, meta, loading: false}

   projectLink: (project, i) ->
     [owner, name] = project.slug.split('/')

-      {if project.redirect
-        {project.display_name}
-      else
-        <Link to="/projects/#{owner}/#{name}">
-          {project.display_name}
-        </Link>
-        }
+      <Link to="/projects/#{owner}/#{name}/talk">
+        {project.display_name}
+      </Link>

   onClickLoadMore: (e) ->
-    @loadMoreProjects(@state.projectsMeta.next_page).then(@setState.bind(this))
+    @loadMoreProjects @state.meta.next_page

   render: ->

-      <button onClick={=> @setState({open: not @state.open})}>
-        {if @state.open
-           Collapse Projects
-        else
-          Change projects
-          }
-      </button>
-
-      {if @state.open
-        if @state.loading
-          <Loading />
-
+      {if @state.loading
+        <Loading />
+      else

<Link to="/talk">Zooniverse Talk</Link>

{@state.projects?.map(@projectLink)}

-          {if @state.projectsMeta?.page isnt @state.projectsMeta?.page_count
+          {if @state.meta?.next_page
             <button
               type="button"
               onClick={@onClickLoadMore}>
               Load more
-            </button>
-          else
-

-            }
-

-        }
+            </button>}
+
}


Replace scrollX/Y for internet explorer

Replace scrollX/Y for internet explorer

--- app/classifier/subject-annotator.cjsx
+++ app/classifier/subject-annotator.cjsx
@@ -53,10 +53,10 @@
   updateSize: ->
     clientRect = @refs.sizeRect?.getDOMNode().getBoundingClientRect() # Read only
     {left, right, top, bottom, width, height} = clientRect
-    left += scrollX
-    right += scrollX
-    top += scrollY
-    bottom += scrollY
+    left += pageXOffset
+    right += pageXOffset
+    top += pageYOffset
+    bottom += pageYOffset
     @setState sizeRect: {left, right, top, bottom, width, height}

   getScale: ->


Load badge counts async and only if needed

closes:  CNVS-36300

test plan:
this chunk of js shouldn't be included in the common bundle and should
only be loaded if ENV.badge_counts is true and as a seperate chunk

Change-Id: Ia83418cb7604c50ad91c2bf54a4fac79ca381b5a
Reviewed-on: https://gerrit.instructure.com/108447
Tested-by: Jenkins
Reviewed-by: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
Product-Review: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>
QA-Review: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>

--- app/coffeescripts/badge_counts.coffee
+++ app/coffeescripts/badge_counts.coffee
@@ -1,8 +1,10 @@
-define ['jquery'], ($) ->
-  $(document).ready ->
-    if ENV.badge_counts
+if ENV.badge_counts
+  require.ensure [], () ->
+    $ = require('jquery')
+    $ ->
       for type, unread of ENV.badge_counts
         if unread > 0
           type = "grades" if type is "submissions"
           $badge = $("<b/>").text(unread).addClass("nav-badge")
           $("#section-tabs .#{type}").append($badge)
+  , 'badgeCountsAsyncChunk'


S50901 -- Remove toggle(s): WSAPI 2.0

S50901 -- Remove toggle(s): WSAPI 2.0

--- kanban/KanbanAppSpec.coffee
+++ kanban/KanbanAppSpec.coffee
@@ -84,7 +84,18 @@
       addNewHelper = new Helpers.AddNewHelper '.kanban'
       addNewHelper.addWithDetails('foo').then =>
         expect(editorOpenedStub).toHaveBeenCalledOnce()
-        expect(editorOpenedStub.getCall(0).args[1]['c_' + @app.getSetting('groupByField')]).toBe @app.cardboard.getColumns()[0].getValue()
+        expect(editorOpenedStub.getCall(0).args[1][@app.getSetting('groupByField')]).toBe @app.cardboard.getColumns()[0].getValue()
+
+  it 'should set custom group by field to first column value', ->
+    @createApp(
+      groupByField: 'KanbanState'
+    ).then =>
+      editorOpenedStub = @stub(Rally.nav.Manager, 'create')
+      addNewHelper = new Helpers.AddNewHelper '.kanban'
+      addNewHelper.addWithDetails('foo').then =>
+        expect(editorOpenedStub).toHaveBeenCalledOnce()
+        groupByField = "c_#{@app.getSetting('groupByField')}"
+        expect(editorOpenedStub.getCall(0).args[1][groupByField]).toBe @app.cardboard.getColumns()[0].getValue()

   it 'should show correct fields on cards', ->
     @createApp({cardFields: 'Name,Defects,Project'}).then =>


feat(PR): add updated demo links in PR comment

--- scripts/gitter-activity-notifier.coffee
+++ scripts/gitter-activity-notifier.coffee
@@ -169,7 +169,7 @@
                     fbResponse = JSON.parse(body)
                     branchName = fbResponse.head.ref
                     user = fbResponse.user.login
-                    demourl = 'http://fgpv.cloudapp.net/demo/users/' + user + '/' + branchName + '/samples/index-one.html'
+                    demourl = 'http://fgpv.cloudapp.net/demo/users/' + user + '/' + branchName # + '/samples/index-one.html'
                     console.log 'Demo url', demourl, m[2], m[2].indexOf('/fgpv-vpgf')

                     # demo urls are only constructed for fgpv-vpgf repos
@@ -271,7 +271,7 @@
             prDelayParts = store[roomid].prDelay[travisid]
             if prDelayParts
                 parts.push(prDelayParts[0])
-                messages.push(primg + vsprintf('`%1$s` %2$s the "__%4$s__" Pull Request: %3$s#%5$s; [Reviewable %5$s](https://reviewable.io/reviews/%3$s/%5$s); [Demo](%6$s)', prDelayParts))
+                messages.push(primg + vsprintf('`%1$s` %2$s the "__%4$s__" Pull Request: %3$s#%5$s; [Reviewable %5$s](https://reviewable.io/reviews/%3$s/%5$s)', prDelayParts))
                 store[roomid].prDelay[travisid] = undefined # null delayed pr message
             else
                 parts.push('Someone')
@@ -279,13 +279,26 @@
             if parts[2] == 'passed'
                 messages.push(travisOk + vsprintf('Pull Request %1$s#%2$s ([Reviewable %2$s](https://reviewable.io/reviews/%1$s/%2$s)) has __passed__: [Travis %5$s](%4$s)', parts))

-                if prDelayParts[5]
+                if prDelayParts and prDelayParts[5]
                     # add travis id to the delayed parts array to add to the message
                     prDelayParts.push(parts[4]) # parts[4] -> %5$s

                     # add a comment to the pull request with a demo url
                     console.log('PR demo -->', prDelayParts[4], prDelayParts[5], prDelayParts)
-                    glitchpy.comment("fgpv-vpgf/fgpv-vpgf", prDelayParts[4], vsprintf('I updated your PR Demo: [Build #%7$s](%6$s). \r\n - [ ] Is demo working as expected?', prDelayParts))
+
+                    commentString = """
+                                    Hey, I updated your PR Demo (__Build #%7$s__):
+
+                                    | Dev Builds                      | Prod Builds                     |
+                                    | ------------------------------- | ------------------------------- |
+                                    | [index-one.html](%6$s/dev/samples/index-one.html)    | [index-one.html](%6$s/prod/samples/index-one.html)    |
+                                    | [index-fgp-en.html](%6$s/dev/samples/index-fgp-en.html) | [index-fgp-en.html](%6$s/prod/samples/index-fgp-en.html) |
+                                    | [index-fgp-fr.html](%6$s/dev/samples/index-fgp-fr.html) | [index-fgp-fr.html](%6$s/prod/samples/index-fgp-fr.html) |
+
+                                    Is it working as expected?
+                                    """
+
+                    glitchpy.comment("fgpv-vpgf/fgpv-vpgf", prDelayParts[4], vsprintf(commentString, prDelayParts))
             else
                 messages.push(travisBroken + vsprintf('`%6$s` owes muffins now!!! :cake: Pull Request %1$s#%2$s ([Reviewable %2$s](https://reviewable.io/reviews/%1$s/%2$s)) is __broken__: [Travis %5$s](%4$s)', parts))


Add Caching of Ship Detail Models

Add Caching of Ship Detail Models

--- app/assets/javascripts/routers/ships_router.js.coffee
+++ app/assets/javascripts/routers/ships_router.js.coffee
@@ -4,12 +4,27 @@
 		"ships/detail/:id(/)": "detail"
 	index: ->
 		console.log('router.index')
-		view = new SitsApp.Views.ShipsIndex { collection: SitsApp.ships, className: "col-md-12" }
-		$('#shipListRow').html(view.render().$el)
+		indexView = new SitsApp.Views.ShipsIndex { collection: SitsApp.ships, className: "col-md-12" }
+		$('#shipListRow').html(indexView.render().$el)
 	detail: (id) ->
-		view = new SitsApp.Views.ShipsIndex { collection: SitsApp.ships, className: "col-md-12" }
-		$('#shipListRow').html(view.render().$el)
-		SitsApp.currentShip = new SitsApp.Models.ShipDetail({id: id})
+		console.log('router.detail')
+		# copied from index
+		# seems to break when I try to naively cache it. look into this.
+		indexView = new SitsApp.Views.ShipsIndex { collection: SitsApp.ships, className: "col-md-12" }
+		$('#shipListRow').html(indexView.render().$el)
+		# the navigation section
+		SitsApp.loadedShips ?= {}
+		# cache our current ship
+		if SitsApp.currentShip?
+			unless SitsApp.loadedShips[SitsApp.currentShip.get('id')]?
+				console.log('caching ship')
+				SitsApp.loadedShips[SitsApp.currentShip.get('id')] = SitsApp.currentShip
+		if SitsApp.loadedShips[id]?
+			console.log('load from cache')
+			SitsApp.currentShip = SitsApp.loadedShips[id]
+		else
+			console.log('creating new model')
+			SitsApp.currentShip = new SitsApp.Models.ShipDetail({id: id})
 		SitsApp.currentShip.fetch()
 		navView = new SitsApp.Views.ShipDetailNavigation({model: SitsApp.currentShip})
 		$('#navigationRow').html(navView.render().$el)


fixes #112 and #125 reset color adjustments

--- app/assets/js/services/hud_adjustments_service.coffee
+++ app/assets/js/services/hud_adjustments_service.coffee
@@ -55,6 +55,8 @@
   hud.reset_changes = ->
     Theme.json.settings = angular.copy(reset_colors)
     Theme.gcolors = angular.copy(reset_gcolors)
+    original_colors  = angular.copy(Theme.json.settings)
+    original_gcolors = angular.copy(Theme.gcolors)
     @brightness = 0
     @contrast   = 0
     @hue        = 0


Sanity check for synchronous behavior

Sanity check for synchronous behavior

--- app/coffee/modules/packages/comm/rpc/test-unit.coffee
+++ app/coffee/modules/packages/comm/rpc/test-unit.coffee
@@ -18,13 +18,18 @@

 				socket.catchEmit 'rpc://test', (data, fn) -> fn result: 420

+				result = null
+				error = 'invalid'
+
 				promise = rpc.call 'test'
-				promise.then (result) -> expect(result).toBe 420
-				promise.catch (errors) -> expect(true).toBe false
+				promise.then (_) -> result = _
+				promise.catch (_) -> error = _

 				$rootScope.$apply()
+
+				expect(result).toBe 420
+				expect(error).toBe 'invalid'
 		]
-

 	it 'should handle errors gracefully', (done) ->

@@ -35,11 +40,16 @@
 				socket.catchEmit 'rpc://test', (data, fn) ->
 					fn errors: [code: 420]

+				result = 'invalid'
+				error = null
+
 				promise = rpc.call 'test'
-				promise.then (result) -> expect(true).toBe false
-				promise.catch (error) -> expect(error).toBeDefined()
+				promise.then (_) -> result = _
+				promise.catch (_) -> error = _

+				expect(result).toBe 'invalid'
+				expect(error).toBeDefined()
+
 				$rootScope.$apply()
 		]
-


One more change for favicon manager

One more change for favicon manager

It seems that chrome works better with a slightly higher timeout and
when href is changed only in timeout

--- app/utils/favicon-manager.coffee
+++ app/utils/favicon-manager.coffee
@@ -11,16 +11,17 @@
 manager.prototype.setFavicon = (href) ->
   head = @getHeadTag()

-  if oldLink = @getLinkTag()
-    head.removeChild(oldLink)
+  oldLink = @getLinkTag()

   link = @createLinkTag()
   head.appendChild(link)

-  link.setAttribute('href', href)
   setTimeout ->
     link.setAttribute('href', href)
-  , 1
+  , 10
+
+  if oldLink
+    head.removeChild(oldLink)

 manager.prototype.getLinkTag = ->
   links = @getHeadTag().getElementsByTagName('link')


remove unnecessary method

remove unnecessary method

--- app/controllers/subject_viewer.coffee
+++ app/controllers/subject_viewer.coffee
@@ -54,9 +54,6 @@
     @el.attr tabindex: 0
     @setClassification @classification

-  setClassificationCohort: (cohort) =>
-    @classification.cohort = cohort
-
   # delegateEvents: ->
   #   super
   #   doc = $(document)


added stats message controller and implemented it in canary

--- src/canary/canary.coffee
+++ src/canary/canary.coffee
@@ -2,7 +2,7 @@
 async = require 'async'
 request = require 'request'
 debug = (require 'debug')('octoblu-flow-canary:canary')
-Stats = require '../stats/stats'
+StatsMessageController = require '../stats/stats-message-controller'
 SlackMessageController = require '../slack/slack-message-controller'

 class Canary
@@ -29,7 +29,7 @@
     @flows = []
     @Date ?= Date

-    @stats = new Stats {@flows,@Date,@CANARY_UPDATE_INTERVAL,@CANARY_HEALTH_CHECK_MAX_DIFF}
+    @stats = new StatsMessageController {@flows,@Date,@CANARY_UPDATE_INTERVAL,@CANARY_HEALTH_CHECK_MAX_DIFF}
     @slack = new SlackMessageController {@CANARY_UPDATE_INTERVAL,@CANARY_HEALTH_CHECK_MAX_DIFF}

     setInterval @processUpdateInterval, @CANARY_UPDATE_INTERVAL


add selection based building

add selection based building

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -267,6 +267,12 @@
       args: (context) -> [context.filepath]

   NSIS:
+    "Selection Based":
+      command: "makensis"
+      args: (context) ->
+        code = context.getCode()
+        tmpFile = GrammarUtils.createTempFileWithCode(code)
+        [tmpFile]
     "File Based":
       command: "makensis"
       args: (context) -> [context.filepath]


Remove extra blank lines at the end of file

--- workers/social/lib/social/main.coffee
+++ workers/social/lib/social/main.coffee
@@ -158,5 +158,3 @@
     res.send "Socialworker is running with version: #{KONFIG.version}"

   app.listen argv.p
-
-


Firewall: Updated url of countries json file.

--- client/Environments/views/firewall/addfirewallrulemodal.coffee
+++ client/Environments/views/firewall/addfirewallrulemodal.coffee
@@ -131,7 +131,7 @@
   fetchCountries: ->
     $.ajax
       type          : "GET"
-      url           : "https://koding-cdn.s3.amazonaws.com/public/countries.jsonp"
+      url           : "https://koding-cdn.s3.amazonaws.com/public/countries.js"
       dataType      : "jsonp"
       jsonp         : false
       jsonpCallback : "callback"


fix isolated scope issue

fix isolated scope issue

--- src/core/javascripts/controllers/base.js.coffee
+++ src/core/javascripts/controllers/base.js.coffee
@@ -101,6 +101,7 @@
     QuestionService, LocaleService, PurchaseService, $sessionStorage, $bbug, SettingsService) ->
   # dont change the cid as we use it in the app to identify this as the widget
   # root scope
+  console.log "setuip bbctrl"
   $scope.cid = "BBCtrl"
   $scope.controller = "public.controllers.BBCtrl"
   $scope.bb = new BBWidget()


Teams: Stacks: Hilite correct line for tabbed views.

--- client/admin/lib/views/stacks/onboarding/onboardingview.coffee
+++ client/admin/lib/views/stacks/onboarding/onboardingview.coffee
@@ -227,7 +227,13 @@
       line.classList.add 'hilite'  for line in lines

     else if type is 'line'
-      commonSelector.addClass 'hilite'
+      if tabView = @currentPage.tabView
+        if tabView.getActivePaneIndex() is 1
+          commonSelector.last().addClass 'hilite'
+        else
+          commonSelector.first().addClass 'hilite'
+      else
+        commonSelector.addClass 'hilite'

     else if type is 'block'
       commonSelector.prev().nextAll().addClass 'hilite'


change help incident text

change help incident text

--- src/sm-cmds.coffee
+++ src/sm-cmds.coffee
@@ -339,8 +339,7 @@
   ]

   helpIncident = [
-    "Invalid command.",
-    "Here are the all supported commands for Service Manager Incident Management module:",
+    "Please use the following commands to access the Service Manager Incident Management module:",
     "* `sm get incident [ID] (on [sm instance])` - Retrieve the details of an incident by incident ID (e.g. IM10001)",
     "* `sm assign incident [ID] [person] (on [sm instance])` - Assign or reassign an incident to a person ([person] can be an email address, SM username, or Slack username)",
     "* `sm resolve incident [ID] \"[solution]\" (on [sm instance])` - Resolve an incident by providing a solution",


fix double click to open shared widget, after the leave it closed

--- client/app/lib/components/sidebarmachineslistitem/index.coffee
+++ client/app/lib/components/sidebarmachineslistitem/index.coffee
@@ -164,8 +164,8 @@

   renderLeaveSharedMachine: ->
-
-    return null  if @props.activeLeavingSharedMachineId isnt @machine('_id')
+
+    return null  if @state.activeMachine isnt @machine('_id')
     return null  if @machine('type') is 'own'
     return null  unless @machine 'isApproved'


errors via query render a message

errors via query render a message

--- src/desktop/apps/home/client/auth_router.coffee
+++ src/desktop/apps/home/client/auth_router.coffee
@@ -33,7 +33,7 @@
         when 'account-not-found', 'no-user-access-token', 'no-user'
           "We couldn't find your account. Please sign up."
         else
-          error
+          "An unexpected error occurred."
       mediator.trigger 'open:auth',
         mode: 'login'
         intent: 'login'


Bugfix

Bugfix

function should be called in the right context.

--- core/app/backbone/views/fact_relations/add_comment_view.coffee
+++ core/app/backbone/views/fact_relations/add_comment_view.coffee
@@ -15,7 +15,7 @@
   parseKeyUp: (e) ->
     code = e.keyCode || e.which
     switch e.keyCode
-      when 13 then @addModel()
+      when 13 then @addModel.call @

   initializeModel: ->
     @model = new Comment(content: '', created_by: currentUser)


Handle parallelism

Handle parallelism

--- src/coffee/import.coffee
+++ src/coffee/import.coffee
@@ -1,5 +1,5 @@
 _ = require 'underscore'
-chunk = require 'lodash.chunk'
+_.mixin require('underscore-mixins')
 Promise = require 'bluebird'
 {SphereClient, ProductSync, Errors} = require 'sphere-node-sdk'
 {Repeater} = require 'sphere-node-utils'
@@ -64,31 +64,36 @@
           # for rawProduct in rawProducts
           #   products.push @validator.map.mapProduct(rawProduct)
           products = rawProducts.map((p) => @validator.map.mapProduct p)
-          Promise.all(chunk(products, 100).map((ps) => @processProducts(ps)))
+          if _.size(@validator.map.errors) isnt 0
+            Promise.reject @validator.map.errors
+          chunks = _.batchList(products, 20)
+          p = (p) => @processProducts(p)
+          Promise.map(chunks, p, { concurrency: 20 })
           .then((results) => results.reduce((agg, r) => agg.concat(r) []))

   processProducts: (products) ->
-    if _.size(@validator.map.errors) isnt 0
-      Promise.reject @validator.map.errors
-    else
-      console.log "Mapping done. About to process existing product(s) ..."
-      ids = products.map((p) -> "\"#{p.product.id}\"").join(',')
-      @client.productProjections.staged().filter("id:in (#{ids})").fetch()
-      .then (payload) =>
-        existingProducts = payload.body.results
-        console.log "Comparing against #{payload.body.total} existing product(s) ..."
-        @initMatcher existingProducts
-        productsToUpdate =
-        if @validator.updateVariantsOnly
-          @mapVariantsBasedOnSKUs existingProducts, products
-        else
-          products
-        console.log "Processing #{_.size productsToUpdate} product(s) ..."
-        @createOrUpdate(productsToUpdate, @validator.types)
-      .then (result) ->
-        # TODO: resolve with a summary of the import
-        console.log "Finished processing #{_.size result} product(s)"
-        Promise.resolve result
+    console.log "Mapping done. About to process existing product(s) ..."
+    ids = products.map((p) -> "\"#{p.product.id}\"").join(',')
+    @client.productProjections.staged().filter("id:in (#{ids})").fetch()
+    .then (payload) =>
+      existingProducts = payload.body.results
+      console.log "Comparing against #{payload.body.total} existing product(s) ..."
+      @initMatcher existingProducts
+      productsToUpdate =
+      if @validator.updateVariantsOnly
+        @mapVariantsBasedOnSKUs existingProducts, products
+      else
+        products
+      console.log "Processing #{_.size productsToUpdate} product(s) ..."
+      @createOrUpdate(productsToUpdate, @validator.types)
+    .then (result) ->
+      # TODO: resolve with a summary of the import
+      console.log "Finished processing #{_.size result} product(s)"
+      Promise.resolve result
+
+  _createProductFetchBySkuQueryPredicate: (skus) ->
+    skuString = "sku in (\"#{skus.join('", "')}\")"
+    return "masterVariant(#{skuString}) or variants(#{skuString})"

   changeState: (publish = true, remove = false, filterFunction) ->
     @publishProducts = true


implement the sanitize_with_replace codepath as a loop instead of a one-shot (which is what string.prototype.replace does) to make it act like the regexp form.  also debug.level == 1 => print tree out before/after closure conversion

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -3,8 +3,6 @@
 syntax = esprima.Syntax
 debug = require 'debug'
 path = require 'path'
-
-#debug.setLevel if __ejs? then 1 else 0

 { Set } = require 'set'
 { NodeVisitor } = require 'nodevisitor'
@@ -1567,22 +1565,24 @@

                 # we don't need to recurse here since we won't have nested functions at this point
                 n
-
+
+sanitize_with_regexp = (filename) ->
+        filename.replace /[.,-\/\\]/g, "_" # this is insanely inadequate
+
+sanitize_with_replace = (filename) ->
+        replace_all = (str, from, to) ->
+                while (str.indexOf from) > -1
+                        str = str.replace from, to
+                str
+
+        filename = replace_all filename, ".", "_"
+        filename = replace_all filename, ",", "_"
+        filename = replace_all filename, "-", "_"
+        filename = replace_all filename, "/", "_"
+        filename = replace_all filename, "\\", "_"
+
 insert_toplevel_func = (tree, filename) ->
-        sanitize = (filename) ->
-                if __ejs?
-                        filename = filename.replace ".js", ""
-                        filename = filename.replace ".", "_"
-                        filename = filename.replace ",", "_"
-                        filename = filename.replace "-", "_"
-                        filename = filename.replace "/", "_"
-                        filename = filename.replace "\\", "_"
-                        filename
-                else
-                        filename = filename.replace /\.js$/, ""
-                        filename = filename.replace /[.,-\/\\]/g, "_" # this is insanely inadequate
-                        filename
-
+        sanitize = if __ejs? then sanitize_with_replace else sanitize_with_regexp
         toplevel =
                 type: syntax.FunctionDeclaration,
                 id:
@@ -1600,7 +1600,7 @@

 exports.compile = (tree, base_output_filename, source_filename) ->

-        console.warn "compiling #{source_filename}"
+        console.warn "compiling #{source_filename} -> #{base_output_filename}"

         tree = insert_toplevel_func tree, base_output_filename

@@ -1608,14 +1608,14 @@

         toplevel_name = tree.body[0].id.name

-        debug.log "before closure conversion"
-        debug.log -> escodegen.generate tree
+        debug.log 1, "before closure conversion"
+        debug.log 1, -> escodegen.generate tree

         tree = closure_conversion.convert tree, path.basename source_filename

-        debug.log "after closure conversion"
-        debug.log -> escodegen.generate tree
-
+        debug.log 1, "after closure conversion"
+        debug.log 1, -> escodegen.generate tree
+
         module = new llvm.Module "compiled-#{base_output_filename}"

         module.toplevel_name = toplevel_name


Fixed depreciated features, started Linux support

--- lib/d-struct.coffee
+++ lib/d-struct.coffee
@@ -2,14 +2,16 @@
 popen = require('child_process').exec
 platform = require('os').platform

-# TODO: linux support still needs to be added
+# --TODO:-linux-support-still-needs-to-be-added-- Still Working!
 commands =
     build:
         win32: "start cmd /k \"cd #{atom.project.getPaths().shift()} && dub run\""
         darwin: "osascript -e \'tell application \"Terminal\" to do script \"cd #{atom.project.getPaths().shift()}; dub run\"\'"
+        #linux: "bash -c \"cd #{atom.project.getPaths().shift()} && dub run\""
     run:
         win32: "start cmd /k \"cd \"#{atom.project.getPaths().shift()}\" && dub build\""
         darwin: "osascript -e \'tell application \"Terminal\" to do script \"cd #{atom.project.getPaths().shift()}; dub build\"\'"
+        #linux: "bash -c \"cd #{atom.project.getPaths().shift()} && dub build\""

 # Open a terminal and run dub
 dub_build = ->
@@ -24,8 +26,8 @@
 module.exports =
   # Bind workspace command to run_dub
   activate: (state) ->
-    atom.workspaceView.command "d-struct:dub-build", => @dubbuild()
-    atom.workspaceView.command "d-struct:dub-run", => @dubrun()
+    atom.commands.add "atom-workspace", "d-struct:dub-build", => @dubbuild()
+    atom.commands.add "atom-workspace", "d-struct:dub-run", => @dubrun()
   dubbuild: ->
     dub_build()
   dubrun: ->


Create user task gets app config for mongo use

--- server/lib/tasks/create-user.coffee
+++ server/lib/tasks/create-user.coffee
@@ -1,3 +1,4 @@
+require('../../initializers/config').initialize()
 require('../../initializers/mongo')()

 User = require('../../models/user').model


Ensures call stack location object exists before calling methods on it (for coffee-script)

Signed-off-by: Jim Knochelmann <1cd02e31b43620d7c664e038ca42a060d61727b9@airspringsoftware.com>

--- lib/longjohn.coffee
+++ lib/longjohn.coffee
@@ -101,7 +101,7 @@
   Error.captureStackTrace(err, arguments.callee)
   stack = err.stack
   Error.prepareStackTrace = orig
-
+  return "bad call_stack_location" if not (stack[2])
   "#{stack[2].getFunctionName()} (#{stack[2].getFileName()}:#{stack[2].getLineNumber()})"

 wrap_callback = (callback, location) ->


Store siblings during reparenting

Store siblings during reparenting

--- lib/messages.coffee
+++ lib/messages.coffee
@@ -399,6 +399,8 @@

   cmsg = Messages.findOne child
   oldPosition = null
+  oldSiblingsBefore = null
+  oldSiblingsAfter = null
   if oldParent
     oldParentMsg = findMessageParent child
     if oldParentMsg?
@@ -408,6 +410,8 @@
         (position? and position == oldPosition) or
         (not position? and oldPosition == oldParentMsg.children.length-1)
       )  ## no-op
+      oldSiblingsBefore = oldParentMsg.children[...oldPosition]
+      oldSiblingsAfter = oldParentMsg.children[oldPosition+1..]
       Messages.update oldParent,
         $pull: children: child
     else
@@ -446,12 +450,15 @@
       _noLongerRoot child if root?
     _submessagesChanged cmsg.root     ## old root
     _submessagesChanged root ? child  ## new root
+
   doc =
     child: child
     parent: parent
     position: position
     oldParent: oldParent
     oldPosition: oldPosition
+    oldSiblingsBefore: oldSiblingsBefore
+    oldSiblingsAfter: oldSiblingsAfter
   if importing
     #cmsg = Messages.findOne child
     doc.updator = cmsg.creator


Clean up publish methods

Clean up publish methods

--- lib/messages.coffee
+++ lib/messages.coffee
@@ -8,10 +8,16 @@
     if groupRoleCheck group, 'read', Meteor.users.findOne @userId
       Messages.find
         group: group
+    else
+      @ready()

   Meteor.publish 'messages.diff', (message) ->
-    MessagesDiff.find
-      id: message
+    check message, String
+    if groupRoleCheck message2group(message), 'read', Meteor.users.findOne @userId
+      MessagesDiff.find
+        id: message
+    else
+      @ready()

   ## Remove all editors on server start, so that we can restart listeners.
   Messages.find().forEach (message) ->


serve Javascript and config defaults from the gateway server

--- lib/mobwrite.coffee
+++ lib/mobwrite.coffee
@@ -9,6 +9,22 @@
 DAEMON_TIMEOUT_IN_MILLISECONDS = 10*1000
 DEFAULT_DAEMON_HOST = "localhost"
 DEFAULT_DAEMON_PORT = 3017
+DEFAULT_MIN_SYNC_INTERVAL = 250
+DEFAULT_MAX_SYNC_INTERVAL = 1250
+
+MOBWRITE_DEBUG_JAVASCRIPT = """
+    ;(function(){
+      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/diff_match_patch_uncompressed.js"))};
+      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/mobwrite_core.js"))};
+      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/mobwrite_form.js"))};
+    }).call(this);
+    """
+
+MOBWRITE_MINIFIED_JAVASCRIPT = """
+    ;(function(){
+      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/compressed_form.js"))};
+    }).call(this);
+    """

 serve = (options) ->
   port = options?.port or DEFAULT_DAEMON_PORT
@@ -59,14 +75,35 @@
 middleware = (options) ->

   # Start the Python mobwrite daemon.
+  debug = options?.debug?
   logger = options?.logger
   daemonPort = options?.port or DEFAULT_DAEMON_PORT
   daemonHost = options?.host or DEFAULT_DAEMON_HOST
-  root = options?.root or "__mobwrite__"
+  root = options?.root or "mobwrite"
   serve({logger: logger, port: daemonPort, host: daemonHost})

   # Make a pattern that we can match inbound requests for mobwrite middleware.
-  rootPattern = new RegExp("#{root}/([^\/]+)")
+  rootPattern = new RegExp("#{root}/([^\\/\\?]+)")
+
+  # Set up default Javascript configs. These can always be overridden in the
+  # HTML anyway, but setting sane defaults helps.
+  clientOptions =
+    debug: debug
+    syncGateway: "/#{root}/sync"
+    syncInterval: options?.minSyncInterval or DEFAULT_MIN_SYNC_INTERVAL
+    minSyncInterval: options?.minSyncInterval or DEFAULT_MIN_SYNC_INTERVAL
+    maxSyncInterval: options?.maxSyncInterval or DEFAULT_MAX_SYNC_INTERVAL
+  clientJavascript = """
+    ;(function(){
+      #{if debug then MOBWRITE_DEBUG_JAVASCRIPT else MOBWRITE_MINIFIED_JAVASCRIPT}
+      var options = JSON.parse(#{JSON.stringify(JSON.stringify(clientOptions))})
+      for (var key in options) {
+        if (options.hasOwnProperty(key)) {
+          mobwrite[key] = options[key]
+        }
+      }
+    }).call(this);
+    """

   # Create a connect middleware (e.g. for use in ExpressJS).
   # TODO: verify that this works with plain http.createServer()
@@ -74,13 +111,16 @@
   return (req, res, next) ->
     bodyParser req, res, ->

-      # Respond to any requests to the sample q.py/q.php/q.jsp endpoints
-      # by grabbing the "q" or "p" parameters and interacting with the Daemon.
-      # TODO: implement as "special" URLs, and offer JS from here
-      # /__mobwrite__/sync (POST)
-      # /__mobwrite__/client.js (GET)
-      # /__mobwrite__/forms.js (GET)
-      if MOBWRITE_SAMPLE_ENDPOINT_PATTERN.test(req.url) or rootPattern.test(req.url)
+      # Respond to requests for the "mobwrite.js" file.
+      rootPath = rootPattern.exec(req.url)?[1]
+      if rootPath is "mobwrite.js"
+        res.writeHead(200, {"Content-Type": "text/javascript"})
+        res.end(clientJavascript)
+
+      # Respond to any requests to the sync endpoint (or to the typical
+      # mobwrite sample code q.py/q.php/q.jsp endpoints) by grabbing the
+      # "q" (AJAX) or "p" (JSONP) parameters and forwarding them to the Daemon.
+      else if rootPath is "sync" or MOBWRITE_SAMPLE_ENDPOINT_PATTERN.test(req.url)
         clientNeedsJsonp = req.query.p?
         daemonRequest = req.body?.q or req.query.p or "\n"
         daemonResponse = ""
@@ -152,11 +192,7 @@
               font-family: sans-serif;
           }
       </style>
-      <script>
-      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/diff_match_patch_uncompressed.js"))};
-      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/mobwrite_core.js"))};
-      #{fs.readFileSync(path.resolve(MOBWRITE_PATH, "html/mobwrite_form.js"))};
-      </script>
+      <script src="/mobwrite/mobwrite.js"></script>
       </head>
       <body>
           <form id="mobwrite-form" action="" method="post" accept-charset="utf-8">
@@ -180,11 +216,6 @@
               </table>
           </form>
           <script>
-              //mobwrite.syncGateway = location.protocol + '//' + location.host + "/__mobwrite__/";
-              mobwrite.debug = true;
-              mobwrite.syncInterval = 250
-              mobwrite.minSyncInterval = 250
-              mobwrite.maxSyncInterval = 1250
               mobwrite.share('mobwrite-form');
           </script>
       </body>


fix use of not for cs linting

fix use of not for cs linting

--- src/components/demo.cjsx
+++ src/components/demo.cjsx
@@ -79,7 +79,7 @@

     displayFeedbackIconClasses = classnames 'fa',
       'fa-check-square-o': displayFeedback
-      'fa-square-o':  !displayFeedback
+      'fa-square-o':  not displayFeedback

     <ExercisePreview exercise={exercisePreviewStub} displayFeedback={displayFeedback}>
       <button className="feedback-toggle" onClick={@toggleFeedbackDisplay}>


Fixed server initial start error.

Fixed server initial start error.

--- server/services/roms-service.coffee
+++ server/services/roms-service.coffee
@@ -2,6 +2,9 @@
 path = require "path"

 romsDir = path.join __dirname, "..", "roms"
+
+isROM = (fileName) ->
+    fileName[-4..].toLowerCase() is ".nes"

 getROMId = (fileName) ->
     fileName
@@ -24,7 +27,10 @@
         @romList = []
         @romMap = {}

-        for file, i in fs.readdirSync romsDir
+        unless fs.existsSync romsDir
+            fs.mkdirSync romsDir
+
+        for file, i in fs.readdirSync romsDir when isROM file
             id = getROMId file
             name = getROMName file
             @romList[i] = { id: id, name: name, file: file }


update ref to be key

update ref to be key

--- src/components/task-step/ends.cjsx
+++ src/components/task-step/ends.cjsx
@@ -96,7 +96,7 @@
           goToStep={@goToStep}
           onNextStep={@onNextStep}
           review={type}
-          ref={"task-review-#{type}"}
+          key={"task-review-#{type}"}
           focus={type is 'todo'}/>
       </div>


Add RSpec to grammars.coffee

Add RSpec to grammars.coffee

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -15,6 +15,11 @@
   Ruby:
     command: "ruby"
     "Selection Based": (code) -> ['-e', code]
+    "File Based": (filename) -> [filename]
+
+  RSpec:
+    command: "rspec"
+    #"Selection Based": (code) -> []
     "File Based": (filename) -> [filename]

   Perl:


fix(macAutocomplete): Fixed dropdown placement issues

Related to #11

--- src/directives/autocomplete.coffee
+++ src/directives/autocomplete.coffee
@@ -187,6 +187,9 @@

         isMenuAppended = true

+        # Hide the element from view when calculating offset
+        menuEl[0].style.visibility = 'hidden'
+
         if inside
           return $animate.enter(menuEl, undefined, element)
         else
@@ -219,12 +222,8 @@
       Calculate the style include position and width for menu
       ###
       positionMenu = ->
-        parentElement = if inside then element[0] else document.body
-        parentStyles  = window.getComputedStyle parentElement
-
         offset          = element.offset()
-        offset.left    -= parseInt parentStyles.marginLeft
-        offset.top     += element.outerHeight() - parseInt parentStyles.marginTop
+        offset.top     += element.outerHeight()
         offset.minWidth = element.outerWidth()

         # Add 'px' to left and top
@@ -233,6 +232,9 @@
             value = "#{value}px"

           menuEl[0].style[key] = value
+
+        # Show dropdown when positioned correctly
+        menuEl[0].style.visibility = 'visible'

       ###
       @function


actor and adapter's module loading fix

actor and adapter's module loading fix

--- lib/hfactory.coffee
+++ lib/hfactory.coffee
@@ -56,13 +56,13 @@

 newActor = (type, properties) ->
   if not type then throw new Error "actor's type undefined"
-  if not actors[type] then actors[type] = require "#{__dirname}/actor/#{type}"
+  if not actors[type] then actors[type] = require type
   else if typeof actors[type] is "string" then actors[type] = require actors[type]
   new actors[type] properties

 newAdapter = (type, properties) ->
   if not type then throw new Error "adapter's type undefined"
-  if not adapters[type] then adapters[type] = require "#{__dirname}/adapters/#{type}"
+  if not adapters[type] then adapters[type] = require type
   else if typeof adapters[type] is "string" then adapters[type] = require adapters[type]
   new adapters[type] properties

@@ -85,6 +85,28 @@
 scan "#{process.cwd()}/actors", withActor
 scan "#{process.cwd()}/adapters", withAdapter

+actors['hactor'] = require "./actor/hactor"
+actors['hauth'] = require "./actor/hauth"
+actors['hchannel'] = require "./actor/hchannel"
+actors['hdispatcher'] = require "./actor/hdispatcher"
+actors['hgateway'] = require "./actor/hgateway"
+actors['hsession'] = require "./actor/hsession"
+actors['htracker'] = require "./actor/htracker"
+
+adapters['channel_in'] = require "./adapters/channel_in"
+adapters['channel_out'] = require "./adapters/channel_out"
+adapters['fork'] = require "./adapters/fork"
+adapters['http_in'] = require "./adapters/http_in"
+adapters['http_out'] = require "./adapters/http_out"
+adapters['inproc'] = require "./adapters/inproc"
+adapters['lb_socket_in'] = require "./adapters/lb_socket_in"
+adapters['lb_socket_out'] = require "./adapters/lb_socket_out"
+adapters['socket_in'] = require "./adapters/socket_in"
+adapters['socket_out'] = require "./adapters/socket_out"
+adapters['socketIO'] = require "./adapters/socketIO"
+adapters['timerAdapter'] = require "./adapters/timerAdapter"
+adapters['twitter_in'] = require "./adapters/twitter_in"
+

 exports.withActor = withActor
 exports.withAdapter = withAdapter


Reinstate unintentionally deleted code.

Reinstate unintentionally deleted code.

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -6,6 +6,11 @@
   onLoadedCallbacks: []

   init: ->
+    if Utils.isExtensionPage()
+      # On extension pages, we use localStorage (or a copy of it) as the cache.
+      @cache = if Utils.isBackgroundPage() then localStorage else extend {}, localStorage
+      @onLoaded()
+
     chrome.storage.local.get null, (localItems) =>
       localItems = {} if chrome.runtime.lastError
       @storage.get null, (syncedItems) =>


Fix chibug

Fix chibug

--- lib/simulate.coffee
+++ lib/simulate.coffee
@@ -64,7 +64,7 @@
       enemyShip[i - 1].hp[0] -= damage
   if kouku.api_fdam?
     for damage, i in kouku.api_fdam
-      continue if kouku.api_fbak_flag <= 0 && kouku.api_frai_flag <= 0
+      continue if (kouku.api_fbak_flag <= 0 && kouku.api_frai_flag <= 0) || i == 0
       damage = Math.floor(damage)
       dmg = []
       dmg.push damage


Snippet directory name in TextMate packages is case insensitive

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -50,6 +50,9 @@

   loadTextMateSnippets: (bundlePath, done) ->
     snippetsDirPath = path.join(bundlePath, 'Snippets')
+    if not fs.isDirectorySync(snippetsDirPath)
+      snippetsDirPath = path.join(bundlePath, "snippets")
+
     return done() unless fs.isDirectorySync(snippetsDirPath)

     loadSnippetFile = (filename, done) =>


adding mithril static routes

adding mithril static routes

--- lib/mithril.app.coffee
+++ lib/mithril.app.coffee
@@ -1,7 +1,7 @@
 "use strict"

 isNode = typeof window is 'undefined'
-m = if isNode then require('./mithril.js') else window.m
+m = if isNode then require(__dirname + '/mithril.js') else window.m

 if isNode and not global.m
   global.m = m
@@ -374,8 +374,6 @@
             html += newHtml
             cb(html)
           , req, res)
-
-      22
 )


Emit failed event more reliably

Emit failed event more reliably

--- lib/uploader.coffee
+++ lib/uploader.coffee
@@ -26,12 +26,15 @@

     @initiated       = false
     @receivedAllData = false
+    @failed          = false
     @partNumber      = 0
     @parts           = []
     @uploadedParts   = {}
     @partSize        = partSize or 5242880 # 5MB
     @currentChunk    = new Buffer 0

+
+    @on 'error', (err) => @failed = true

     @handleStream stream
     process.nextTick => @initiateTransfer()
@@ -59,6 +62,7 @@
       if @currentChunk.length > @partSize
         @flushPart()

+    stream.on 'error', (err) -> @failed = true
     stream.on 'close', -> console.error 'closed'
     stream.on 'end', =>
       @receivedAllData = true
@@ -147,7 +151,12 @@
       MultipartUpload: Parts: ({'ETag': etag, 'PartNumber': parseInt(partNumber, 10)} for partNumber, etag of @uploadedParts)
     , (err, data) =>
       @emit 'finished', data
-      if err then return @emit 'error', err
+      if err
+        @emit 'error', err
+        @failed = true
+
+      if @failed
+        return @emit 'failed', err
       @emit 'completed', err, location: data.Location, bucket: data.Bucket, key: data.Key, etag: data.ETag, expiration: data.Expiration, versionId: data.VersionId

 module.exports =


fix settings tab title i18n

fix settings tab title i18n

- always tranlate tab title even window.I18N.pref.done is true

--- lib/preferences.coffee
+++ lib/preferences.coffee
@@ -12,8 +12,7 @@
       if item isnt undefined
         if item.uri isnt undefined
           if item.uri.indexOf('atom://config') isnt -1
-            unless window.I18N.pref.done
-              @updateSettings(true)
+            @updateSettings(true)

   @updateSettings: (onSettingsOpen = false) ->
     setTimeout(@delaySettings, 0, onSettingsOpen)
@@ -24,7 +23,7 @@
     return unless settingsTab && settingsEnabled
     try
       settingsTab.querySelector('.title').textContent = @defS.Settings["tab-title"]
-      # BUG re-open setting tab i18n fails
+      return if window.I18N.pref.done

       @sv = document.querySelector('.settings-view')


Changed .css calls to .show() and .hide(). Also used shorter notation for if statement from if mode !=null to if mode?

--- lib/script-view.coffee
+++ lib/script-view.coffee
@@ -50,13 +50,13 @@

   toggleConfigureOptions: (mode=null) ->
-    if mode !=null
+    if mode?
       @configureOptionsToggle = !mode
     if @configureOptionsToggle
-      @customOptionView.css('display', 'none')
+      @customOptionView.hide()
       @configureOptionsToggle = false
     else
-      @customOptionView.css('display', 'block')
+      @customOptionView.show()
       @configureOptionsToggle = true

   saveOptions: =>


Add ^C to kill

Add ^C to kill

--- lib/script-view.coffee
+++ lib/script-view.coffee
@@ -149,8 +149,10 @@
     @bufferedProcess = new BufferedProcess({command, args, options, stdout, stderr, exit})

   stop: ->
-    # Kill existing process
-    @bufferedProcess.kill() if @bufferedProcess? and @bufferedProcess.process?
+    # Kill existing process if available
+    if @bufferedProcess? and @bufferedProcess.process?
+      @display("stdout", "^C")
+      @bufferedProcess.kill()

   display: (css, line) ->
     # For display


server: return only 20 customer entries

server: return only 20 customer entries

--- servers/lib/server/customers.coffee
+++ servers/lib/server/customers.coffee
@@ -33,7 +33,7 @@
     queue    = []
     response = {}

-    usernames.forEach (username)->
+    usernames[0..20].forEach (username)->
       queue.push -> JMachine.fetchByUsername username, (err, machines)->
         return err  if err


Fix of publish typo

Fix of publish typo

--- app/pages/about/acknowledgements.cjsx
+++ app/pages/about/acknowledgements.cjsx
@@ -9,10 +9,10 @@
     Per the [Zooniverse Project Builder Policies](/lab-policies), all research publications using any data derived from Zooniverse approved projects (those listed on the [Zooniverse Projects page](/projects)) are required to acknowledge the Zooniverse and the Project Builder platform. To do so, please use the following text:

     *This publication uses data generated via the [Zooniverse.org](https://www.zooniverse.org/) platform, development of which funded by generous support, including a Global Impact Award from Google, and by a grant from the Alfred P. Sloan Foundation.
-
+
     We ask that all researchers making use of the Zooniverse Project Builder platform in any way also consider including the above acknowledgement in their publications.

-    We strongly encourage project owners to report publish accepted research publications using Zooniverse-produced data to us via [this form](https://docs.google.com/forms/d/e/1FAIpQLSdbAKVT2tGs1WfBqWNrMekFE5lL4ZuMnWlwJuCuNM33QO2ZYg/viewform). You can find a list of publications written using the Zooniverse on our [Publications page](publications).
+    We strongly encourage project owners to report published accepted research publications using Zooniverse-produced data to us via [this form](https://docs.google.com/forms/d/e/1FAIpQLSdbAKVT2tGs1WfBqWNrMekFE5lL4ZuMnWlwJuCuNM33QO2ZYg/viewform). You can find a list of publications written using the Zooniverse on our [Publications page](publications).

     If you have any questions about how to acknowledge the Zooniverse, such as referencing a particular individual or custom code, please [get in touch](contact).
 '''


bar label numbers now acurately reflect changes on timeline move

--- app/assets/javascripts/commit.js.coffee
+++ app/assets/javascripts/commit.js.coffee
@@ -363,8 +363,8 @@
     Repo.chart.selectAll("text.bar-label")
       .text (f) ->
         file = Repo.correct_object(f)
-        return 0 if file is undefined
-        f[3]
+        return "" if file is undefined
+        return file[3]

     Repo.chart.selectAll("rect.deletions")
       .transition(settings.duration)


update

update

--- app/assets/javascripts/common.js.coffee
+++ app/assets/javascripts/common.js.coffee
@@ -4,10 +4,12 @@
 widthIsOver850 = () ->
   $("article, article div, article header, article .image img, article iframe,.thumbnail").width("500")
   $(".linkimg").width("250")
+  $(".linkimg").height("250")
   $("#tags").show("fadein")
 widthIsUnder850 = () ->
   $("article, article div, article header, article .image img, article iframe,.thumbnail").width("310")
   $(".linkimg").width("150")
+  $(".linkimg").height("150")
   $("#tags").hide("fadeout")

 responsiveWindow = ()->


fix(js): add check on ga exist

fix(js): add check on ga exist

--- app/assets/javascripts/common.js.coffee
+++ app/assets/javascripts/common.js.coffee
@@ -27,7 +27,7 @@

   if $('#uuid').length > 0
     uid = document.getElementById('uuid').dataset.userId
-    ga('set', '&uid', uid)
+    ga?('set', '&uid', uid)

   $('input#event_started_at').datetimepicker
     language: 'ru'


reordered households, industry and such

reordered households, industry and such

--- app/assets/javascripts/d3/sankey.coffee
+++ app/assets/javascripts/d3/sankey.coffee
@@ -1,12 +1,12 @@
 D3.sankey =
   data :
     nodes: [
-      {id: 'industry',    column: 0, row: 0},
-      {id: 'other',       column: 0, row: 1},
-      {id: 'households',  column: 0, row: 2},
-      {id: 'agriculture', column: 0, row: 3},
-      {id: 'buildings',   column: 0, row: 4},
-      {id: 'transport',   column: 0, row: 5},
+      {id: 'households',  column: 0, row: 0},
+      {id: 'buildings',   column: 0, row: 1},
+      {id: 'transport',   column: 0, row: 2},
+      {id: 'industry',    column: 0, row: 3},
+      {id: 'agriculture', column: 0, row: 4},
+      {id: 'other',       column: 0, row: 5},
       {id: 'loss',        column: 0, row: 6},

       {id: 'el_prod',     column: 1, row: 1, label: "electricity production"},


Update dashboard example

Update dashboard example

--- app/assets/javascripts/dashboard.coffee
+++ app/assets/javascripts/dashboard.coffee
@@ -11,7 +11,7 @@
       value: 300
       color:"#F7464A"
       highlight: "#FF5A5E"
-      label: "Red"
+      label: "Alimentação - R$300,00"
     },
     {
       value: 50
@@ -28,13 +28,15 @@
   ]

   @options =
-    animation: true
-    animationEasing: "easeOutQuart"
-    showScale: true
-    scaleOverride: false
-    responsive: false
-    maintainAspectRatio: true
-    showTooltips: true
+    segmentShowStroke : true
+    segmentStrokeColor : "#fff"
+    segmentStrokeWidth : 1
+    animationSteps : 100
+    animationEasing : "easeOutBounce"
+    animateRotate : true
+    animateScale : false
+    legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%>
<span style=\"background-color:<%=segments[i].fillColor%>\"><%if(segments[i].label){%><%=segments[i].label%><%}%>
<%}%>
"
+

   if @context
     @pieChart = new Chart(@context).Pie(@data, @options)


:fire: leftover, passing never used argument

--- lib/text-object.coffee
+++ lib/text-object.coffee
@@ -243,7 +243,7 @@
     finder

   getPairInfo: (from) ->
-    finder = @getFinder(from)
+    finder = @getFinder()
     pairInfo = finder.find(from, {@allowForwarding})
     unless pairInfo?
       return null


Update jake loader.load call to match expected arguments.  Stack trace of bug follows:

$ tintan -T

/usr/lib/node_modules/jake/lib/loader.js:93
    _loadJakefile(opts.jakefile);
                      ^
TypeError: Cannot read property 'jakefile' of undefined
    at Loader.load (/usr/lib/node_modules/tintan/node_modules/jake/lib/loader.js:93:23)
    at main (/usr/lib/node_modules/tintan/lib/tintan/main.coffee:72:14)
    at Function.$.main (/usr/lib/node_modules/tintan/lib/tintan.coffee:69:38)
    at Object.<anonymous> (/usr/lib/node_modules/tintan/bin/tintan:8:34)
    at Module._compile (module.js:449:26)
    at Object.Module._extensions..js (module.js:467:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.runMain (module.js:492:10)
    at process.startup.processNextTick.process._tickCallback (node.js:244:9)

--- lib/tintan/main.coffee
+++ lib/tintan/main.coffee
@@ -45,7 +45,7 @@
   boot = require('./boot') Tintan
   if boot.ready()
     loader = new Loader()
-    loader.load(jake.opts.jakefile)
+    loader.load(jake.opts)
   else unless taskNames.length
     taskNames = ['boot:init']


only write once, whoops

only write once, whoops

--- emo.coffee
+++ emo.coffee
@@ -65,7 +65,7 @@
         console.log e
         console.log token

-      if write_needed_flag then @write_store()
+    if write_needed_flag then @write_store()
     return input

   # http://stackoverflow.com/a/1144788/83859


cleanup

cleanup

--- app/assets/javascripts/movies.js.coffee
+++ app/assets/javascripts/movies.js.coffee
@@ -1,3 +0,0 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/


Tune Vegan animation

Tune Vegan animation

--- source/assets/javascripts/app.js.coffee
+++ source/assets/javascripts/app.js.coffee
@@ -57,11 +57,11 @@
       showRoom: '/assets/images/vegan-sans-show-room.svg'
       color: '#ff0'
       preSlide: (show) ->
-        show.select('g#slide-1').attr(transform: 'translate(-'+width+', 0)')
+        show.select('g#slide-1').attr(transform: 'translate(-'+width/2+', 0)')
         show.select('g#slide-2').attr(transform: 'translate(80, '+height+')')

       showSlide: (show) ->
-        show.select('g#slide-1').animate { transform: 'translate(80, 10)' }, 1000, mina.easeout
+        show.select('g#slide-1').animate { transform: 'translate(80, 10)' }, 1000, mina.bounce

       changeSlide: (show) ->
         show.select('g#slide-1').animate { transform: 'translate(80, -'+height+')' }, 750, mina.easein


Forgot a console.log

Forgot a console.log

--- SingularityUI/app/views/request.coffee
+++ SingularityUI/app/views/request.coffee
@@ -193,8 +193,6 @@
                     @render()
                 .done =>
                     @requestModel.fetched = true
-
-                    console.log @requestModel

                     canBeBounced = @requestModel.get('state') in ["ACTIVE", "SYSTEM_COOLDOWN"]
                     canBeBounced = canBeBounced and not @requestModel.get("scheduled")


Fixed problem with sprint stats calculation

--- app/coffee/controllers/dashboard.coffee
+++ app/coffee/controllers/dashboard.coffee
@@ -32,29 +32,22 @@
         _.each $scope.userstoriesList, (us) ->
             totalPoints += pointIdToOrder(us.points)

-        _.each $scope.tasks, (task) ->
-            completedTasks +=1 if $scope.statuses[task.status].is_closed
-
         _.each $scope.usTasks, (statuses, usId) ->
             hasOpenTasks = false
-
-            completedTasks = 0
-            totalTasks = 0
+            hasTasks = false

             _.each statuses, (tasks, statusId) ->
-                totalTasks += tasks.length
-
+                hasTasks = true
                 if $scope.statuses[statusId].is_closed
                     completedTasks += tasks.length
                 else if tasks.length > 0
                     hasOpenTasks = true

-            compledUss += 1 if hasOpenTasks is true
-
-            us = $scope.userstories[usId]
-            points = pointIdToOrder(us.points)
-
-            completedPoints += ((completedTasks * points) / totalTasks) || 0
+            if hasOpenTasks is false and hasTasks is true
+                compledUss += 1
+                us = $scope.userstories[usId]
+                points = pointIdToOrder(us.points)
+                completedPoints += points

         $scope.stats =
             totalPoints: totalPoints


fix manual loader call

fix manual loader call

--- app/coffee/modules/common/loader.coffee
+++ app/coffee/modules/common/loader.coffee
@@ -97,8 +97,6 @@
             startCurrentPageLoader: () ->
                 if config.enabled
                     start()
-                else
-                    pageLoaded(true)

             onStart: (fn) ->
                 $rootscope.$on("loader:start", fn)


Remove console.log

Remove console.log

--- server/lib/_settings.coffee
+++ server/lib/_settings.coffee
@@ -4,8 +4,6 @@
 	if settings.ENV?
 		for key, value of settings.ENV
 			process.env[key] = value
-
-	console.log process.env

 configLoginServices = (settings) ->
 	settings?['login-services']?.forEach (config) ->


update fat arrow, contextType

update fat arrow, contextType

--- src/components/course-settings/remove-teacher.cjsx
+++ src/components/course-settings/remove-teacher.cjsx
@@ -16,8 +16,6 @@
     teacher: React.PropTypes.object.isRequired
     courseRoles: React.PropTypes.array.isRequired
     courseId: React.PropTypes.string.isRequired
-  contextTypes:
-    router: React.PropTypes.func

   isRemovalCurrentTeacher: ->
     role = _.chain(@props.courseRoles)
@@ -26,7 +24,7 @@
       .value()

   goToDashboard: ->
-    TeacherRosterStore.once 'deleted', =>
+    TeacherRosterStore.once 'deleted', ->
       window.location.href = '/dashboard/'

   performDeletion: ->


a little bit more formatting

a little bit more formatting

--- src/components/navbar/server-error-monitoring.cjsx
+++ src/components/navbar/server-error-monitoring.cjsx
@@ -16,10 +16,14 @@
   errorInfo = "#{statusCode} with #{message} for #{request.method} on #{request.url}"

   if request.data?
-    errorInfo += " with #{request.data}"
+    errorInfo += " with\n#{request.data}"

-  template = "Hello!\nI ran into a problem on #{userAgent} at #{location}.
-    Here is some additional info: #{errorInfo}."
+  template = """Hello!
+    I ran into a problem on
+    #{userAgent} at #{location}.
+
+    Here is some additional info:
+    #{errorInfo}."""

 makeContactURL = (supportLinkBase, statusCode, message, request) ->
   q = encodeURIComponent(makeContactMessage(statusCode, message, request))


add back the check for existence

add back the check for existence

--- src/node_modules/round-model/round-model.coffee
+++ src/node_modules/round-model/round-model.coffee
@@ -67,11 +67,13 @@

           contributor = contributors[userId]

-          if contributors
-            if not contributor.contributionCents
-              contributor.contributionCents = contribution.amountCents
-            else
-              contributor.contributionCents += contribution.amountCents
+          if not contributors or not contributor
+            return
+
+          if not contributor.contributionCents
+            contributor.contributionCents = contribution.amountCents
+          else
+            contributor.contributionCents += contribution.amountCents

           contributor.contribution = contributor.contributionCents / 100


Update snippet for newly upgraded javascript bundle

--- src/packages/snippets/spec/snippets-spec.coffee
+++ src/packages/snippets/spec/snippets-spec.coffee
@@ -272,7 +272,7 @@
         expect(snippet.prefix).toBe 'fun'
         expect(snippet.name).toBe 'Function'
         expect(snippet.body).toBe """
-          function function_name (argument) {
+          function function_name(argument) {
           \t// body...
           }
         """


repair test formatters

repair test formatters

--- app/spec/utils/formatters_spec.coffee
+++ app/spec/utils/formatters_spec.coffee
@@ -1,6 +1,17 @@
 describe "Unit Formatters -", ->

   formatters = ledger.formatters
+
+  beforeAll ->
+    ledger.preferences.instance ?= {}
+    ledger.preferences.instance.getLocale = jasmine.createSpyObj('prefs', ['getLocale'])
+    spyOn(ledger.preferences.instance, "getLocale").and.callFake ->
+      "en_GB"
+
+    ###
+    spyOn(formatters, "getBtcUnit").and.callFake ->
+      "BTC"
+    ###

   it "should return a String", ->
     res = formatters.formatUnit(1000, 'BTC', -1)


Hide keyboard upon site selection on iOS.

--- src/ui.coffee
+++ src/ui.coffee
@@ -139,14 +139,14 @@
 lastInputTime = new Date(1970, 1, 1)
 delayTime = 500

-delay_call = (cb) ->
+delay_call = (cb, delay = delayTime) ->
 	triggerTime = lastInputTime = new Date().getTime()
 	setTimeout(
 		->
 			if triggerTime == lastInputTime
 				cb()
 				return
-		, delayTime)
+		, delay)
 	return

 exports.site_update = site_update = ->
@@ -233,7 +233,15 @@
 			updater: (item) ->
 				console.log "#{item} selected"
 				site_update()
-				load_site_options gen_passwd
+
+				# Must use delay_call to
+				# 1. make blur take effect os iOS
+				# 2. make sure gen_passwd get the selected item
+				delay_call ->
+					load_site_options ->
+						$('#site').blur() if is_ios?
+						gen_passwd()
+					, 10
 				item
 		}
 		return


Add compatible argument to outdated command

--- src/upgrade.coffee
+++ src/upgrade.coffee
@@ -37,6 +37,7 @@
     options.alias('h', 'help').describe('help', 'Print this usage message')
     options.alias('l', 'list').boolean('list').describe('list', 'List but don\'t install the outdated packages')
     options.boolean('json').describe('json', 'Output outdated packages as a JSON array')
+    options.string('compatible').describe('compatible', 'Only list packages/themes compatible with this Atom version')

   getInstalledPackages: ->
     packages = []
@@ -52,11 +53,16 @@
       metadata = JSON.parse(fs.readFileSync(path.join(packageDirectory, 'package.json')))
       return metadata if metadata?.name and metadata?.version

-  loadInstalledAtomVersion: (callback) ->
-    config.getResourcePath (resourcePath) =>
-      try
-        @installedAtomVersion = JSON.parse(fs.readFileSync(path.join(resourcePath, 'package.json')))?.version
-      callback()
+  loadInstalledAtomVersion: (options, callback) ->
+    if options.argv.compatible
+      process.nextTick =>
+        @installedAtomVersion = options.argv.compatible if semver.valid(options.argv.compatible)
+        callback()
+    else
+      config.getResourcePath (resourcePath) =>
+        try
+          @installedAtomVersion = JSON.parse(fs.readFileSync(path.join(resourcePath, 'package.json')))?.version
+        callback()

   getLatestVersion: (pack, callback) ->
     requestSettings =
@@ -121,7 +127,7 @@
     options = @parseOptions(options.commandArgs)
     options.command = command

-    @loadInstalledAtomVersion =>
+    @loadInstalledAtomVersion options, =>
       if @installedAtomVersion
         @upgradePackages(options, callback)
       else


Test for the .text-subtle class

Test for the .text-subtle class

--- spec/installed-package-view-spec.coffee
+++ spec/installed-package-view-spec.coffee
@@ -92,7 +92,7 @@
         expect(card.refs.keybindingToggle.checked).toBe false
         expect(_.include(atom.config.get('core.packagesWithKeymapsDisabled') ? [], 'language-test')).toBe true

-        keybindingRows = card.element.querySelectorAll('.package-keymap-table tbody tr')
+        keybindingRows = card.element.querySelectorAll('.package-keymap-table tbody.text-subtle tr')
         expect(keybindingRows.length).toBe 1

         card.refs.keybindingToggle.click()


added namespace alias support on use clauses and fixed minor unhandled exception

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -157,11 +157,12 @@

         currentMethodParams = @getMethodParams(editor,bufferPosition)

-        for param in currentMethodParams
-            if prefix.indexOf(param.varName) == 0
-                unless param.objectType is undefined
-                    regex = "\\$#{param.varName.substr(1)}\\-\\>"
-                    return if prefix.match(regex) then param.objectType else false
+        unless currentMethodParams is undefined
+            for param in currentMethodParams
+                if prefix.indexOf(param.varName) == 0
+                    unless param.objectType is undefined
+                        regex = "\\$#{param.varName.substr(1)}\\-\\>"
+                        return if prefix.match(regex) then param.objectType else false

     getMethodParams: (editor,bufferPosition) ->

@@ -195,7 +196,8 @@
                 fullMethodString = inline.reverse().reduce (previous,current) ->
                     previous.trim()+current.trim()

-                return fullMethodString.match(fullMethodRegex)[0]
+                if m = fullMethodString.match(fullMethodRegex)
+                    return m[0]

          return ''

@@ -214,11 +216,16 @@
             if matches = line.match(regex)
                 isValid = matches[1].split('\\').map(
                     (item) ->
-                        item.split(';')[0].split(' as ')[0] == objectType
+                        l = item.split(';')[0].split(' as ')
+                        if l.length == 1
+                            l[0] == objectType
+                        else if l.length == 2
+                            l[0] == objectType or l[1] == objectType
+
                 ).filter(
                     (item) -> item == true
                 )
-                console.log isValid, objectType, matches[1].match(objectType)
+                # console.log isValid, objectType, matches[1].match(objectType)
                 if isValid.length > 0
                     return @fetchAndResolveDependencies(matches[1].match(objectType),prefix,resolve)

@@ -234,7 +241,7 @@
         script = @getScript()
         autoload = @getAutoloadPath()

-        console.log namespace, script, autoload
+        # console.log namespace, script, autoload

         process = proc.spawn "php", [script, autoload, namespace]

@@ -251,7 +258,7 @@
         process.on 'close', (code) =>
             try
                 @availableResources = JSON.parse(@compiled)
-                console.log @availableResources
+                # console.log @availableResources

                 completions = []

@@ -270,7 +277,6 @@
         __dirname + '/../scripts/main.php'

     parseNamespace: (lastMatch) ->
-        console.log lastMatch
         if typeof lastMatch is 'string'
             return lastMatch
         lastMatch.input.substring(1,lastMatch.input.length - 1).split(' as ')[0]


Add the user agent, in hopes that it will work

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -61,6 +61,8 @@
       @request
         method: 'POST'
         url: "https://www.google-analytics.com/collect"
+        headers:
+          'User-Agent': navigator.userAgent
         qs: params

     # Private


Sanitize <input> to also be disabled

Sanitize <input> to also be disabled

--- lib/sanitize.coffee
+++ lib/sanitize.coffee
@@ -123,10 +123,11 @@
 cssCommentRegex = /\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\//g

 sanitizeHtml.defaults.transformTags =
-  'input': (tagName, attribs) ->
-    attribs.type = 'checkbox'
-    tagName: tagName
-    attribs: attribs
+  ## Force all <input>s to have type="checkbox" and be disabled
+  'input': sanitizeHtml.simpleTransform 'input',
+    type: 'checkbox'
+    disabled: true
+
   '*': (tagName, attribs) ->
     ## We used to always forbid position:absolute, but KaTeX needs them
     ## (see e.g. `\not`).  But we do need to forbid position:fixed, because


clearly log git result

clearly log git result

--- src/tf.coffee
+++ src/tf.coffee
@@ -79,4 +79,9 @@
     fp = basepath + "/" + fn

     exec "GIT_SSH_COMMAND='ssh -i #{fp} -F /dev/null -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' git clone #{url} #{fp}", (error, stdout, stderr) ->
-      msg.send {room: msg.message.user.name}, "```\n#{stdout}\n```"
+      if error
+        msg.send {room: msg.message.user.name}, "Error: #{error}"
+      if stderr
+        msg.send {room: msg.message.user.name}, "stderr:\n```\n#{stderr}\n```"
+      if stdout
+        msg.send {room: msg.message.user.name}, "stdout:\n```\n#{stdout}\n```"


Reduce support for old browser

Reduce support for old browser

--- app/javascript/src/legacy/common.coffee
+++ app/javascript/src/legacy/common.coffee
@@ -892,23 +892,6 @@
       return 'error'
   return

-### Chrome 10/WebKit braindamage; stop breaking things intentionally just to create
-# busywork for everyone else:
-###
-
-if !('URL' of window) and 'webkitURL' of window
-  window.URL = window.webkitURL
-
-### For Chrome 9: ###
-
-if 'createObjectURL' of window and !('URL' of window)
-  window.URL =
-    createObjectURL: (blob) ->
-      window.createObjectURL blob
-    revokeObjectURL: (url) ->
-      window.revokeObjectURL url
-      return
-
 ### Allow CSS styles for WebKit. ###

 if navigator.userAgent.indexOf('AppleWebKit/') != -1


Update description of config option

Update description of config option

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -103,7 +103,7 @@
     description: """
     Almost equivalent to `startofline` pure-Vim option. When true, move cursor to first char.
     Affects to `ctrl-f, b, d, u`, `G`, `H`, `M`, `L`, `gg`
-    But unlike pure-Vim `d`, `<<`, `>>` is not affected by this option, use independent `stayOn` options.
+    Unlike pure-Vim, `d`, `<<`, `>>` are not affected by this option, use independent `stayOn` options.
     """
   flashOnUndoRedo: true
   flashOnOperate: true


return error if error

return error if error

--- app/models/forgot-password-model.coffee
+++ app/models/forgot-password-model.coffee
@@ -16,7 +16,8 @@
   forgot :(email, callback=->) =>
     debug "looks like #{email} forgot their password."
     @findSigned "#{@uuid}.id" : email, (error, device) =>
-      return callback new Error('Device not found for email address') if error? or !device?
+      return callback error if error?
+      return callback new Error('Device not found for email address') unless device?
       debug "found device #{JSON.stringify(device)}"
       resetToken = @uuidGenerator.v4()


Use charWidth/lineHeight from editorView not editor

--- lib/bracket-matcher-view.coffee
+++ lib/bracket-matcher-view.coffee
@@ -85,8 +85,8 @@
     element.style.display = 'block'
     element.style.top = "#{pixelPosition.top}px"
     element.style.left = "#{pixelPosition.left}px"
-    element.style.width = "#{@editor.charWidth}px"
-    element.style.height = "#{@editor.lineHeight}px"
+    element.style.width = "#{@editorView.charWidth}px"
+    element.style.height = "#{@editorView.lineHeight}px"

   moveHighlightViews: (bufferRange) ->
     {start, end} = Range.fromObject(bufferRange)


blur replaces keyup

blur replaces keyup

--- lib/client/autoform-file.coffee
+++ lib/client/autoform-file.coffee
@@ -54,7 +54,7 @@
   update(t)

 update = (t) ->
-  $(t.find('.js-value')).keyup()
+  $(t.find('.js-value')).blur()
   $(t.find('.js-value')).trigger('change')

 makeThatImage = (f, t, e) ->


Use atom watchPath

Use atom watchPath

https://flight-manual.atom.io/api/v1.45.0/PathWatcher/

--- lib/git-diff-staged-view.coffee
+++ lib/git-diff-staged-view.coffee
@@ -1,4 +1,4 @@
-fs = require 'fs'
+{watchPath} = require('atom')
 {join} = require 'path'
 {Directory, CompositeDisposable} = require 'atom'
 {repositoryForPath} = require './helpers'
@@ -21,13 +21,11 @@
     @subscriptions = new CompositeDisposable()
     @decorations = {}
     @markers = []
-    @indexWatch = null
     @timeoutId = @repository = @editor = null

   dispose: =>
     @cancelUpdate()
     @removeDecorations()
-    @indexWatch?.close()
     @subscriptions?.dispose()
     @reset()

@@ -54,13 +52,15 @@
       @addIndexWatch()

   addIndexWatch: ->
-    @indexWatch?.close()
-    @indexWatch = fs.watch join(@repository.getPath(), 'index'), =>
-      # atom/git-utils Repository does not always detect index changes
-      # ... let others know (e.g. tree-view)
-      @repository?.refreshStatus()
-      @scheduleUpdate()
-      @addIndexWatch()
+    return unless @repository
+    indexFile = join(@repository.getPath(), 'index.lock')
+    promise = watchPath @repository.getPath(), {}, (events)=>
+      for e in events when e.path is indexFile
+        @scheduleUpdate()
+        break
+      return
+    promise.then (disposable)=>
+      @subscriptions.add disposable

   cancelUpdate: ->
     clearTimeout(@timeoutId)


Fix mounting hole symbol

Fix mounting hole symbol

--- src/symbol/default/mounting-hole.coffee
+++ src/symbol/default/mounting-hole.coffee
@@ -33,6 +33,6 @@
       passive: true
     .lineWidth settings.lineWidth.thick
     .circle 0, 0, r, settings.fill
-    .circle 0, 0, r - d, settings.fill
+    .circle 0, 0, r - d, 'none'

   [2*r, 2*r]


fixed missing time axis grids

fixed missing time axis grids

--- src/viz/types/helpers/graph/includes/svg.coffee
+++ src/viz/types/helpers/graph/includes/svg.coffee
@@ -237,7 +237,8 @@
     grid.enter().append "g"
       .attr "id", "d3plus_graph_"+axis+"grid"
     lines = grid.selectAll("line")
-      .data gridData, (d) -> d
+      .data gridData, (d, i) ->
+        if d.constructor is Date then d.getTime() else d
     lines.transition().duration vars.draw.timing
       .call tickPosition, axis
       .call tickStyle, axis, true


Update atom config

Update atom config

--- link/.atom/config.cson
+++ link/.atom/config.cson
@@ -6,16 +6,14 @@
   "atom-beautify":
     _analyticsUserId: "824852c3-cab2-4571-b79a-150f9e541808"
   editor:
-    fontSize: 12
     preferredLineLength: 120
     useShadowDOM: true
-    invisibles:
-      {}
+    invisibles: {}
     zoomFontWhenCtrlScrolling: true
     showIndentGuide: true
+    fontSize: 13
   core:
     disabledPackages: [
-      "background-tips"
       "bookmarks"
       "deprecation-cop"
       "incompatible-packages"
@@ -31,31 +29,28 @@
       "language-ruby-on-rails"
       "language-sass"
       "language-toml"
-      "language-yaml"
-      "markdown-preview"
       "metrics"
-      "open-on-github"
       "package-generator"
-      "release-notes"
       "spell-check"
       "styleguide"
       "welcome"
-      "whitespace"
-      "wrap-guide"
     ]
     themes: [
       "seti-ui"
       "one-dark-syntax"
     ]
-  linter:
-    {}
+  linter: {}
   "vim-mode":
     useClipboardAsDefaultRegister: true
-  "linter-eslint":
-    {}
+  "linter-eslint": {}
+  "tree-view":
+    hideIgnoredNames: true
+    hideVcsIgnoredFiles: true
+  minimap:
+    absoluteMode: true
+".ini.source":
+  editor:
+    preferredLineLength: 120
 ".source.ssh-config":
   editor:
     preferredLineLength: 120
-".ini.source":
-  editor:
-    preferredLineLength: 120


Sidebar: do not list unshared workspaces of host

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -443,7 +443,10 @@
           title    = "#{workspace.name}"

           unless isMyMachine
-            ideRoute = "#{ideRoute}/#{machineOwner}"
+            if channelId = workspace.channelId
+            then ideRoute = "/IDE/#{channelId}"
+            else
+              return

           unless workspace.isDefault
             title += ""


LogsListController: simplify request handling

--- client/admin/lib/views/logs/logslistcontroller.coffee
+++ client/admin/lib/views/logs/logslistcontroller.coffee
@@ -24,13 +24,9 @@

     @isFetching = yes

-    @fetchLogsFromAPI options, (err, res) =>
-
+    @fetchLogsFromAPI options, (err, logs) =>
       return  if showError err
-
-      { data: { logs } } = res
       @listLogs logs
-
       @isFetching = no

@@ -50,7 +46,13 @@
       endPoint = "#{endPoint}?#{args.join ','}"

     doXhrRequest { endPoint, type }, (err, res) ->
-      callback err, res
+
+      return callback err  if err
+
+      { data: { logs } } = res
+      logs.reverse()
+
+      callback null, logs

   listLogs: (logs) ->


Client: Activity: Updated InfiniteScroll component for scrolling bottom at first and when message added.

--- client/app/lib/components/infinitescroll/index.coffee
+++ client/app/lib/components/infinitescroll/index.coffee
@@ -8,10 +8,15 @@
   @defaultProps =
     isDataLoading   : no
     scrollDirection : 'up'
-    scrollOffset    : 200
+    scrollOffset    : 5
+    isScrollBottom  : yes
+
+
+  shouldScrollBottomAtFirst: yes

   onScroll: (event) ->
+
     isScrollLoadable = isScrollThresholdReached
       el              : event.target
       isDataLoading   : @props.isDataLoading
@@ -22,8 +27,31 @@
     @props.onScrollThresholdReached() if isScrollLoadable

+  componentWillUpdate: ->
+
+    InfiniteScroll = React.findDOMNode(@refs.InfiniteScroll)
+    @scrollTop     = InfiniteScroll.scrollTop
+    @offsetHeight  = InfiniteScroll.offsetHeight
+    @scrollHeight  = InfiniteScroll.scrollHeight
+    @shouldScrollBottom = (@scrollTop + InfiniteScroll.offsetHeight) is @scrollHeight
+
+
+  componentDidUpdate: ->
+
+    if @shouldScrollBottom
+      InfiniteScroll = React.findDOMNode(@refs.InfiniteScroll)
+      InfiniteScroll.scrollTop = InfiniteScroll.scrollHeight
+    else
+      InfiniteScroll.scrollTop = @scrollTop + (InfiniteScroll.scrollHeight - @scrollHeight)
+
+    kd.utils.wait 373, =>
+      if @shouldScrollBottomAtFirst and @offsetHeight
+        InfiniteScroll.scrollTop = InfiniteScroll.scrollHeight
+        @shouldScrollBottomAtFirst = no
+
+
   render: ->
-

+

       {@props.children}


postgres testing

postgres testing

--- application/controllers/mytravel.coffee
+++ application/controllers/mytravel.coffee
@@ -15,7 +15,7 @@
 #
 {APPPATH, BASEPATH, ENVIRONMENT, EXT, FCPATH, SYSDIR, WEBROOT} = require(process.cwd() + '/index')
 {Exspresso, config_item, get_config, is_loaded, load_class, load_new, load_object, log_message} = require(BASEPATH + 'core/Common')
-{SELECT, FROM, WHERE, LIKE, LIMIT, OFFSET, GO} = require(FCPATH+'lib/sql')
+{DISTINCT, FROM, GO, INNER, INSERT, INTO, IS, JOIN, LEFT, LIKE, LIMIT, OFFSET, ON, ORDER_BY, OUTER, RIGHT, SELECT, SET, UPDATE, VALUES, WHERE} = require(FCPATH + 'lib/sql.dsl')

 CI_Controller   = require(BASEPATH + 'core/Controller') # Exspresso Controller Base Class


fix lint

fix lint

--- js/src/service/SharingClient.coffee
+++ js/src/service/SharingClient.coffee
@@ -100,7 +100,7 @@
         return Promise.resolve()

       Promise.resolve()
-      .then =>
+      .then ->
         validateId(id)
         validateUsernames(usernames)

@@ -109,7 +109,7 @@
         userKeys    = usernamesToKeys(usernames, realm)

         revocationRequest = new RevocationRequest { id, userKeys }
-      .then ->
+      .then =>
         @sharingApi.revokeObject(revocationRequest)
       .then ->
         log.info('revoked access', revocationRequest)


Fixed X-OpenHIM-TransactionID Header

Fixed X-OpenHIM-TransactionID Header

--- src/middleware/messageStore.coffee
+++ src/middleware/messageStore.coffee
@@ -1,5 +1,6 @@
 transactions = require "../model/transactions"
 logger = require "winston"
+Q = require "q"

 transactionStatus =
 	PROCESSING: 'Processing'
@@ -97,7 +98,10 @@
 		return done()

 exports.koaMiddleware =  `function *storeMiddleware(next) {
-		exports.storeTransaction(this, function(){});
-		yield next;
+		var saveTransaction = Q.denodeify(exports.storeTransaction);
+		yield saveTransaction(this);
+		if (this.transactionId){
+			yield next;
+		}
 		exports.storeResponse(this, function(){});
 	}`


Messages#show - Depending on type of message, different initial view is shown

--- app/assets/javascripts/admin/views/messages/show.js.coffee
+++ app/assets/javascripts/admin/views/messages/show.js.coffee
@@ -4,8 +4,14 @@

   render: ->
     @$el.html JST["admin/templates/messages/show"](model: @model)
-    @$el.find('#detail-view').html JST["admin/templates/messages/_notifications"](model: @model)
+    @showInitialSubView()
     @
+
+  showInitialSubView: ->
+    switch @model.get('queue_name')
+      when 'accepted' then @$el.find('#detail-view').html JST["admin/templates/messages/_payload"](model: @model)
+      when 'archived' then @$el.find('#detail-view').html JST["admin/templates/messages/_result"](model: @model)
+      when 'incoming' then @$el.find('#detail-view').html JST["admin/templates/messages/_children"](model: @model)

   showSubView: (e) ->
     templateName = $(e.currentTarget).data('template')


Use Event.currentTarget to get the toggle element

--- lib/notification-element.coffee
+++ lib/notification-element.coffee
@@ -76,7 +76,7 @@
         addSplitLinesToContainer(stackContainer, stack)

         stackToggle.addEventListener 'click', (e) => @handleStackTraceToggleClick(e, stackContainer)
-        @handleStackTraceToggleClick({target: stackToggle}, stackContainer)
+        @handleStackTraceToggleClick({currentTarget: stackToggle}, stackContainer)

     if @model.isDismissable()
       closeButton = @querySelector('.close')
@@ -173,10 +173,10 @@
   handleStackTraceToggleClick: (e, container) ->
     e.preventDefault?()
     if container.style.display is 'none'
-      e.target.innerHTML = 'Hide Stack Trace'
+      e.currentTarget.innerHTML = 'Hide Stack Trace'
       container.style.display = 'block'
     else
-      e.target.innerHTML = 'Show Stack Trace'
+      e.currentTarget.innerHTML = 'Show Stack Trace'
       container.style.display = 'none'

   autohide: ->


Make sorting handle nulls somewhat sensibly

--- lib/pg-hoff-results-view.coffee
+++ lib/pg-hoff-results-view.coffee
@@ -16,7 +16,12 @@
     resultsets: []

     getCompare: (typeName, asc, colIdx) ->
-        defaultCompare = (left, right) -> +(left > right) || - (right > left)
+        defaultCompare = (left, right) ->
+            switch
+                when left is null and right is null then 0
+                when left is null then 1
+                when right is null then -1
+                else +(left > right) || - (right > left)
         compare = Type[typeName]?.compare || defaultCompare
         (left, right) -> compare(left[colIdx], right[colIdx]) * if asc then 1 else -1 ? 0


Key bindings; fix exit help page.

Key bindings; fix exit help page.

--- pages/help_dialog.coffee
+++ pages/help_dialog.coffee
@@ -48,7 +48,13 @@
           chrome.runtime.sendMessage handler: "copyToClipboard", data: commandName
           HUD.showForDuration("Yanked #{commandName}.", 2000)

-  hide: -> UIComponentServer.postMessage "hide"
+    @exitOnEscape = new Mode exitOnEscape: true
+    @exitOnEscape.onExit (event) =>
+      HelpDialog.hide() if event?.type == "keydown" and KeyboardUtils.isEscape event
+
+  hide: ->
+    @exitOnEscape.exit()
+    UIComponentServer.postMessage "hide"

   toggle: (html) ->
     if @showing then @hide() else @show html


fix ServerClient

fix ServerClient

--- app/templates/app/scripts/coffee/utils/ServerClient.coffee
+++ app/templates/app/scripts/coffee/utils/ServerClient.coffee
@@ -43,13 +43,16 @@
       options.stub = null
       $.ajax(options)
         .done (data)->
-          async.resolve data
+          unless data.result is "error"
+            async.resolve data
+          else
+            async.reject data
         .fail (err)->
           async.reject err
         .always =>
           @lock.unlock url, lockname

-    ajax:(options,{stub,server})->
+    ajax:(options)->
       async = $.Deferred()
       options or options = {}

@@ -62,15 +65,12 @@
           @_ajax options, async
       async.promise()

-    get:(options,stub)->
+    get:(options)->
       options or options = {}
       options.type = "GET"
-      @ajax options, stub
+      @ajax options

-    post:(options,stub)->
+    post:(options)->
       options or options = {}
       options.type = "POST"
-      @ajax options, stub
-
-
-
+      @ajax options


Fix: delete action on reposts deletes the repost, not the original

--- lib/assets/javascripts/views/post/post_action_delete.js.coffee
+++ lib/assets/javascripts/views/post/post_action_delete.js.coffee
@@ -3,7 +3,8 @@

   postView: => @parentView()

-  post: => @postView()?.post()
+  post: =>
+    @postView()?.parentPost?() || @postView()?.post()

   showErrors: (error) =>
     alert(_.map(error, (e) -> e.text).join("\n"))


Remove error handling

Remove error handling

--- app.coffee
+++ app.coffee
@@ -52,9 +52,9 @@
     return res.send(404) unless file
     return res.send(file.content, {"Content-Type": file.mime})

-app.error (err, req, res, next) ->
-  body = {}
-  if err.message then body.message = err.message
-  if err.errors then body.errors = err.errors
+#app.error (err, req, res, next) ->
+#  body = {}
+#  if err.message then body.message = err.message
+#  if err.errors then body.errors = err.errors

-  res.json body, err.number or 400
+#  res.json body, err.number or 400


Ticker is no longer used

Ticker is no longer used

--- assets/scripts/lib/travis/ticker.coffee
+++ assets/scripts/lib/travis/ticker.coffee
@@ -1,14 +0,0 @@
-@Travis.Ticker = Ember.Object.extend
-  init: ->
-    @schedule() unless @get('interval') == -1
-
-  tick: ->
-    context = @get('context')
-    targets = @get('targets') || [@get('target')]
-    for target in targets
-      target = context.get(target) if context
-      target.tick() if target
-    @schedule()
-
-  schedule: ->
-    setTimeout((=> @tick()), @get('interval') || Travis.TICK_INTERVAL)


Minor fix in the marshaller

Minor fix in the marshaller

--- library/membrane/marshal.coffee
+++ library/membrane/marshal.coffee
@@ -56,5 +56,6 @@
     @serialize: (sequence) -> _.toArray _.cloneDeep sequence, ->
         possibleError = (o) -> o.message? and o.stack?
         value = _.head arguments or undefined
+        return value unless _.isObject value
         return unless possibleError(value) is yes
         message: value.message, stack: value.stack


improve hasmany beforeEach hook

improve hasmany beforeEach hook

--- test/spec/sync/relational/has_many.tests.coffee
+++ test/spec/sync/relational/has_many.tests.coffee
@@ -98,17 +98,22 @@

       # link and save all
       queue.defer (callback) ->
-        save_queue = new Queue()
-
+        save_queue = new Queue(1)
+
+        link_tasks = []
         for owner in MODELS.owner
-          do (owner) -> save_queue.defer (callback) ->
-            owner.set({
+          link_task =
+            owner: owner
+            values:
               flats: [MODELS.flat.pop(), MODELS.flat.pop()]
               reverses: [MODELS.reverse.pop(), MODELS.reverse.pop()]
               more_reverses: [MODELS.more_reverse.pop(), MODELS.more_reverse.pop()]
               foreign_reverses: [MODELS.foreign_reverse.pop()]
-            })
-            owner.save callback
+          link_tasks.push(link_task)
+
+        for link_task in link_tasks then do (link_task) -> save_queue.defer (callback) ->
+          link_task.owner.set(link_task.values)
+          link_task.owner.save callback

         save_queue.await callback


+store

+store

--- task/backup.coffee
+++ task/backup.coffee
@@ -34,6 +34,10 @@
       type: 'autocomplete'
       message: 'input'
       list: listTarget
+
+    target = target
+    .replace /_/g, ' '
+
     unless target in listTarget
       throw new Error "invalid target '#{target}'"


Fixes issue with internal istanbul upgrade

--- build/tasks/istanbul.coffee
+++ build/tasks/istanbul.coffee
@@ -4,7 +4,7 @@
   @loadNpmTasks 'grunt-istanbul'

   # Inject the Istanbul Traceur version to provide proper ES6 coverage.
-  task = require.cache[require.resolve('grunt-istanbul/node_modules/istanbul')]
+  task = require.cache[require.resolve('istanbul')]
   task.exports.Instrumenter = istanbulTraceur.Instrumenter

   @config 'instrument',


Whitespace /o/

Whitespace /o/

--- scripts/kerb.coffee
+++ scripts/kerb.coffee
@@ -18,7 +18,7 @@
     jsdom.env url, [ "http://code.jquery.com/jquery-1.5.min.js" ], (errors, window) ->
       trader_panel = window.$(".panel")[1]
       msg.send window.$(trader_panel).children("p").text()
-
+
   robot.respond /what\'s on kerb/i, (msg) ->
     url = "http://www.kerbfood.com/kings-cross/"


fixed undefined error type

fixed undefined error type

--- src/steroids/data/SandboxDB.coffee
+++ src/steroids/data/SandboxDB.coffee
@@ -15,6 +15,7 @@
   @SandboxDBError: class SandboxDBError extends steroidsCli.SteroidsError
   @ProvisionError: class ProvisionError extends SandboxDBError
   @WriteFileError: class WriteFileError extends SandboxDBError
+  @ConnectionError: class ConnectionError extends SandboxDBError

   providerName: "AppGyver Sandbox Database"
   providerTypeId: 6
@@ -59,7 +60,7 @@
         url: "#{sandboxDBBaseURL}/v1/credentials/provision"
       , (err, res, body) =>
         if err?
-          reject new DeployError "Could not connect to Sandbox DB"
+          reject new ConnectionError "Could not connect to Sandbox DB"
         else if res.statusCode == 200 and body.code == 201 # The fuq?
           @fromApiSchemaDict(body.body)
           resolve()


Add missing atom.exe path

Add missing atom.exe path

--- build/tasks/codesign-task.coffee
+++ build/tasks/codesign-task.coffee
@@ -7,7 +7,7 @@
     done = @async()
     spawn {cmd: 'taskkill', args: ['/F', '/IM', 'atom.exe']}, ->
       cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
-
+      atomExePath = path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')
       spawn {cmd, args: [atomExePath]}, (error) ->
         return done(error) if error?


Coverage not yet being detected

Coverage not yet being detected

--- gulp.coffee
+++ gulp.coffee
@@ -53,6 +53,7 @@

     }
   }))
+  ###
   .pipe(gCoverageEnforcer({
     thresholds : {
       statements : 0,
@@ -63,6 +64,7 @@
     coverageDirectory : 'coverage',
     rootDirectory : ''
   }))
+  ###

 gulpTestExamples = () ->
   gulp


Client: Sidebar: Deleted unnecessary class references and added news

--- client/app/lib/components/sidebarmachineslistitem/sharingmachineinvitationwidget.coffee
+++ client/app/lib/components/sidebarmachineslistitem/sharingmachineinvitationwidget.coffee
@@ -1,10 +1,9 @@
-React                     = require 'kd-react'
-Popover                   = require 'app/components/common/popover'
-actions                   = require 'app/flux/environment/actions'
+React                    = require 'kd-react'
+ReactDOM                 = require 'react-dom'
+actions                  = require 'app/flux/environment/actions'
 SidebarWidget             = require './sidebarwidget'
-InvitationWidgetUserView  = require './invitationwidgetuserview'
-EnvironmentFlux           = require 'app/flux/environment'
-
+EnvironmentFlux          = require 'app/flux/environment'
+InvitationWidgetUserView = require './invitationwidgetuserview'

 module.exports = class SharingMachineInvitationWidget extends React.Component


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/color2.coffee
+++ test/color2.coffee
@@ -159,7 +159,7 @@
   color1 = Color2(255, 255, 255, 1)
   color2 = Color2([255, 255, 255])

-  log color1.equal(color2)
+  ok color1.equal(color2)

 module()


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -24,6 +24,6 @@
     width: 10
     height: 10

-
+  fast

 module()


Fix double colon on help messages

Fix double colon on help messages

--- modules/help.coffee
+++ modules/help.coffee
@@ -5,7 +5,7 @@
     @registerCommand 'help', { allowDM: true }, ({ msg, args, s, l })=>
       gstr = ''
       if msg.guild
-        gstr = "\n**#{l.gen l.help.prefix, msg.guild.name}**: `#{s.prefix}`\n"
+        gstr = "\n**#{l.gen l.help.prefix, msg.guild.name}** `#{s.prefix}`\n"
         # Calculate permission level
         level = 0
         level = 1 if Core.permissions.isDJ(msg.member)


LARA link updated to use the V2 Doc Store API [#129951047]

--- src/code/views/share-dialog-view.coffee
+++ src/code/views/share-dialog-view.coffee
@@ -1,6 +1,7 @@
 {div, input, a, button, strong, textarea, svg, g, path, span, circle, ul, li} = React.DOM

 ModalDialog = React.createFactory require './modal-dialog-view'
+getQueryParam = require '../utils/get-query-param'

 tr = require '../utils/translate'
 socialIcons = require 'svg-social-icons/lib/icons.json'
@@ -70,9 +71,11 @@
   getLara: (options = null) ->
     sharedDocumentId = @getSharedDocumentId()
     if sharedDocumentId
+      documentServer = getQueryParam('documentServer') or 'https://document-store.concord.org'
+      documentServer = documentServer.slice(0, -1) while documentServer.substr(-1) is '/'  # remove trailing slash
       server = encodeURIComponent (if options?.hasOwnProperty('codapServerUrl') then options.codapServerUrl else @state.codapServerUrl)
       buttonText = encodeURIComponent (if options?.hasOwnProperty('launchButtonText') then options.launchButtonText else @state.launchButtonText)
-      "https://document-store.concord.org/document/launch?recordid=#{sharedDocumentId}&server=#{server}&buttonText=#{buttonText}"
+      "#{documentServer}/v2/documents/#{sharedDocumentId}/launch?server=#{server}&buttonText=#{buttonText}"
     else
       null


Include deprecated APIs when running specs

--- src/browser/atom-application.coffee
+++ src/browser/atom-application.coffee
@@ -510,7 +510,7 @@
     isSpec = true
     devMode = true
     safeMode ?= false
-    includeDeprecatedAPIs ?= false
+    includeDeprecatedAPIs ?= true
     new AtomWindow({bootstrapScript, resourcePath, exitWhenDone, isSpec, devMode, specDirectory, logFile, safeMode, includeDeprecatedAPIs})

   runBenchmarks: ({exitWhenDone, specDirectory}={}) ->


Save list of open windows as windows are added/removed

--- src/browser/atom-application.coffee
+++ src/browser/atom-application.coffee
@@ -100,6 +100,7 @@
   removeWindow: (window) ->
     @windows.splice @windows.indexOf(window), 1
     @applicationMenu?.enableWindowSpecificItems(false) if @windows.length is 0
+    @saveState()

   # Public: Adds the {AtomWindow} to the global window list.
   addWindow: (window) ->
@@ -114,6 +115,7 @@
       window.browserWindow.once 'closed', =>
         @lastFocusedWindow = null if window is @lastFocusedWindow
         window.browserWindow.removeListener 'focus', focusHandler
+      window.browserWindow.webContents.once 'did-finish-load', => @saveState()

   # Creates server to listen for additional atom application launches.
   #
@@ -202,9 +204,6 @@
     app.on 'window-all-closed', ->
       app.quit() if process.platform in ['win32', 'linux']

-    app.on 'before-quit', =>
-      @saveState()
-
     app.on 'will-quit', =>
       @killAllProcesses()
       @deleteSocketFile()


koding-bound: fix the behavior

koding-bound: fix the behavior

--- node_modules_koding/koding-bound/src/koding-bound/index.coffee
+++ node_modules_koding/koding-bound/src/koding-bound/index.coffee
@@ -1,7 +1,7 @@
-module.exports = (method, rest...)->
+module.exports = (method) ->
   throw new Error "@bound: unknown method! #{method}"  unless @[method]?
   boundMethod = "__bound__#{method}"
   boundMethod of this or Object.defineProperty(
-    this, boundMethod, value: @[method].bind this, rest...
+    this, boundMethod, value: @[method].bind this
   )
   return @[boundMethod]


Skip CoffeeScript setSource test on browser if there is no CoffeeScript compiler available

--- spec/ComponentLoader.coffee
+++ spec/ComponentLoader.coffee
@@ -336,6 +336,10 @@
               done()
             ins.send 'ES6'
       describe 'with CoffeeScript', ->
+        before ->
+          # CoffeeScript tests work in browser only if we have CoffeeScript
+          # compiler loaded
+          return @skip() if noflo.isBrowser() and not window.CoffeeScript
         workingSource = """
         noflo = require 'noflo'
         exports.getComponent = ->


Use absolute paths in Editor.reloadGrammar() specs

--- spec/app/editor-spec.coffee
+++ spec/app/editor-spec.coffee
@@ -2051,7 +2051,7 @@
     [path] = []

     beforeEach ->
-      path = "/tmp/grammar-change.txt"
+      path = fs.join(fs.absolute("/tmp"), "grammar-change.txt")
       fs.write(path, "var i;")

     afterEach ->


Fix spec of confirmSync in 'window:close'.

--- spec/app/window-spec.coffee
+++ spec/app/window-spec.coffee
@@ -47,21 +47,21 @@
     describe "when pane items are are modified", ->
       it "prompts user to save and and calls window.closeWithoutConfirm", ->
         spyOn(window, 'closeWithoutConfirm')
-        spyOn(atom, "confirm").andCallFake (a, b, c, d, e, f, g, noSave) -> noSave()
+        spyOn(atom, "confirmSync").andReturn(2)
         editSession = rootView.open("sample.js")
         editSession.insertText("I look different, I feel different.")
         $(window).trigger 'window:close'
         expect(window.closeWithoutConfirm).toHaveBeenCalled()
-        expect(atom.confirm).toHaveBeenCalled()
+        expect(atom.confirmSync).toHaveBeenCalled()

       it "prompts user to save and aborts if dialog is canceled", ->
         spyOn(window, 'closeWithoutConfirm')
-        spyOn(atom, "confirm").andCallFake (a, b, c, d, e, cancel) -> cancel()
+        spyOn(atom, "confirmSync").andReturn(1)
         editSession = rootView.open("sample.js")
         editSession.insertText("I look different, I feel different.")
         $(window).trigger 'window:close'
         expect(window.closeWithoutConfirm).not.toHaveBeenCalled()
-        expect(atom.confirm).toHaveBeenCalled()
+        expect(atom.confirmSync).toHaveBeenCalled()

   describe "requireStylesheet(path)", ->
     it "synchronously loads css at the given path and installs a style tag for it in the head", ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/sprite.coffee
+++ test/sprite.coffee
@@ -8,7 +8,8 @@
   spriteUrl = "http://images.pixie.strd6.com/avatars/1/thumb.png"

   callback = ->
-    sprite2 = Sprite.load spriteUrl, () ->
+    sprite2 = Sprite.load spriteUrl, (s) ->
+

   sprite = Sprite.load spriteUrl, callback


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/sprite.coffee
+++ test/sprite.coffee
@@ -9,8 +9,9 @@

   callback = (s) ->
     sprite = Sprite.load spriteUrl
+
+

   sprite = Sprite.load spriteUrl, callback
-

 module()


[background] fix for empty spreadsheets

[background] fix for empty spreadsheets

--- src/coffee/data/spreadsheets.coffee
+++ src/coffee/data/spreadsheets.coffee
@@ -90,6 +90,10 @@
                 headers = []
                 result = []

+                if nbCols is 0 or nbRows is 0
+                    callback 'The spreadsheet is empty.', null
+                    return
+
                 for i in [0..nbCols-1]
                     headers[i] = data.getColumnLabel i


wrote a test for just passing in a name

wrote a test for just passing in a name

--- spec/lib/router-spec.coffee
+++ spec/lib/router-spec.coffee
@@ -84,6 +84,11 @@
       Given -> @test = => @router.use()
       Then -> expect(@test).toThrow new Error 'expecting at least one parameter'

+    describe '#use (name:Sring)', ->
+
+      Given -> @test = => @router.use 'name'
+      Then -> expect(@test).toThrow new Error 'we have the name, but need a handler'
+
     describe '#use (fn:Function)', ->

       Given -> @fn = (socket, args, next) ->


fix e2e tests

fix e2e tests

--- test/wd/e2e.coffee
+++ test/wd/e2e.coffee
@@ -1,6 +1,6 @@
 cleanLines = (html) ->
-  html = html.replace(/\ class\="line"/g, '')
-  html = html.replace(/\ id\="line-\d+"/g, '')
+  html = html.replace(/\ class\="ql-line"/g, '')
+  html = html.replace(/\ id\="ql-line-\d+"/g, '')
   return html


remove ross

remove ross

--- scripts/ross.coffee
+++ scripts/ross.coffee
@@ -1,24 +0,0 @@
-# Description:
-#   Finds Ross.
-#
-
-BASE_URL = 'http://odyssey.rosspaffett.com'
-POLL_INTERVAL_MINS = 10
-ROOM = 'stream:social topic:rossachusetts'
-
-cheerio = require 'cheerio'
-
-module.exports = (robot) ->
-  callback = ->
-    robot.http(BASE_URL + '/posts').get() (err, res, body) ->
-      $ = cheerio.load(body)
-      location = $('.post-header strong').eq(1).text()
-      link = BASE_URL + $('a.post-link').first().attr('href')
-      picture_link = $('a.post-link img').first().attr('src')
-
-      if robot.brain.data.rosslink isnt link
-        robot.brain.data.rosslink = link
-        robot.send {room: ROOM},
-          "[Ross has arrived in #{location}](#{link})\n[picture](#{picture_link})"
-
-  setInterval callback, POLL_INTERVAL_MINS * 60 * 1000