commented auto updator for testing without code signing

--- electron/js/main.coffee
+++ electron/js/main.coffee
@@ -59,8 +59,8 @@

 createWindow = ->
  #console.log electron
- autoUpdater = electron.autoUpdater
- autoUpdater.setFeedURL "http://localhost:3000/update"
+ #autoUpdater = electron.autoUpdater
+ #autoUpdater.setFeedURL "http://localhost:3000/update"
  mainWindow = new BrowserWindow width: 800, height: 600
  mainWindow.setMenu null
  mainWindow.loadURL "file://#{__dirname}/index.html"
@@ -72,8 +72,8 @@
   # when you should delete the corresponding element.
   mainWindow = null

- autoUpdater.addListener 'error', (e) ->
-  throw 'error'
+ #autoUpdater.addListener 'error', (e) ->
+ # throw 'error'

  mainWindow.webContents.once "did-frame-finish-load", (e) ->
   console.log 'frame load'
@@ -81,7 +81,7 @@
   #autoUpdater.checkForUpdates()

-return if handleSquirrelEvent()
+#return if handleSquirrelEvent()

 app.on 'ready', createWindow


Add double click fix to last commit

Add double click fix to last commit

--- app/assets/javascripts/modules/mobilemenu.coffee
+++ app/assets/javascripts/modules/mobilemenu.coffee
@@ -12,7 +12,7 @@
     return

   if smartphone
-    $inputQuery.click ->
+    $inputQuery.unbind('click').click ->
       $inputLocationContainer.toggleClass "is-visible"
       $submit.toggleClass "is-enlarged"
       $distributor.toggleClass "is-enlarged"


inline footer svg

inline footer svg


Move sapphire spree app to single file

Move sapphire spree app to single file

--- app/assets/javascripts/sapphire_cms/spree.coffee
+++ app/assets/javascripts/sapphire_cms/spree.coffee
@@ -1 +1,5 @@
-#= require underscore+#= require underscore
+#= require sapphire-cms/client
+#= require ./sapphire-cms.spree
+
+angular.module 'app', ['sp.spree']


CRUD for users: NEW action

CRUD for users: NEW action

--- app/assets/javascripts/views/users/new.js.coffee
+++ app/assets/javascripts/views/users/new.js.coffee
@@ -41,7 +41,8 @@

Salary

-        <input data-attribute=membership.salary size="30" type="number">

+        <input data-attribute=membership.salary size="30" type="number">
+

Full-Time Equivalent

         <input data-attribute=membership.full_time_equivalent size="30" type="number">

@@ -73,23 +74,27 @@
   initialize: ->
     @userNewTemplate = Handlebars.compile(@templates.userNew)
     @$el.html @userNewTemplate
+
     @render()
   events: ->
     "change select[data-attribute=membership.employment_status]": "refreshSalaryRelatedFields"
     "click div.actions input[type=submit]": "saveUser"

   refreshSalaryRelatedFields: (event) ->
-    selection = $(event.currentTarget).val()
-    console.log selection
+    selected = $(event.currentTarget).val()
+
+    @$el.find('div#salary_information div.salary').hide()
+    @$el.find('div#salary_information').find('input, select').prop('disabled', true)
+    @$el.find('div#salary_information div.' + selected).find('input, select').show().prop('disabled', false)
+    @$el.find('div#salary_information div.' + selected).show()

   saveUser: =>
     serializedForm = {}
-    _.each @$el.find('[data-attribute]'), (element) ->
+    _.each @$el.find('[data-attribute]:not(:disabled)'), (element) ->
       setValueAt serializedForm, $(element).data('attribute').split("."), $(element).val()

-    # Should work for both new and edit :/
     @collection.create serializedForm,
-      wait: true # Best to wait for a successful CREATE server-side to add the model to the collection
+      wait: true
       error: (model, response) =>
         alert "An error prevented the User from being saved."
       success: (model, response) =>
@@ -97,4 +102,7 @@

   render: ->
     @$el.appendTo("section.main .content")
+    selected = $('select[data-attribute="membership.employment_status"]').val()
+    $("div#salary_information div.salary").hide().find('input, select').prop('disabled', true)
+    $("div#salary_information div." + selected + "").show().find('input, select').prop('disabled', false)


Revert "Make MSF work for wiki pages in old UI"

refs CNVS-26906

This reverts commit 3ceda8fe8803abd7d08c944de78b9a9802850685.

Change-Id: If4e48b25aa1fe9e797d53fc964cd3a9fe6f2d9b0
Reviewed-on: https://gerrit.instructure.com/71159
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
Tested-by: Jenkins
QA-Review: Clare Strong <40d6bb3ed7fef516c73274131d5a837c16de74fd@instructure.com>
Product-Review: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>

--- app/coffeescripts/views/wiki/WikiPageView.coffee
+++ app/coffeescripts/views/wiki/WikiPageView.coffee
@@ -70,10 +70,7 @@

       # attach/re-attach the sequence footer (if this is a course, but not the home page)
       unless @$sequenceFooter || @course_home || !@course_id
-        if (ENV.use_new_styles)
-          @$sequenceFooter ||= $('

').hide()
-        else
-          @$sequenceFooter ||= $('

').hide()
+        @$sequenceFooter ||= $('

').hide()
         @$sequenceFooter.moduleSequenceFooter(
           courseID: @course_id
           assetType: 'Page'
@@ -82,10 +79,7 @@
         )
       else
         @$sequenceFooter?.msfAnimation(false)
-      if (ENV.use_new_styles)
-        @$sequenceFooter.appendTo($('.ic-app-main-and-right-side')) if @$sequenceFooter
-      else
-        @$sequenceFooter.appendTo(@$el) if @$sequenceFooter
+      @$sequenceFooter.appendTo($('.ic-app-main-and-right-side')) if @$sequenceFooter

     navigateToLinkAnchor: ->
       anchor_name = window.location.hash.replace(/^#/, "")


Make growl notifications component IE8 compatible.

--- app/scripts/components/GrowlNotifications.coffee
+++ app/scripts/components/GrowlNotifications.coffee
@@ -54,9 +54,9 @@
         ###
         init: ->
             @._super()
-            fn = (->
+            fn = (=>
                 @notifyPropertyChange "style"
-            ).bind(@)
+            )
             @set "_recomputeStyle", fn
             $(window).bind "resize", fn

@@ -66,10 +66,10 @@
         didInsertElement: ->
             #@$().fadeIn(@get('fadeInTime'))
             # Be prepared to auto-hide the notification
-            @set "timeoutId", setTimeout((->
+            @set "timeoutId", setTimeout((=>
                 #@send "close"
                 @send("close")
-            ).bind(this), @get("parentView.showTime"))
+            ), @get("parentView.showTime"))

             # Fade in the view.
             Ember.run.later this, (->
@@ -81,6 +81,7 @@
         ###
         willDestroyElement: ->
             $(window).unbind('resize', @get('_recomputeStyle'))
+

         style: (->
             notifications = @get('parentView.content').rejectProperty('closed', true)
@@ -116,11 +117,11 @@
         actions:
             close: ->
                 @set('isOpaque', false)
-                setTimeout (->
+                setTimeout (=>
                     @get('parentView.content').removeObject(@get('content'))
                     clearTimeout @get("timeoutId")

-                ).bind(@), 300
+                ), 300
     )
 )


[client-app] Prevent unnecessary re-rendering of thread-list

Summary:
This commit adds a `shouldComponentUpdate` to thread-list.cjsx so that
the thread list doesn't unnecessarily /try/ to re-render when state or
props haven't actually changed.

I noticed this because the thread list was constantly calling `render`
even though it didn't render any changes to the DOM. This was caused
because it listens to `NylasSyncStatusStore` which constantly triggers,
even though the piece of state the list is interested in rarely changes,
causing unnecessary calls to the `render` loop.

Test Plan: manual

Reviewers: halla, evan

Reviewed By: evan

Differential Revision: https://phab.nylas.com/D4047

--- packages/client-app/internal_packages/thread-list/lib/thread-list.cjsx
+++ packages/client-app/internal_packages/thread-list/lib/thread-list.cjsx
@@ -10,6 +10,7 @@
  SyncingListState} = require 'nylas-component-kit'

 {Actions,
+ Utils,
  Thread,
  Category,
  CanvasUtils,
@@ -45,12 +46,16 @@

   componentDidMount: =>
     @_reportAppBootTime()
-    @unsub = NylasSyncStatusStore.listen( => @setState
-      syncing: FocusedPerspectiveStore.current().hasSyncingCategories()
-    )
+    @unsub = NylasSyncStatusStore.listen(@_onSyncStatusChanged)
     window.addEventListener('resize', @_onResize, true)
     ReactDOM.findDOMNode(@).addEventListener('contextmenu', @_onShowContextMenu)
     @_onResize()
+
+  shouldComponentUpdate: (nextProps, nextState) =>
+    return (
+      (not Utils.isEqualReact(@props, nextProps)) or
+      (not Utils.isEqualReact(@state, nextState))
+    )

   componentDidUpdate: =>
     dataSource = ThreadListStore.dataSource()
@@ -221,6 +226,10 @@
         accountIds: [thread.accountId]
       }

+  _onSyncStatusChanged: =>
+    syncing = FocusedPerspectiveStore.current().hasSyncingCategories()
+    @setState({syncing})
+
   _onShowContextMenu: (event) =>
     data = @_targetItemsForMouseEvent(event)
     if not data


fixed that if you write a post with an embedded link a second time that the first one does not appear

--- client/app/Applications/Activity.kdapplication/views/embedbox.coffee
+++ client/app/Applications/Activity.kdapplication/views/embedbox.coffee
@@ -140,7 +140,6 @@
         when 'object' then containerClass = EmbedBoxObjectView
         else               containerClass = EmbedBoxLinkView

-      @embedContainer.destroy()
       @embedLinks.hide()
       @embedContainer = new containerClass embedOptions, data
       @embedContainer.show()
@@ -255,6 +254,7 @@
       if embed.url is url or embedUrl.indexOf(url_,embedUrl.length-url_.length) >= 0
         return @embedExistingData @cache[i], options, callback

+    @embedContainer.destroy()  if @embedContainer
     @embedLoader.show()
     @$('div.link-embed').addClass 'loading'
     @fetchEmbed url, options, (data, embedlyOptions)=>


payments: group payments loader WIP

payments: group payments loader WIP

--- client/app/Applications/Dashboard.kdapplication/AppController.coffee
+++ client/app/Applications/Dashboard.kdapplication/AppController.coffee
@@ -103,14 +103,15 @@
   policyViewAdded: (pane, view) ->

   paymentViewAdded: (pane, view) ->
+
     paymentController = KD.getSingleton 'paymentController'

     group = @getData()

     group.fetchPaymentMethod (err, paymentMethod) ->
-      console.log { err, paymentMethod }
-    # paymentController.fetchBillingInfo 'group', (err, billingInfo) =>
-      view.setBillingInfo paymentMethod
+      return new KDNotificationView title: err.message  if err
+
+      view.setBillingInfo paymentMethod  if paymentMethod

     @paymentView = view

@@ -139,20 +140,28 @@

   createBillingInfoModal: ->

+    console.trace()
+
     paymentController = KD.getSingleton "paymentController"

     billingInfoModal = paymentController.createBillingInfoModal 'group', {}
+    billingInfoModal.showLoader()

-    paymentController.fetchBillingInfo 'group', (err, groupBillingInfo) ->
+    group = @getData()

-      if groupBillingInfo
-        billingInfoModal.setBillingInfo groupBillingInfo
+    group.fetchPaymentMethod (err, groupBillingMethod) ->
+
+      if groupBillingMethod
+        billingInfoModal.hideLoader()
+        billingInfoModal.setBillingInfo groupBillingMethod

       else
-        paymentController.fetchBillingInfo 'user', (err, personalBillingInfo) ->

-          if personalBillingInfo
-            { billing } = personalBillingInfo
+        KD.whoami().fetchPaymentMethods (err, personalBillingMethods) ->
+
+          billingInfoModal.hideLoader()
+
+          if personalBillingMethods

             useExistingModal = new KDModalView
               title: 'Would you like to link an existing payment method?'
@@ -161,12 +170,17 @@
                   style       : 'modal-cancel'
                   callback    : -> useExistingModal.destroy()

-            billingMethodView = new BillingMethodView {}, billing
-            useExistingModal.addSubView billingMethodView

-            billingMethodView.on 'BillingEditRequested', ->
-              billingInfoModal.setBillingInfo personalBillingInfo.billing
-              useExistingModal.destroy()
+            personalBillingMethods.forEach ({ accountCode, billing }) ->
+
+              billingMethodView = new BillingMethodView {}, billing
+              useExistingModal.addSubView billingMethodView
+              destroy = useExistingModal.bound 'destroy'
+              billingInfoModal.on 'KDObjectWillBeDestroyed', destroy
+
+              billingMethodView.on 'BillingEditRequested', ->
+                console.log { accountCode }
+                # group.addPaymentMethod

     return billingInfoModal


Sidebar: Fixed Your Server's tab state to show/hide it properly.

--- client/landing/app/MainApp/sidebar/sidebarview.coffee
+++ client/landing/app/MainApp/sidebar/sidebarview.coffee
@@ -86,7 +86,7 @@
     @finderBottomControlPin = new KDToggleButton
       cssClass     : "finder-bottom-pin"
       iconOnly     : yes
-      defaultState : "show"
+      defaultState : "hide"
       states       : [
         title      : "show"
         iconClass  : "up"


team: onboarding and invitation routes improved

--- client/landing/site.landing/coffee/core/routes.coffee
+++ client/landing/site.landing/coffee/core/routes.coffee
@@ -8,8 +8,8 @@
     # don't load the root content when we're just consuming a hash fragment
     return if location.hash.length

-    { router }           = KD.singletons
-    { groupName, group } = KD.config
+    { router } = KD.singletons
+    { groupName, group, environment } = KD.config

     # root is home if group is koding
     if groupName is 'koding'
@@ -18,21 +18,39 @@

     # if there is no such group take user to group creation with given group info
-    if not group or KD.config.environment is PROD
-      newUrl = 'http://' + location.host.replace("#{groupName}.", '') + "/Teams?group=#{groupName}"
+    if not group or environment is PROD
+      newUrl = "http://#{location.host.replace(groupName '.', '')}/Teams?group=#{groupName}"
       return location.replace newUrl

     # if there is a group then take user to group login page
     else
       return router.openSection 'Team', null, null, (app) -> app.jumpTo 'login'

+  handleInvitation = ({params : {token}, query}) ->

-  handleTeamRoute = (section, {params, query}) ->
+    { routeIfInvitationTokenIsValid } = KD.utils
+    routeIfInvitationTokenIsValid token

-    # if group is koding or if the route doesnt have a subdomain route to root.
-    return handleRoot()  if KD.config.groupName is KODING

-    { router } = KD.singletons
+  handleTeamOnboardingRoute = (section, {params, query}) ->
+
+    { groupName, group, environment } = KD.config
+    { router }                        = KD.singletons
+
+    # if group is koding or if the route doesnt have a subdomain we route to root.
+    return router.handleRoute '/'  if groupName is KODING
+
+    # if we dont have a group with the subdomain slug we again route to root.
+    unless group
+      newUrl = "http://#{location.host.replace(groupName + '.', '')}"
+      return location.replace newUrl
+
+    # if we dont have a valid email fetched from the invitation token we warn and route to root.
+    unless KD.utils.getTeamData().invitation?.email
+      console.warn 'No valid invitation found!'
+      return router.handleRoute '/'
+
+    # we open the team creation or onboarding section
     return router.openSection 'Team', null, null, (app) -> app.jumpTo section, params, query

@@ -41,10 +59,10 @@
     ''                     : handleRoot
     # the routes below are subdomain routes
     # e.g. team.koding.com/Invitation
-    '/Invitation/:token?'  : handleTeamRoute.bind this, 'invitation'
-    '/Welcome'             : handleTeamRoute.bind this, 'welcome'
-    '/Register'            : handleTeamRoute.bind this, 'register'
-    '/Authenticate/:step?' : handleTeamRoute.bind this, 'stacks'
-    '/Congratz'            : handleTeamRoute.bind this, 'congratz'
+    '/Invitation/:token'   : handleInvitation
+    '/Welcome'             : handleTeamOnboardingRoute.bind this, 'welcome'
+    '/Register'            : handleTeamOnboardingRoute.bind this, 'register'
+    '/Authenticate/:step?' : handleTeamOnboardingRoute.bind this, 'stacks'
+    '/Congratz'            : handleTeamOnboardingRoute.bind this, 'congratz'


SimpleForm: Fixed block depth calculation. This got broken after form-depth was removed.

--- src/elements/Form/SimpleForm.coffee
+++ src/elements/Form/SimpleForm.coffee
@@ -657,9 +657,14 @@
 				return true
 		return false

-	getBlockLevelOffset: ->
-		parentBlockLevelOffset = @getForm()?.getBlockLevelOffset?() or 0
-		return parentBlockLevelOffset + @_blockLevelOffset
+	getBlockLevelOffset: (level = 0) ->
+
+		if @getForm()
+			parent = (@getForm().getBlockLevelOffset() or 0) + 1
+		else
+			parent = 0
+
+		return @_blockLevelOffset + parent

 	setBlockLevelOffset: (@_blockLevelOffset) ->
 		return @_blockLevelOffset


On menu based markdown conversion,  	be picky about x as marker for correct requiring it to be first non-whitespace char on line, followed by whitespace, followed eventually but another non-whitespace char  	strip trailing newline from selection.

--- common/lib/xmodule/xmodule/js/src/problem/edit.coffee
+++ common/lib/xmodule/xmodule/js/src/problem/edit.coffee
@@ -125,23 +125,17 @@

   @insertGenericChoice: (selectedText, choiceStart, choiceEnd, template) ->
     if selectedText.length > 0
-      # Replace adjacent newlines with a single newline
-      cleanSelectedText = selectedText.replace(/\n+/g, '\n')
+      # Replace adjacent newlines with a single newline, strip any trailing newline
+      cleanSelectedText = selectedText.replace(/\n+/g, '\n').replace(/\n$/,'')
       lines =  cleanSelectedText.split('\n')
       revisedLines = ''
       for line in lines
         revisedLines += choiceStart
-        # This is looking for a x before text to mark as selected.
-        if /x\s/i.test(line)
-          # Remove the x and any initial whitespace
-          lineWithoutX = line.replace(/^(\s+)?x/i, '')
-          # Check if any non-whitespace chars remain on the line
-          if not /^\s+$/.test(lineWithoutX)
-            # Remove initial whitespace, x, and space immediately after
-            line = line.replace(/^(\s+)?x\s/i, '')
-            revisedLines += 'x'
-          else
-            revisedLines += ' '
+        # a stand alone x before other text implies that this option is "correct"
+        if /^\s*x\s*(\S)/i.test(line)
+          # Remove the x and any initial whitespace as long as there's more text on the line
+          line = line.replace(/^\s*x\s*(\S)/i, '$1')
+          revisedLines += 'x'
         else
           revisedLines += ' '
         revisedLines += choiceEnd + ' ' + line + '\n'


Behaviour: Fix on_enter_vr.

Behaviour: Fix on_enter_vr.

--- engine/behaviour.coffee
+++ engine/behaviour.coffee
@@ -68,9 +68,9 @@
                         but object picking is disabled."
                     console.warn 'Add "this.enable_object_picking()"
                         to on_init()'
-        if @on_enter_vr? and @context.vr_screen?
-            [vp1, vp2] = @context.vr_screen.viewports
-            @on_enter_vr vp1.camera, vp2.camera
+            if @on_enter_vr? and @context.vr_screen?
+                [vp1, vp2] = @context.vr_screen.viewports
+                @on_enter_vr vp1.camera, vp2.camera

     enable: ->
         if not @_enabled


bubbles: tipsy code commented

bubbles: tipsy code commented

--- app/charts/bubbles.coffee
+++ app/charts/bubbles.coffee
@@ -343,9 +343,12 @@
               d3.max(maxTotalMagnitudes.inbound),
               d3.max(maxTotalMagnitudes.outbound))

+
         rscale = d3.scale.sqrt()
-          .range([0, Math.min(bubblesChartWidth/25, bubblesChartHeight /12)])
           .domain([0, maxTotalMagnitude])
+          .range([0, Math.min(bubblesChartWidth/25, bubblesChartHeight/12)])
+
+
         maxr = rscale.range()[1]

         fwscale = d3.scale.sqrt() #.linear()
@@ -586,9 +589,9 @@

           createNodeTimeSeries(this, d, i)

-          $(this).tipsy("show")
-          $(tipsy.$tip)  # fix vertical position
-              .css('top', d3.event.pageY-($(tipsy.$tip).outerHeight()/2))
+#          $(this).tipsy("show")
+#          $(tipsy.$tip)  # fix vertical position
+#              .css('top', d3.event.pageY-($(tipsy.$tip).outerHeight()/2))

         .on 'mouseout', (d, i) ->
           d3.select(this).classed("highlighted", false)
@@ -599,7 +602,7 @@
           if selectedNode != this
             tseriesPanel.remove(d[conf.nodeIdAttr])

-          $(this).tipsy("hide")
+#          $(this).tipsy("hide")

         force.nodes(nodes)
@@ -750,34 +753,35 @@
           .attr("x2", (d) -> d.target.x)
           .attr("y2", (d) -> d.target.y)
           .attr("visibility", (d) -> if flowLineValue(d) > 0 then "visible" else "hidden")
-          .on "mouseover", (d, i) ->
+          .on("mouseover", (d, i) ->
             if this.parentNode?
               this.parentNode.appendChild(this)

-            $(this).tipsy("show")
-
             createFlowTimeSeries(this, d, i)
-
-            $(tipsy.$tip)
-                .css('top', d3.event.pageY-($(tipsy.$tip).outerHeight()/2))
-                .css('left', d3.event.pageX + 10)
-          .on "mouseout", (d, i) ->
-            $(this).tipsy("hide")
+#            $(this).tipsy("show")
+
+
+#            $(tipsy.$tip)
+#                .css('top', d3.event.pageY-($(tipsy.$tip).outerHeight()/2))
+#                .css('left', d3.event.pageX + 10)
+          ).on("mouseout", (d, i) ->
+#            $(this).tipsy("hide")
             tseriesPanel.remove("flow" + i)
-
-          lines
-            .transition()
-                .duration(200)
-                  .attr("stroke-width", (d) -> fwscale(flowLineValue(d)))
-                  #.attr("opacity", 1)
-
-
-        $('g.flows line').tipsy
-          gravity: 'w'
-          opacity: 0.9
-          html: true
-          trigger: "manual"
-          title: -> flowTooltip(d3.select(this).datum())
+          )
+
+        lines
+          .transition()
+              .duration(200)
+                .attr("stroke-width", (d) -> fwscale(flowLineValue(d)))
+                #.attr("opacity", 1)
+
+
+#        $('g.flows line').tipsy
+#          gravity: 'w'
+#          opacity: 0.9
+#          html: true
+#          trigger: "manual"
+#          title: -> flowTooltip(d3.select(this).datum())


No need to check for property existence.

--- services/web/public/coffee/main/event.coffee
+++ services/web/public/coffee/main/event.coffee
@@ -17,11 +17,7 @@

 		_eventInCache = (key) ->
 			curCache = _getEventCache()
-
-			if (curCache.hasOwnProperty key)
-				curCache[key]
-			else
-				false
+			curCache[key] || false

 		_addEventToCache = (key) ->
 			curCache = _getEventCache()


Load / run scripts synchronously

Load / run scripts synchronously

--- index.coffee
+++ index.coffee
@@ -1,12 +1,11 @@
-fs = require "fs"
-path = require "path"
+fs = require 'fs'
+path = require 'path'

 module.exports = (robot, scripts) ->
-    scriptsPath = path.resolve(__dirname, "src")
-    fs.exists scriptsPath, (exists) ->
-        if exists
-            for script in fs.readdirSync(scriptsPath)
-                if scripts? and "*" not in scripts
-                    robot.loadFile(scriptsPath, script) if script in scripts
-                else
-                    robot.loadFile(scriptsPath, script)+    scriptsPath = path.resolve(__dirname, 'src')
+    if fs.existsSync scriptsPath
+        for script in fs.readdirSync(scriptsPath).sort()
+            if scripts? and '*' not in scripts
+                robot.loadFile(scriptsPath, script) if script in scripts
+            else
+                robot.loadFile(scriptsPath, script)


Use spawn from Atom's task helpers

Use spawn from Atom's task helpers

--- index.coffee
+++ index.coffee
@@ -1,3 +1,4 @@
+ChildProcess = require 'child_process'
 fs = require 'fs'
 path = require 'path'
 temp = require 'temp'
@@ -7,8 +8,19 @@

 module.exports = (grunt) ->
   spawn = (options, callback) ->
-    spawnedProcess = grunt.util.spawn(options, callback)
-    spawnedProcess.on('error', callback)
+    stdout = []
+    stderr = []
+    error = null
+
+    spawnedProcess = ChildProcess.spawn(options.cmd, options.args, options.opts)
+    spawnedProcess.stdout.on 'data', (data) -> stdout.push(data.toString())
+    spawnedProcess.stderr.on 'data', (data) -> stderr.push(data.toString())
+    spawnedProcess.on 'error', (processError) -> error ?= processError
+    spawnedProcess.on 'close', (exitCode, signal) ->
+      error ?= new Error(signal) if exitCode != 0
+      results = {stderr: stderr.join(''), stdout: stdout.join(''), code: exitCode}
+      grunt.log.error results.stderr if exitCode != 0
+      callback(error, results, exitCode)

   grunt.registerTask 'create-windows-installer', 'Create the Windows installer', ->
     @requiresConfig("#{@name}.appDirectory")


fix listing when TIME_STYLE is not long-iso

--- index.coffee
+++ index.coffee
@@ -38,7 +38,7 @@
       res.status(200).set('Content-Type', 'text/plain').send()
       return
     maxListCount = config.maxListCount + 1
-    shCmd = "ls -tl | head -#{maxListCount} | tail -n +2 | tr -s ' ' | cut -d' ' -f6,7,8"
+    shCmd = "TIME_STYLE=long-iso ls -tl | head -#{maxListCount} | tail -n +2 | tr -s ' ' | cut -d' ' -f6,7,8"
     execOptions = {cwd: "#{__dirname}/tastes/"}
     execFile '/bin/sh', ['-c', shCmd], execOptions, (err, stdout, stderr) ->
       return next err  if err?


Update to use full plugin names

Update to use full plugin names

Requires deathcap/voxel-plugins@0a3117a8c4a1ce4b33d2f80271db8aefae4a841f

--- index.coffee
+++ index.coffee
@@ -90,7 +90,7 @@
   console.log 'initializing plugins'
   plugins = createPlugins game, {require: require}

-  plugins.preload 'registry', {registerDefaults: (registry) ->
+  plugins.preload 'voxel-registry', {registerDefaults: (registry) ->
     registry.registerBlock 'grass', {texture: ['grass_top', 'dirt', 'grass_side'], hardness:5}
     registry.registerBlock 'dirt', {texture: 'dirt', hardness:4}
     registry.registerBlock 'stone', {texture: 'stone', hardness:90}
@@ -111,16 +111,16 @@
   }

-  plugins.preload '!craftingrecipes', {}
+  plugins.preload 'craftingrecipes', {}

   playerInventory = new Inventory(10, 5)

-  plugins.preload 'workbench', {playerInventory:playerInventory}
-
-  plugins.preload 'land', {populateTrees: true}
+  plugins.preload 'voxel-workbench', {playerInventory:playerInventory}
+
+  plugins.preload 'voxel-land', {populateTrees: true}

   # note: preconfigure(), not preload(), so doesn't automatically enable
-  plugins.preconfigure 'oculus', { distortion: 0.2, separation: 0.5 } # TODO: switch to voxel-oculus-vr? https://github.com/vladikoff/voxel-oculus-vr?source=c - closer matches threejs example
+  plugins.preconfigure 'voxel-oculus', { distortion: 0.2, separation: 0.5 } # TODO: switch to voxel-oculus-vr? https://github.com/vladikoff/voxel-oculus-vr?source=c - closer matches threejs example

   if window.location.href.indexOf('rift') != -1 ||  window.location.hash.indexOf('rift') != -1
     # Oculus Rift support
@@ -135,10 +135,10 @@

   # create the player from a minecraft skin file and tell the
   # game to use it as the main player
-  plugins.preload 'player', {image: 'player.png'}
-
-  plugins.preload 'fly', {flySpeed: 0.8}
-  plugins.preload 'walk', {}
+  plugins.preload 'voxel-player', {image: 'player.png'}
+
+  plugins.preload 'voxel-fly', {flySpeed: 0.8}
+  plugins.preload 'voxel-walk', {}

   game.mode = 'survival'

@@ -147,25 +147,25 @@
   #playerInventory.give new ItemPile('plankOak', 10)
   #playerInventory.give new ItemPile('logBirch', 5)
   #playerInventory.give new ItemPile('workbench', 1)
-  plugins.preload 'inventory-hotbar', {inventory:playerInventory, inventorySize:10}
-
-  plugins.preload 'inventory-dialog', {playerInventory:playerInventory}
+  plugins.preload 'voxel-inventory-hotbar', {inventory:playerInventory, inventorySize:10}
+
+  plugins.preload 'voxel-inventory-dialog', {playerInventory:playerInventory}

   REACH_DISTANCE = 8
-  plugins.preload 'reach', { reachDistance: REACH_DISTANCE }
+  plugins.preload 'voxel-reach', { reachDistance: REACH_DISTANCE }
   # left-click hold to mine
-  plugins.preload 'mine', {
+  plugins.preload 'voxel-mine', {
     timeToMine: (target) =>
       # the innate difficulty of mining this block
       blockID = game.getBlock(target.voxel)
-      blockName = plugins.all.registry?.getBlockName(blockID)
-      hardness = plugins.all.registry?.getBlockProps(blockName)?.hardness
+      blockName = plugins.get('voxel-registry')?.getBlockName(blockID)
+      hardness = plugins.get('voxel-registry')?.getBlockProps(blockName)?.hardness
       hardness ?= 9

       # effectiveness of currently held tool, shortens mining time
-      heldItem = plugins.all['inventory-hotbar']?.held()
+      heldItem = plugins.get('voxel-inventory-hotbar')?.held()
       speed = 1.0
-      speed = plugins.all.registry?.getItemProps(heldItem?.item)?.speed ? 1.0
+      speed = plugins.get('voxel-registry')?.getItemProps(heldItem?.item)?.speed ? 1.0
       finalTimeToMine = Math.max(hardness / speed, 0)
       # TODO: more complex mining 'classes', e.g. shovel against dirt, axe against wood

@@ -177,10 +177,10 @@
   }

   # right-click to place block (etc.)
-  plugins.preload 'use', {}
+  plugins.preload 'voxel-use', {}

   # handles 'break' event from voxel-mine (left-click hold breaks blocks), collects block and adds to inventory
-  plugins.preload 'harvest', {
+  plugins.preload 'voxel-harvest', {
     playerInventory:playerInventory,
     block2ItemPile: (blockName) ->
       # TODO: use registry? more data-driven
@@ -196,7 +196,7 @@
   }

   # highlight blocks when you look at them
-  highlight = plugins.preload 'highlight', {
+  highlight = plugins.preload 'voxel-highlight', {
     color:  0xff0000
     distance: REACH_DISTANCE
     adjacentActive: () -> false   # don't hold <Ctrl> for block placement (right-click instead, 'reach' plugin)
@@ -204,16 +204,16 @@

   # the GUI window (built-in toggle with 'H')
   gui = new datgui.GUI()
-  plugins.preload 'debug', {gui:gui}
-  plugins.preload 'plugins-ui', {gui:gui}
-  plugins.preload '!kb-bindings-ui', {gui:gui, kb:game.buttons}
+  plugins.preload 'voxel-debug', {gui:gui}
+  plugins.preload 'voxel-plugins-ui', {gui:gui}
+  plugins.preload 'kb-bindings-ui', {gui:gui, kb:game.buttons}

   plugins.loadOrderly()
   ## plugins are loaded from here on out ##

   # recipes
-  recipes = plugins.all['!craftingrecipes']
+  recipes = plugins.get('craftingrecipes')
   recipes.thesaurus.registerName 'wood.log', new ItemPile('logOak')
   recipes.thesaurus.registerName 'wood.log', new ItemPile('logBirch')
   recipes.thesaurus.registerName 'wood.plank', new ItemPile('plankOak')
@@ -234,50 +234,51 @@
     [undefined, 'stick', undefined]], new ItemPile('pickaxeDiamond', 1))

-  avatar = plugins.all.player
+  avatar = plugins.get('voxel-player')
   avatar.pov('first');
   avatar.possess()
   home(avatar)

   # load textures after all plugins loaded (since they may add their own)
-  game.materials.load plugins.all.registry.getBlockPropsAll 'texture'
-  global.InventoryWindow_defaultGetTexture = (itemPile) => plugins.all.registry.getItemPileTexture(itemPile)
-
-  plugins.disable 'fly'
+  registry = plugins.get('voxel-registry')
+  game.materials.load registry.getBlockPropsAll 'texture'
+  global.InventoryWindow_defaultGetTexture = (itemPile) => registry.getItemPileTexture(itemPile)
+
+  plugins.disable 'voxel-fly'

   # one of everything, please..
   creativeInventoryArray = []
-  for props in plugins.all.registry.blockProps
+  for props in registry.blockProps
     creativeInventoryArray.push(new ItemPile(props.name, Infinity)) if props.name?

   survivalInventoryArray = []

   game.buttons.down.on 'pov', () -> avatar.toggle() # TODO: disable/re-enable voxel-walk in 1st/3rd person?
-  game.buttons.down.on 'vr', () -> plugins.toggle 'oculus'
+  game.buttons.down.on 'vr', () -> plugins.toggle 'voxel-oculus'
   game.buttons.down.on 'home', () -> home(avatar)
-  game.buttons.down.on 'inventory', () -> plugins.all['inventory-dialog']?.toggle()
-  inventoryHotbar = plugins.all['inventory-hotbar']
+  game.buttons.down.on 'inventory', () -> plugins.get('voxel-inventory-dialog')?.toggle()
+  inventoryHotbar = plugins.get('voxel-inventory-hotbar')
   game.buttons.down.on 'gamemode', () ->
     # TODO: add gamemode event? for plugins to handle instead of us
     if game.mode == 'survival'
       game.mode = 'creative'
-      plugins.enable 'fly'
-      plugins.all.mine?.instaMine = true
+      plugins.enable 'voxel-fly'
+      plugins.get('voxel-mine')?.instaMine = true
       survivalInventoryArray = inventoryHotbar.inventory.array
       inventoryHotbar.inventory.array = creativeInventoryArray
       inventoryHotbar.refresh()
       console.log 'creative mode'
     else
       game.mode = 'survival'
-      plugins.disable 'fly'
-      plugins.all.mine?.instaMine = false
+      plugins.disable 'voxel-fly'
+      plugins.get('voxel-mine')?.instaMine = false
       inventoryHotbar.inventory.array = survivalInventoryArray
       inventoryHotbar.refresh()
       console.log 'survival mode'

   # show origin
-  plugins.all.debug?.axis [0, 0, 0], 10
+  plugins.get('voxel-debug').axis [0, 0, 0], 10

   return game


Enable hiding genes or alleles in chromosome view

--- app/views/dragon-chromosome-pulldown-view.coffee
+++ app/views/dragon-chromosome-pulldown-view.coffee
@@ -2,7 +2,9 @@
 EventTypes = require 'event-types'

 module.exports = class DragonChromosomePulldownView
-  constructor: (@dragon, domId)->
+  constructor: (@dragon, domId, {@hiddenGenes, @hiddenAlleles})->
+    @hiddenAlleles ?= []
+    @hiddenGenes ?= []
     @div = $(domId)[0]
     @species = BioLogica.Species.Dragon

@@ -37,11 +39,13 @@
     unless chromo is 'XY' and side is 'B' and @dragon.sex is BioLogica.MALE
       # Allele pulldowns
       for gene in genes
+        continue if gene in @hiddenGenes
         sel = document.createElement 'select'
         sel.name = "#{chromoLabel}#{side}-#{gene}"
         sel.classList.add gene
         chromoElem.appendChild sel
         for allele in @species.geneList[gene].alleles
+          continue if allele in @hiddenAlleles
           opt = document.createElement 'option'
           opt.value = allele
           opt.innerHTML = allele


client: removed unused file

client: removed unused file

--- client/Social/Activity/views/activityinnernavigation.coffee
+++ client/Social/Activity/views/activityinnernavigation.coffee
@@ -1,22 +0,0 @@
-class ActivityInnerNavigation extends CommonInnerNavigation
-
-  viewAppended:->
-
-    filterController = @setListController
-      type: "filterme"
-      itemClass: CommonInnerNavigationListItem
-    , @filterMenuData
-
-    @addSubView filterController.getView()
-    filterController.selectItem filterController.getItemsOrdered().first
-
-    KD.getSingleton('mainController').on "AccountChanged", (account)=>
-      filterController.reset()
-      filterController.selectItem filterController.getItemsOrdered()[0]
-
-  filterMenuData :
-    title: 'FILTER'
-    items: [
-      {title: "Public",    type: "Public" },
-      {title: "Following", type: "Followed", role: "member" }
-    ]


Activity: privte messages markdown styling WIP

--- client/Social/Activity/views/privatemessage/listitem.coffee
+++ client/Social/Activity/views/privatemessage/listitem.coffee
@@ -54,7 +54,7 @@
         {{> @author}} {{> @timeView }} {{> @timeAgoView}} {{> @likeView}}
       </div>
       {{> @editWidgetWrapper}}
-      {article{KD.utils.formatContent #(body)}}
+      {article.has-markdown{KD.utils.formatContent #(body)}}
       {{> @embedBox}}
     </div>
     """


account: change href for ssh key help link

--- client/account/lib/views/accountsshkeylistcontroller.coffee
+++ client/account/lib/views/accountsshkeylistcontroller.coffee
@@ -96,7 +96,7 @@
       @sshKeyHelpLink = new KDCustomHTMLView
         cssClass : 'ssh-key-help'
         partial  : """
-          How to delete ssh key from your VM
+          How to delete ssh key from your VM
         """
       @getListView().addSubView @sshKeyHelpLink


Fix returning back to homepage from Koding logo issue

--- client/app/MainApp/maincontroller/mainviews/mainview.coffee
+++ client/app/MainApp/maincontroller/mainviews/mainview.coffee
@@ -111,8 +111,10 @@
       partial   : ""
       click     : (event)=>
         KD.utils.stopDOMEvent event
-        homeRoute = if KD.isLoggedIn() then "/Activity" else "/"
-        KD.getSingleton('router').handleRoute homeRoute, {entryPoint}
+        if KD.isLoggedIn()
+          KD.getSingleton('router').handleRoute "/Activity", {entryPoint}
+        else
+          location.replace '/'

     wrapper.addSubView loginLink = new CustomLinkView
       domId       : 'header-sign-in'


Client: Sidebar: Updated profile link by isSoloProductLite flag

--- client/app/lib/commonviews/linkviews/profilelinkview.coffee
+++ client/app/lib/commonviews/linkviews/profilelinkview.coffee
@@ -5,7 +5,7 @@
 JView = require '../../jview'
 LinkView = require './linkview'
 isKoding = require 'app/util/isKoding'
-
+isSoloProductLite = require 'app/util/issoloproductlite'

 module.exports = class ProfileLinkView extends LinkView

@@ -49,11 +49,10 @@

     href = if payload?.channelIntegrationId
       "/Admin/Integrations/Configure/#{payload.channelIntegrationId}"
+    else if isSoloProductLite() or not nickname or not isKoding()
+      "/#"
     else
-      if isKoding() and nickname
-      then "/#{nickname}"
-      else "/#"
-
+      "/#{nickname}"

     @setAttribute "href", href  if href


Fix editing IRs after clicking annotation

--- client/controllers/curatorInbox/curatorSourceDetails.coffee
+++ client/controllers/curatorInbox/curatorSourceDetails.coffee
@@ -148,7 +148,7 @@
   'click span.annotation': (event, instance) ->
     incidentId = $(event.currentTarget).data('incident-id')
     Modal.show 'incidentModal',
-      incident: instance.incidentCollection.findOne(incidentId)
+      incident: Incidents.findOne(incidentId)
       articles: [instance.source.get()]
       edit: true
       updateEvent: false


Teamwork: Additional cssClasses for chat items.

--- client/landing/CollaborativeWorkspace/panes/chatitem.coffee
+++ client/landing/CollaborativeWorkspace/panes/chatitem.coffee
@@ -2,7 +2,7 @@

   constructor: (options, data) ->

-    options.cssClass = KD.utils.curry "chat-item", options.cssClass
+    options.cssClass = KD.utils.curry "tw-chat-item", options.cssClass

     super options, data

@@ -22,7 +22,8 @@
       cssClass   : "time-ago"
     , new Date @getOptions().time

-    @messageList.addSubView new KDCustomHTMLView
+    @messageList.addSubView @message = new KDCustomHTMLView
+      cssClass   : "tw-chat-body"
       partial    : Encoder.XSSEncode @getOptions().body

     @setClass "mine" if ownMessage


payment controller: code cleanup

payment controller: code cleanup

--- client/landing/app/MainApp/payment/paymentcontroller.coffee
+++ client/landing/app/MainApp/payment/paymentcontroller.coffee
@@ -23,14 +23,6 @@
       else
         JRecurlyPlan.setUserAccount newData, callback

-  fetchBillingInfo: (type, callback) ->
-
-    { JRecurlyPlan } = KD.remote.api
-
-    if type in ['group', 'expensed']
-      getGroup().fetchBillingInfo callback
-    else
-      JRecurlyPlan.getAccount callback

   getSubscription: do ->
     findActiveSubscription = (subs, planCode, callback) ->
@@ -108,16 +100,16 @@
     { JRecurlyPlan } = KD.remote.api

     switch type
-      when 'group'
-        debugger
+      when 'group', 'expensed'
+        getGroup().fetchBillingInfo callback
       when 'user'
         JRecurlyPlan.getAccount callback

   updateBillingInfo: (billingInfo, callback) ->

-    { JRecurlyPlan } = KD.remote.api
+    { JRecurly } = KD.remote.api

-    JRecurlyPlan.setUserAccount newData, (err, result)->
+    JRecurly.setBillingInfo billingInfo, (err, result)->
       debugger


Stop doing hard stuff on every request

Stop doing hard stuff on every request

--- server/lib/session_authentication.coffee
+++ server/lib/session_authentication.coffee
@@ -1,11 +1,10 @@
 _ = require('underscore')

 httpVerbWhitelist = ['GET']
+if process.env.NODE_ENV is 'production'
+  httpVerbWhitelist = []

 module.exports = (req, res, next) ->
-  if process.env.NODE_ENV is 'production'
-    httpVerbWhitelist = []
-
   return next() if /^\/login/.test(req.path)
   return next() if process.env.NODE_ENV == 'test'
   return next() if req.isAuthenticated() or _.contains(httpVerbWhitelist, req.method)


include category in autogenerated slug so that proposals with same name under different categories can exist

--- @client/new_proposal.coffee
+++ @client/new_proposal.coffee
@@ -354,10 +354,11 @@
                   fields[field] = fetch("#{field}-new-proposal-#{cluster_slug}").html

                 description = proposal_fields.create_description(fields)
-                slug = slugify(name)
                 active = true
                 hide_on_homepage = false
                 category = @refs.category.getDOMNode().value
+                slug = slugify("#{name}-#{category}")
+
                 if current_user.is_admin && @local.category == 'new category'
                   category = @refs.new_category.getDOMNode().value or cluster_name


Optimize jpg images too

Optimize jpg images too

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -213,15 +213,14 @@

     # Imagemin
     imagemin:
-      png:
+      images:
         options:
           optimizationLevel: 7
         files: [{
           expand: true
           cwd: 'dist/images/'
-          src: ['**/*.png']
+          src: ['**/*.{png,jpg,gif}']
           dest: 'dist/images/'
-          ext: '.png'
         }]

   # Dependencies


move js lint stuff to lint target

move js lint stuff to lint target

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1314,7 +1314,6 @@
 # This is the target run by Travis. Targets in here should run locally
 # and on Travis/Sauce Labs.
 taskManager.add 'test', [
-  'exec:lintFirefoxJs'
   'test_lib'
   'test_core'
   'test_ui'
@@ -1331,6 +1330,7 @@

 taskManager.add 'lint', [
   'tslint'
+  'exec:lintFirefoxJs'
 ]

 taskManager.add 'dist', [


Minify and generate docco as part of default watch task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -41,6 +41,5 @@
     grunt.loadNpmTasks 'grunt-contrib-watch'
     grunt.loadNpmTasks 'grunt-docco'

-    grunt.registerTask 'compile', ['coffee', 'concat']
+    grunt.registerTask 'compile', ['coffee', 'concat', 'uglify', 'docco']
     grunt.registerTask 'default', ['compile', 'watch']
-    grunt.registerTask 'release', ['compile', 'uglify', 'docco']


Reorder gruntfile

Reorder gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -18,7 +18,6 @@
       css         : 'source/quo.css.coffee'
       element     : 'source/quo.element.coffee'
       environment : 'source/quo.environment.coffee'
-
       events      : 'source/quo.events.coffee'
       gestures    : 'source/quo.gestures.coffee'
       output      : 'source/quo.output.coffee'
@@ -26,37 +25,33 @@
       quojs       : 'source/*.coffee'
       spec        : 'spec/*.coffee'

-
     concat:
-      core        : files: '<%=meta.build%>/<%=meta.file%>.coffee': '<%= source.core %>'
-      spec        : files: '<%=meta.build%>/<%=meta.file%>.spec.coffee': '<%= source.spec %>'
+      core        : files: '<%=meta.build%>/<%=meta.file%>.coffee'            : '<%= source.core %>'
+      spec        : files: '<%=meta.build%>/<%=meta.file%>.spec.coffee'       : '<%= source.spec %>'

     coffee:
-      core        : files: '<%= meta.build %>/<%= meta.file %>.js': '<%=meta.build%>/<%=meta.file%>.coffee'
-      ajax        : files: '<%= meta.build %>/<%= meta.file %>.ajax.js': '<%=source.ajax%>'
-      css         : files: '<%= meta.build %>/<%= meta.file %>.css.js': '<%=source.css%>'
-      element     : files: '<%= meta.build %>/<%= meta.file %>.element.js': '<%=source.element%>'
+      core        : files: '<%= meta.build %>/<%= meta.file %>.js'            : '<%=meta.build%>/<%=meta.file%>.coffee'
+      ajax        : files: '<%= meta.build %>/<%= meta.file %>.ajax.js'       : '<%=source.ajax%>'
+      css         : files: '<%= meta.build %>/<%= meta.file %>.css.js'        : '<%=source.css%>'
+      element     : files: '<%= meta.build %>/<%= meta.file %>.element.js'    : '<%=source.element%>'
       environment : files: '<%= meta.build %>/<%= meta.file %>.environment.js': '<%=source.environment%>'
-
-      events      : files: '<%= meta.build %>/<%= meta.file %>.events.js': '<%=source.events%>'
-      gestures    : files: '<%= meta.build %>/<%= meta.file %>.gestures.js': '<%=source.gestures%>'
-      output      : files: '<%= meta.build %>/<%= meta.file %>.output.js': '<%=source.output%>'
-      query       : files: '<%= meta.build %>/<%= meta.file %>.query.js': '<%=source.query%>'
-      spec        : files: '<%= meta.build %>/<%= meta.file %>.spec.js': '<%=meta.build%>/<%=meta.file%>.spec.coffee'
+      events      : files: '<%= meta.build %>/<%= meta.file %>.events.js'     : '<%=source.events%>'
+      gestures    : files: '<%= meta.build %>/<%= meta.file %>.gestures.js'   : '<%=source.gestures%>'
+      output      : files: '<%= meta.build %>/<%= meta.file %>.output.js'     : '<%=source.output%>'
+      query       : files: '<%= meta.build %>/<%= meta.file %>.query.js'      : '<%=source.query%>'
+      spec        : files: '<%= meta.build %>/<%= meta.file %>.spec.js'       : '<%=meta.build%>/<%=meta.file%>.spec.coffee'

     uglify:
       options: mangle: false, banner: "<%= meta.banner %>", report: "gzip"
-      core        : files: '<%= meta.bower %>/<%= meta.file %>.js': '<%= meta.build %>/<%= meta.file %>.js'
-      element     : files: '<%= meta.bower %>/<%= meta.file %>.element.js': '<%= meta.build %>/<%= meta.file %>.element.js'
+      core        : files: '<%= meta.bower %>/<%= meta.file %>.js'            : '<%= meta.build %>/<%= meta.file %>.js'
+      ajax        : files: '<%= meta.bower %>/<%= meta.file %>.ajax.js'       : '<%= meta.build %>/<%= meta.file %>.ajax.js'
+      css         : files: '<%= meta.bower %>/<%= meta.file %>.css.js'        : '<%= meta.build %>/<%= meta.file %>.css.js'
+      element     : files: '<%= meta.bower %>/<%= meta.file %>.element.js'    : '<%= meta.build %>/<%= meta.file %>.element.js'
       environment : files: '<%= meta.bower %>/<%= meta.file %>.environment.js': '<%= meta.build %>/<%= meta.file %>.environment.js'
-
-      ajax        : files: '<%= meta.bower %>/<%= meta.file %>.ajax.js': '<%= meta.build %>/<%= meta.file %>.ajax.js'
-      events      : files: '<%= meta.bower %>/<%= meta.file %>.events.js': '<%= meta.build %>/<%= meta.file %>.events.js'
-      gestures    : files: '<%= meta.bower %>/<%= meta.file %>.gestures.js': '<%= meta.build %>/<%= meta.file %>.gestures.js'
-      output      : files: '<%= meta.bower %>/<%= meta.file %>.output.js': '<%= meta.build %>/<%= meta.file %>.output.js'
-      query       : files: '<%= meta.bower %>/<%= meta.file %>.query.js': '<%= meta.build %>/<%= meta.file %>.query.js'
-      css         : files: '<%= meta.bower %>/<%= meta.file %>.css.js': '<%= meta.build %>/<%= meta.file %>.css.js'
-
+      events      : files: '<%= meta.bower %>/<%= meta.file %>.events.js'     : '<%= meta.build %>/<%= meta.file %>.events.js'
+      gestures    : files: '<%= meta.bower %>/<%= meta.file %>.gestures.js'   : '<%= meta.build %>/<%= meta.file %>.gestures.js'
+      output      : files: '<%= meta.bower %>/<%= meta.file %>.output.js'     : '<%= meta.build %>/<%= meta.file %>.output.js'
+      query       : files: '<%= meta.bower %>/<%= meta.file %>.query.js'      : '<%= meta.build %>/<%= meta.file %>.query.js'

     jasmine:
       pivotal:
@@ -66,17 +61,16 @@
           '<%=meta.bower%>/<%= meta.file %>.css.js',
           '<%=meta.bower%>/<%= meta.file %>.element.js',
           '<%=meta.bower%>/<%= meta.file %>.environment.js',
+          '<%=meta.bower%>/<%= meta.file %>.events.js',
+          '<%=meta.bower%>/<%= meta.file %>.gestures.js',
           '<%=meta.bower%>/<%= meta.file %>.output.js',
           '<%=meta.bower%>/<%= meta.file %>.query.js']
         options:
           specs: '<%=meta.build%>/<%=meta.file%>.spec.js',

     notify:
-      core:
-        options: title: 'Quo Core', message: 'Build!'
       spec:
         options: title: 'Quo Spec', message: 'Test 100% passed!'
-

     watch:
       core:
@@ -94,7 +88,6 @@
       environment:
         files: ['<%= source.environment %>']
         tasks: ['coffee:environment', 'uglify:environment']
-
       events:
         files: ['<%= source.events %>']
         tasks: ['coffee:events', 'uglify:events']
@@ -114,8 +107,6 @@
         files: ['<%= source.spec %>']
         tasks: ['concat:spec', 'coffee:spec', 'jasmine', 'notify:spec']

-
-
   grunt.loadNpmTasks 'grunt-contrib-concat'
   grunt.loadNpmTasks 'grunt-contrib-coffee'
   grunt.loadNpmTasks 'grunt-contrib-uglify'
@@ -123,5 +114,4 @@
   grunt.loadNpmTasks 'grunt-notify'
   grunt.loadNpmTasks 'grunt-contrib-watch'

-  # Default task.
   grunt.registerTask 'default', ['concat', 'coffee', 'uglify', 'jasmine']


Grunt: Use standard MicroFlo arduino build target

Also specify library so we don't get stub components

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -62,7 +62,7 @@
             level: 'warn'

     exec:
-      build_arduino: "#{microflo_make} GRAPH=graphs/PortalLights.fbp build-arduino-min"
+      build_arduino: "#{microflo_make} GRAPH=graphs/PortalLights.fbp LIBRARY=arduino-standard build-arduino"
       build_tiva: "#{microflo_make} STELLARIS_GRAPH=graphs/TableLights.fbp build-stellaris"

   # Grunt plugins used for building


Fix version setter bug

Fix version setter bug

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -211,9 +211,8 @@

       writeVersion:
         command: (appName, version) ->
-          content = "module.#{appName}.version = '#{version}';"
-          content = content.replace(/[0-9a-zA-Z]+-/, '')
-          content = content.replace(/'/g, "''")
+          appName = appName.replace(/-/g, '')
+          content = "module.#{appName}.version = \"#{version}\";"
           "mkdir -p tmp; echo '#{content}' >> tmp/version.js"

       make:


fix(lint): map grunt lint to coffeelint to enable both (#256)

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -129,6 +129,7 @@
   grunt.registerTask 'doc', ['shell:doc']
   grunt.registerTask 'doc:publish', ['build', 'shell:doc', 'shell:doc_publish']
   grunt.registerTask 'build', ['clean', 'coffeelint', 'coffee', 'concat']
+  grunt.registerTask 'lint', ['coffeelint']
   grunt.registerTask 'test', 'Run test with optional target', (target) ->
     suffix = if target then "-#{target}" else ''
     grunt.task.run 'build', "shell:jasmine#{suffix}"


Removing when library from rallymetrics bundle as it is only used in the tests

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -111,7 +111,7 @@
         src: ['src/main.js'],
         dest: 'bundle.js',
         options:
-          external: [ 'underscore', 'when' ],
+          external: [ 'underscore' ],
           alias: ['src/main.js:RallyMetrics']

     'browserify-object':
@@ -129,11 +129,11 @@
         objectToExport: "require('RallyMetrics')"
         globalAlias: 'RallyMetrics'
         deps:
-          'default': ['_', 'when']
-          amd: ['underscore', 'when']
-          cjs: ['underscore', 'when']
-          global: ['_', 'when']
-        browserifyMapping: '{"underscore":_, "when": when}'
+          'default': ['_']
+          amd: ['underscore']
+          cjs: ['underscore']
+          global: ['_']
+        browserifyMapping: '{"underscore":_}'

     open:
       docs:


[hotfix] Remove es5 flag on jshint task because in jshint 2 break the build if its set

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -102,7 +102,6 @@
       files:        [ '<%= SERVER_DIR + JS_FILES %>'
                       '<%= CLIENT_DIR + JS_FILES %>' ]
       options:
-        es5:        true
         laxcomma:   true  # Common in Express-derived libraries

     # Browser-based testing


feat(grunt): auto release task

feat(grunt): auto release task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -352,6 +352,9 @@

       amsf__theme__to_dev_repo:
         command: "rsync -avz --delete --progress --exclude=.git --exclude=node_modules <%= amsf.base %>/themes/<%= amsf.theme.current %>/ /Users/sparanoid/Git/amsf-<%= amsf.theme.current %> > rsync-theme-dev.log"
+
+      amsf__release:
+        command: "git checkout release && git pull && git merge master --no-edit && git push && git checkout master && git push"

     concurrent:
       options:
@@ -630,6 +633,10 @@
       "replace:amsf__site__update_version"
       "bump-commit"
     ]
+    if grunt.option("publish")
+      grunt.task.run [
+        "shell:amsf__release"
+      ]

   grunt.registerTask "deploy-rsync", "Deploy to remote server via rsync",  [
     "shell:amsf__deploy__rsync"


Run coffeelint on pieces

Run coffeelint on pieces

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -13,7 +13,7 @@
         ]

     coffeelint:
-      bacon: [ 'dist/Bacon.coffee' ]
+      bacon: [ 'src/*.coffee' ]
       options:
         configFile: 'coffeelint.json'


Any change forces reload

Any change forces reload

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -146,12 +146,12 @@
       # Changes to app code should be validated and re-copied to the `build`, triggering `regarde:build`
       js:
         files:      '<%= CLIENT_DIR + JS_FILES %>'
-        tasks:      [ 'copy:js', 'parallel:jshint' ]
+        tasks:      [ 'copy:js', 'parallel:jshint', 'livereload' ]

       # Changes to app styles should re-compile, triggering `regarde:build`
       less:
         files:      '<%= CLIENT_DIR + LESS_FILES %>'
-        tasks:      [ 'less' ]
+        tasks:      [ 'less', 'livereload' ]

       # Changes to server-side code should validate, restart the server, & refresh the browser
       server:
@@ -161,7 +161,7 @@
       # Changes to app templates should re-copy & re-compile them, triggering `regarde:build`
       templates:
         files:      '<%= CLIENT_DIR + HTML_FILES %>'
-        tasks:      [ 'copy:templates', 'ngtemplates' ]
+        tasks:      [ 'copy:templates', 'ngtemplates', 'livereload' ]

     # Express requires `server.script` to reload from changes
     server:


Set correct remote URL, refs component/component#447

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -42,11 +42,11 @@
       bower_install:
         command: 'node ./node_modules/bower/bin/bower install -F'
       main_install:
-        command: 'node ./node_modules/component/bin/component install'
+        command: 'node ./node_modules/component/bin/component install -r https://raw.githubusercontent.com'
       main_build:
         command: 'node ./node_modules/component/bin/component build -u component-json,component-fbp,component-coffee -o browser -n noflo-ui -c'
       preview_install:
-        command: 'node ./node_modules/component/bin/component install'
+        command: 'node ./node_modules/component/bin/component install -r https://raw.githubusercontent.com'
         cwd: 'preview'
       preview_build:
         command: 'node ./node_modules/component/bin/component build -u component-json,component-fbp,component-coffee -o browser -n noflo-ui-preview -c'


Add launch task

Add launch task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -9,8 +9,8 @@
         dest: 'chrome-app/lib/pomodoro.min.js'

     watch:
-      files: 'src/*.coffee'
-      tasks: ['test','compile']
+      files: ['src/*.coffee','chrome-app/**','!chrome-app/lib/**']
+      tasks: ['test','compile','launch']
       options:
         livereload:
           port: 9000
@@ -34,6 +34,9 @@
       browserify:
         cmd: 'browserify -t coffeeify src/*.coffee > chrome-app/lib/pomodoro.js'

+      runPomodoro:
+        cmd: 'run-pomodoro.sh'
+
   grunt.loadNpmTasks 'grunt-contrib-concat'
   grunt.loadNpmTasks 'grunt-contrib-uglify'
   grunt.loadNpmTasks 'grunt-contrib-watch'
@@ -41,4 +44,5 @@

   grunt.registerTask 'default', ['watch']
   grunt.registerTask 'compile', ['bgShell:browserify','uglify']
-  grunt.registerTask 'test', ['bgShell:runMochaTests']+  grunt.registerTask 'test', ['bgShell:runMochaTests']
+  grunt.registerTask 'launch', ['bgShell:runPomodoro']


Fixed grunt html watcher and paths

Fixed grunt html watcher and paths

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -4,6 +4,7 @@
   grunt.initConfig
     pkg: grunt.file.readJSON("package.json")
     paths:
+      static: "static"
       build: "static/build"
       src: "static/src"
       deploy: "static/dist"
@@ -84,10 +85,10 @@
     targethtml:
       dev:
         files:
-          "static/index.html": "<%= paths.html %>/index.html"
+          "<%= paths.static %>/index.html": "<%= paths.html %>/index.html"
       prod:
         files:
-          "static/index.html": "<%= paths.html %>/index.html"
+          "<%= paths.static %>/index.html": "<%= paths.html %>/index.html"

     ##
     ## Watcher Configuation
@@ -107,8 +108,8 @@
         tasks: ["jade"]

       html:
-        files: ["html/index.html"]
-        tasks: ["env:dev"]
+        files: ["<%= paths.html %>/index.html"]
+        tasks: ["targethtml:dev"]

     concurrent:
       build: ["coffee", "sass:build", "jade", "targethtml:dev"]


resauce

resauce

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -407,10 +407,10 @@
   @registerTask 'test', [
     'coffeelint:app'
     'inlinelint'
-    # 'build'
-    # 'coffee'
-    # 'connect'
-    # 'saucelabs-mocha'
+    'build'
+    'coffee'
+    'connect'
+    'saucelabs-mocha'
   ]
   @registerTask 'app', ['build', 'phonegap-build']
   @registerTask 'default', ['test']


Simplify the copy.

Simplify the copy.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -8,28 +8,19 @@
       prod:
         NODE_ENV: 'production'

-    preprocess:
-      # Note: This 'preprocess' task is actually used to post-process
-      # the Javascript in place after it is compiled from CoffeeScript.
-      js:
-        src: '_public/javascripts/config.js'
-      options:
-        inline: true
-
     clean:
       # Note: Grunt 0.4.5 file.js has an invalid test for whether the
       #   target is contained in the cwd. Work-around is the force option.
-      # Note: the odd _public patterns are the most concise way to delete
-      #   all of the _public tree except for the data directory and the
-      #   jspm package directory _public/javascripts/lib defined in
-      #   package.json. The entries:
-      #     '_public/**', '!_public/javascripts/lib'
-      #   deletes the entire _public tree. Given
+      # Note: the odd public patterns are the most concise way to delete
+      #   all of the public tree except for the data and jspm_packages
+      #   subdirectories. The entries:
+      #     'public/**', '!public/jspm_packages/**'
+      #   deletes the entire public tree. Given
       #   https://github.com/cbas/grunt-rev/issues/16, this is probably
       #   a grunt bug, although it is unclear how the force option is
       #   intended to modify the behavior in this case.
-      derived: ['_build', '_public/*.*', '_public/*/*', '!_public/data',
-                '!_public/javascripts/lib']
+      derived: ['_build', 'public/*', 'public/*/**', '!public/data/**',
+                '!public/jspm_packages/**']
       options:
         force: true

@@ -38,21 +29,22 @@
         module: "commonjs"
         emitDecoratorMetadata: true
         sourceMap: true
+        sourceRoot: 'app'
         removeComments: false
         verbose: true
       default:
         expand: true
         cwd: 'app/'
-        src: ['javascripts/*.ts']
-        dest: '_public/'
+        src: ['**/*.ts']
+        dest: 'public/'

     coffee:
       default:
         expand: true
         ext: '.js'
         cwd: 'app/'
-        src: ['javascripts/*.coffee']
-        dest: '_public/'
+        src: ['**/*.coffee']
+        dest: 'public/'

     jade:
       options:
@@ -61,16 +53,16 @@
         expand: true
         ext: '.html'
         cwd: 'app/'
-        src: ['index.jade', 'partials/**/*.jade', '!**/include/**']
-        dest: '_public/'
+        src: ['**/*.jade', '!**/include/**']
+        dest: 'public/'

     markdown:
       default:
         expand: true
         ext: '.html'
         cwd: 'app/'
-        src: ['partials/**/*.md']
-        dest: '_public/'
+        src: ['**/*.md']
+        dest: 'public/'

     stylus:
       options:
@@ -80,28 +72,35 @@
         ]
       default:
         src: ['app/stylesheets/app.styl']
-        dest: '_public/static/stylesheets/app.css'
+        dest: 'public/stylesheets/app.css'

     copy:
       # The native applicaton JavaScript files.
       js:
         expand: true
         cwd: 'app/'
-        src: ['javascripts/*.js']
-        dest: '_public/'
+        src: ['**/*.js']
+        dest: 'public/'

       # The applicaton TypeScript files.
       ts:
         expand: true
         cwd: 'app/'
-        src: ['javascripts/*.ts']
-        dest: '_public/'
+        src: ['**/*.ts']
+        dest: 'public/'
+
+      # The applicaton JSON files.
+      json:
+        expand: true
+        cwd: 'app/'
+        src: ['**/*.json']
+        dest: 'public/'

       # The images and icons.
       static:
         expand: true
         src: ['static/**']
-        dest: '_public/'
+        dest: 'public/'

       # Note: this task is only used to copy CSS map files. The
       # CSS style files themselves are copied to the destination
@@ -115,7 +114,7 @@
         flatten: true
         cwd: 'node_modules/'
         src: ['bootstrap/dist/css/bootstrap.css.map']
-        dest: '_public/static/stylesheets/'
+        dest: 'public/stylesheets/'

       fonts:
         expand: true
@@ -125,7 +124,15 @@
         #   e.g. 4.0.4/index.html, can't be excluded
         #   (cf. https://github.com/gruntjs/grunt-contrib-copy/issues/13).
         src: ['bootstrap/dist/fonts/*', 'font-awesome/fonts/*']
-        dest: '_public/fonts/'
+        dest: 'public/fonts/'
+
+    sync:
+      # Copy changed app TypeScript files.
+      ts:
+        expand: true
+        cwd: 'app/'
+        src: ['**/*.js']
+        dest: 'public/'

     concat:
       css:
@@ -133,7 +140,29 @@
           'node_modules/bootstrap/dist/css/bootstrap.css'
           'node_modules/font-awesome/css/font-awesome.css'
         ]
-        dest: '_public/static/stylesheets/vendor.css'
+        dest: 'public/stylesheets/vendor.css'
+
+    concurrent:
+      options:
+        logConcurrentOutput: true
+      compile:
+        tasks: ['coffee', 'jade', 'markdown', 'stylus']
+
+    cssmin:
+      options:
+        'nomunge': true
+        'line-break': 80
+      files:
+        src: ['public/stylesheets/app.css']
+        dest: 'public/stylesheets/app.min.css'
+
+    browserSync:
+      options:
+        watchTask: true
+        proxy: 'http:3000'
+      bsFiles:
+        src:
+          'public/**'

     karma:
       options:
@@ -146,9 +175,11 @@
     exec:
       # Convert CommonJS modules to AMD.
       convert:
-        command:
-          './node_modules/.bin/r.js -convert _build/commonjs _public/javascripts/lib'
-
+        command: './node_modules/.bin/r.js -convert _build/commonjs public/lib'
+
+      # This task is used in preference to grunt-selenium-standalone to
+      # suppress extraneous console messages and wait for the server to
+      # start.
       selenium:
         # If selenium is not already running, then start it. Suppress all
         # output, since there are no documented options to tailor the
@@ -165,12 +196,13 @@
         #
         #   pkill -f selenium-standalone
         #
-        # The sleep command pauses one second to allow the server to start.
+        # The sleep command pauses half a second to allow the server to start.
+        # Otherwise, grunt might exit and kill the process aborning.
         command: 'lsof -i :4444 >/dev/null 2>&1 || ' +
                  '(./node_modules/selenium-standalone/bin/selenium-standalone' +
                  '   install --silent && ' +
                  ' ((./node_modules/selenium-standalone/bin/selenium-standalone' +
-                 '   start >/dev/null 2>&1 &) && sleep 1))'
+                 '   start >/dev/null 2>&1 &) && sleep .5))'

       updatewebdriver:
         command: './node_modules/protractor/bin/webdriver-manager update'
@@ -199,6 +231,9 @@
       typescript:
         files: ['app/**/*.ts']
         tasks: ['copy:ts']
+      json:
+        files: ['app/**/*.json']
+        tasks: ['copy:json']
       coffee:
         files: ['app/**/*.coffee']
         tasks: ['coffee']
@@ -214,20 +249,6 @@
       markdown:
         files: ['app/partials/**/*.md']
         tasks: ['markdown']
-
-    concurrent:
-      options:
-        logConcurrentOutput: true
-      compile:
-        tasks: ['compile:coffee', 'jade', 'markdown', 'stylus']
-
-    cssmin:
-      options:
-        'nomunge': true
-        'line-break': 80
-      files:
-        src: ['_public/stylesheets/app.css']
-        dest: '_public/stylesheets/app.min.css'
   )

   # Load all grunt-* tasks.
@@ -236,23 +257,14 @@
   # Build for development is the default.
   grunt.registerTask 'default', ['build:dev']

-  # Assemble the app.
-  grunt.registerTask 'copy:app', ['copy:js', 'copy:ts', 'copy:cssmap',
-                                  'copy:fonts', 'copy:static']
-
-  # Compile the app CoffeeScript.
-  grunt.registerTask 'compile:coffee', ['coffee', 'preprocess']
-
   # Compile the app bits concurrently.
   grunt.registerTask 'compile', ['concurrent:compile']

   # Build the application from scratch.
-  grunt.registerTask 'build:app', ['clean', 'copy:app', 'concat:css',
-                                   'compile']
+  grunt.registerTask 'build:app', ['clean', 'copy', 'concat:css', 'compile']

   # Build the app and test environment.
-  grunt.registerTask 'build:dev', ['env:dev', 'build:app',
-                                   'exec:updatewebdriver']
+  grunt.registerTask 'build:dev', ['env:dev', 'build:app', 'exec:updatewebdriver']

   # Build the app for deployment.
   grunt.registerTask 'build:prod', ['env:prod', 'build:app']
@@ -261,10 +273,7 @@
   grunt.registerTask 'postinstall', ['build:prod']

   # Start the server with debug turned on.
-  grunt.registerTask 'start:dev', ['express:dev', 'watch']
-
-  # Start the server in test mode.
-  grunt.registerTask 'start:test', ['express:test', 'watch']
+  grunt.registerTask 'start:dev', ['express:dev', 'watch', 'sync']

   # Start the server in production mode.
   grunt.registerTask 'start:prod', ['express:prod']
@@ -276,8 +285,7 @@
   grunt.registerTask 'test:unit', ['karma:unit']

   # Run the Protractor end-to-end tests.
-  grunt.registerTask 'test:e2e', ['exec:selenium', 'express:test',
-                                  'protractor:e2e']
+  grunt.registerTask 'test:e2e', ['exec:selenium', 'express:test', 'protractor:e2e']

   # Run all tests.
   grunt.registerTask 'test', ['test:unit', 'test:e2e']


fix for samples target

fix for samples target

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -25,7 +25,7 @@
   'echoServerFirefoxApp'
   'simpleSocksChromeApp'
   'simpleSocksFirefoxApp'
-  'copyPasteSocksChromeApp'
+  'copyPasteSocks'
   'simpleTurnChromeApp'
   'simpleChurnChatChromeApp'
   'copyPasteChurnChatChromeApp'


extend grunt watcher

extend grunt watcher

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -36,6 +36,8 @@
       source:
         files: [
           "_sass/**/*"
+          "javascripts/**/*"
+          "index.html"
         ]
         tasks: [
           "sass"


Remove unused line

Remove unused line

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,4 +1,5 @@
 { dirname, filename, extname, sep } = require 'path'
+
 firstDirname = (filepath) ->
   filepath.split(sep)[0]
 secondDirname = (filepath) ->
@@ -14,10 +15,8 @@
         dirs: [
           'keymaps/**/*'
           'lib/**/*'
-          'menus/**/*'
           'spec/**/*'
           'stylesheets/**/*'
-          'node_modules/atom-refactor/**/*'
         ]
         livereload:
           enabled: false
@@ -27,6 +26,7 @@
   grunt.loadNpmTasks 'grunt-este-watch'

   grunt.registerTask 'apm:test', ->
+    start = new Date().getTime()
     done = @async()
     grunt.util.spawn
       cmd: 'apm'
@@ -36,6 +36,7 @@
         grunt.util.error err
       if result?
         grunt.log.writeln result
+      grunt.log.writeln "#{(new Date().getTime() - start) / 1000}sec"
       done()

   grunt.registerTask 'default', [


Resize on resize

Resize on resize

--- js/views/VizView.coffee
+++ js/views/VizView.coffee
@@ -19,7 +19,10 @@

     @server = options.server

-    @listenTo(@model, 'change:ignore change:serverResponse', @render)
+    @_renderCallback = @render.bind(@)
+
+    @listenTo(@model, 'change:ignore change:serverResponse', @_renderCallback)
+    window.addEventListener('resize', @_renderCallback, false)

   render: ->
     @initialRender() if !@svg?
@@ -45,7 +48,7 @@

     @fontSize
       .domain([ minCount, maxCount ])
-      .rangeRound([ Math.round(w / 100), Math.round(w / 12) ])
+      .rangeRound([ Math.round(w / 90), Math.round(w / 12) ])

     @texts
       .attr('transform', "translate(#{w >> 1},#{h >> 1})")
@@ -191,3 +194,7 @@
   onClickIgnore: (el) ->
     token = Backbone.$(el.currentTarget).attr('data-token')
     @model.addIgnore(token)
+
+  remove: ->
+    super()
+    window.removeEventListener(@_renderCallback)


Add ensureOperation spec helper for testing un-keymapped commands

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -287,6 +287,13 @@
       method = 'ensure' + _.capitalize(_.camelize(name))
       this[method](options[name])

+  ensureOperation: (operation, options) =>
+    atom.commands.dispatch(atom.views.getView(@editor), operation)
+
+    for name in ensureOptionsOrdered when options[name]?
+      method = 'ensure' + _.capitalize(_.camelize(name))
+      this[method](options[name])
+
   ensureText: (text) ->
     expect(@editor.getText()).toEqual(text)


fix(build): Fix lint errors

fix(build): Fix lint errors

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -1,6 +1,6 @@
 _ = require 'underscore'
 _str = require 'underscore.string'
-_ = _.extend(_, require('../src/config-utils'));
+_ = _.extend(_, require('../src/config-utils'))

 fs = require 'fs-plus'
 path = require 'path'
@@ -197,7 +197,7 @@

   # reset config before each spec; don't load or save from/to `config.json`
   fakePersistedConfig = {}
-  spyOn(Config::, 'getRawValues').andCallFake () =>
+  spyOn(Config::, 'getRawValues').andCallFake =>
     fakePersistedConfig
   spyOn(Config::, 'setRawValue').andCallFake (keyPath, value) =>
     if (keyPath)


fix not showing any desktop notification

--- packages/rocketchat-ui/lib/notification.coffee
+++ packages/rocketchat-ui/lib/notification.coffee
@@ -31,7 +31,7 @@

 	showDesktop: (notification) ->
 		if not window.document.hasFocus?() and Meteor.user().status isnt 'busy'
-			@KonchatNotification._showDesktop(notification)
+			KonchatNotification._showDesktop(notification)

 	newMessage: ->
 		unless Session.equals('user_' + Meteor.userId() + '_status', 'busy') or Meteor.user()?.settings?.preferences?.disableNewMessageNotification


Include original stack trace if present. Usually from a compiler error.

--- compiler/SDKError.coffee
+++ compiler/SDKError.coffee
@@ -45,7 +45,12 @@
         url = DOCS[subject][code]
     else
         url = DOCS[subject]
-    return new Error("#{ colors.error(message) } See: #{ colors.underline(colors.help(url)) }\n")
+
+    if message.stack
+        post_message = "\nOriginal stack trace:\n#{ colors.yellow(message.stack) }\n"
+    else
+        post_message = ''
+    return new Error("#{ colors.error(message) } See: #{ colors.underline(colors.help(url)) }\n#{ post_message }")


Fixed the config to not include underscore in the vendor output.

--- config.coffee
+++ config.coffee
@@ -23,7 +23,7 @@
         'javascripts/frimfram.js': /^src/
         '../dist/frimfram.js': /^src/
         'javascripts/app.js': /^app/
-        'javascripts/vendor.js': /^(vendor|bower_components)/
+        'javascripts/vendor.js': /^(vendor|bower_components)(?![\/\\]underscore[\/\\])/
         'javascripts/test-app.js': /^test[\/\\]app/
         'javascripts/demo-app.js': /^test[\/\\]demo/

@@ -35,7 +35,7 @@
           'bower_components/jquery/dist/jquery.js'
           'bower_components/lodash/lodash.js'
           'bower_components/backbone/backbone.js'
-          'bower_components/bootstrap/dist/bootstrap.js'
+          'bower_components/bootstrap/dist/js/bootstrap.js'
           'bower_components/tv4/tv4.js'
          ]


global error handler

global error handler

--- app.coffee
+++ app.coffee
@@ -2,6 +2,9 @@
 express = require 'express'
 fetcher = require './fetcher'
 app = express()
+
+process.on 'uncaughtException', (err) ->
+	console.log err

 app.get '/query', (req, res) ->
 	if req.query.id? and req.query.password?


Debug config and env

Debug config and env

--- app.coffee
+++ app.coffee
@@ -23,4 +23,7 @@
   require('./config/controllers')(app)
   require('./config/routes')(app, passport)

+  console.log config
+  console.log process.env
+
   app.listen(config.server.port, config.server.hostname)


Added some code comments

Added some code comments

--- source/assets/app/javascripts/base.js.coffee
+++ source/assets/app/javascripts/base.js.coffee
@@ -1,19 +1,10 @@
 $ = jQuery
 po = org.polymaps
-
 radius = 5
-
 tips = {}
-
 features = []

-# loadFeatures = (e) ->
-#   console.log e.features
-#   for f in e.features
-#     f.element.setAttribute("r", radius)
-#     if f.data.properties.data['Vorgehen_Code'] is "3"
-#       $(f.element).addClass("green")
-#       console.log("green")
+# Polymaps Stylist Event Handlers

 styleFeatures = po.stylist()
   .attr("r", radius)
@@ -21,6 +12,8 @@

 styleCounties = po.stylist()
   .attr("class", "county")
+
+# Tooltip Event Handlers

 loadTooltips = (e) ->
   for f in e.features
@@ -83,6 +76,7 @@
     })
   tip.toggle

+# Setup map
 map = po.map()
 .container(document.getElementById("map").appendChild(po.svg("svg")))
 .center({lon: 8.596677185140349, lat: 46.77841693384364})
@@ -91,15 +85,19 @@
 .on("move", moveTooltips)
 .on("resize", moveTooltips)

+# Add map background tiles
 map.add(po.image()
 .url(po.url("http://{S}tile.cloudmade.com/1a1b06b230af4efdbb989ea99e9841af/998/256/{Z}/{X}/{Y}.png")
 .hosts(["a.", "b.", "c.", ""])))

+# DOM Loaded:
 $ ->
   map_offset = $("#map").offset()
   $("#map").css({
     #height: $(document).height() - map_offset.top
   })
+
+  # Load points, then add them to the map
   $.get "media/data/vbs-belastete-standorte.json", (data) ->
     # console.log data

@@ -121,7 +119,8 @@
       .on("load", loadTooltips)
       .on("show", showTooltips)
       .features(features)
-
+
+  # Load county shapes, then add them to the map
   $.get "media/maps/schweiz_gemeinden_geojson.json", (data) ->
     # console.log data
     p = po.geoJson()


Add lint config

Add lint config

--- etc/atom/config.cson
+++ etc/atom/config.cson
@@ -12,7 +12,6 @@
     'showIndentGuide': true
     'softWrapAtPreferredLineLength': true
     'fontSize': 14
-    'invisibles': {}
   'core':
     'themes': [
       'atom-dark-ui'
@@ -26,5 +25,6 @@
   'atom-beautify':
     '_analyticsUserId': '542ad6ff-4e4a-479a-bee1-7e619cab00b0'
     'analytics': false
-    'beautifyEntireFileOnSave': false
     'js_jslint_happy': true
+  'linter':
+    'lintOnChange': false


:lipstick:

:lipstick:

--- src/packages/gists/lib/gists.coffee
+++ src/packages/gists/lib/gists.coffee
@@ -8,7 +8,7 @@
   constructor: ->
     rootView.command 'gist:create', '.editor', => @createGist()

-  createGist: (editor) ->
+  createGist: ->
     editor = rootView.getActiveView()
     return unless editor?


Fix paths for update locking and resin-kill-me

--- src/application.coffee
+++ src/application.coffee
@@ -249,11 +249,11 @@

 lockPath = (app) ->
 	appId = app.appId ? app
-	return "/mnt/root/resin-data/#{appId}/resin-updates.lock"
+	return "/resin-data/#{appId}/resin-updates.lock"

 killmePath = (app) ->
 	appId = app.appId ? app
-	return "/mnt/root/resin-data/#{appId}/resin-kill-me"
+	return "/resin-data/#{appId}/resin-kill-me"

 # At boot, all apps should be unlocked *before* start to prevent a deadlock
 application.unlockAndStart = unlockAndStart = (app) ->


bug fix

bug fix

--- src/plugins/faction/fallback.coffee
+++ src/plugins/faction/fallback.coffee
@@ -11,7 +11,7 @@
         r = FactionUtil.parseCallingBody item

         FactionUtil.send Bot.getTemplate([
-            ['@{player}'],
+            ['@{player} '],
             [
                 '呵呵'
                 '嗯?'


added error for no messages to select

added error for no messages to select

--- src/public/javascripts/index.coffee
+++ src/public/javascripts/index.coffee
@@ -93,6 +93,9 @@
   if count != 0
     $(this).text(new_text)
     $(this).data('state', new_state)
+  else
+    # Display an error that there are no messages to select
+    utils.flash 'info', 'No messages to select.'

 if $('#create_message').length
   # Create the Quill editor


MER-41: remove invalid comment.

MER-41: remove invalid comment.

--- src/spec/product-import.spec.coffee
+++ src/spec/product-import.spec.coffee
@@ -4,7 +4,6 @@
 Config = require('../config')
 Promise = require 'bluebird'
 fs = require('fs')
-#This should be done in beforeAll method.
 sampleProducts = require('../samples/import.json')
 sampleProductProjectionsResponse = require('../samples/product_projection_response.json')


FIX: Rework submission wizard for needs help

Students were getting confused as to how to upload work
after it was submitted as 'need help'. Previously this
required student to click the "ready to mark", then
click "ready to mark" again in the file uploader ( as
it defaulted to the previous state). Now this updates
the state of the task when the status is changed in the
task viewer.

--- src/app/tasks/task-viewer/task-viewer.coffee
+++ src/app/tasks/task-viewer/task-viewer.coffee
@@ -151,6 +151,7 @@
     $scope.triggerTransition = (status) ->
       if (status == 'ready_to_mark' || status == 'need_help') and $scope.project.selectedTask.definition.upload_requirements.length > 0
         $scope.setActiveTab($scope.tabs.fileUpload)
+        $scope.project.selectedTask.status = status
         return # handle with the uploader...
       else
         taskService.updateTaskStatus($scope.unit, $scope.project, $scope.project.selectedTask, status)


k8s: minor changes to project manager (nothing really)

--- src/k8s/smc-project/manager/image/run.coffee
+++ src/k8s/smc-project/manager/image/run.coffee
@@ -83,7 +83,7 @@
                     if z[field] != x.new_val[field]
                         z[field] = x.new_val[field]
                         changed[field] = true
-                if state == 'ready' and z['run'] and not changed.run and (changed.resources or changed.preemptible or changed.disk_size or changed.storage_ready or changed.idle_timeout)
+                if state == 'ready' and z['run'] and not changed.run and (changed.resources or changed.preemptible or changed.disk_size or changed.storage_ready)
                     # Currently running with no change to run state.
                     # Something changed which can be done via editing the deployment using kubectl
                     kubectl_update_project(project_id)
@@ -159,10 +159,12 @@
                 process(line)

         r.on 'exit', (code) ->
-            throw "kubectl terminated -- #{code}"
+            log("kubectl terminated normally", code)
+            throw "kubectl terminated (code=#{code})"

         r.on 'error', (err) ->
-            throw "kubectl subprocess error -- #{err}"
+            log("kubectl subprocess error", err)
+            throw "kubectl subprocess error (err=#{err})"

         cb?()

@@ -420,11 +422,3 @@
             log("SUCCESSFULLY INITIALIZED; now RUNNING")

 main()
-
-# For debugging/dev
-exports.main = main
-exports.connect_to_rethinkdb = connect_to_rethinkdb
-exports.init_kubectl_watch = init_kubectl_watch
-exports.init_projects_changefeed = init_projects_changefeed
-exports.projects = projects
-exports.get_all_storage_servers = get_all_storage_servers


Remove unused script

Remove unused script

--- src/main/assets/javascripts/bootstrap.coffee
+++ src/main/assets/javascripts/bootstrap.coffee
@@ -1,4 +0,0 @@
-jQuery ->
-  $("a[rel=popover]").popover()
-  $(".tooltip").tooltip()
-  $("a[rel=tooltip]").tooltip()


adjust the way to show insertion

adjust the way to show insertion

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -89,6 +89,7 @@
 					self.hideInsertion()
 			else
 				self.showInsertion()
+				self.setInsertionTop thisOffset.top - parentOffset.top + height
 	bindTo: (jqel)->
 		self = @
 		jqel.on 'mousemove', (e)->


Fix popup open

Fix popup open

--- app/services/popup.coffee
+++ app/services/popup.coffee
@@ -2,7 +2,7 @@

 PopupService = Ember.Service.extend
   open: (name) ->
-    @closeAll()
+    @close()
     name = event?.target?.name || name
     $("##{name}").toggleClass('display')
   close: ->


Update deprecated selectors in keymap

Update deprecated selectors in keymap

--- keymaps/go-to-line.cson
+++ keymaps/go-to-line.cson
@@ -1,15 +1,15 @@
 '.platform-darwin, .platform-win32, .platform-linux':
   'ctrl-g': 'go-to-line:toggle'

-'.go-to-line .mini.editor input':
+'.go-to-line atom-text-editor[mini]':
   'enter': 'core:confirm',
   'escape': 'core:cancel'

-'.platform-darwin .go-to-line .mini.editor input':
+'.platform-darwin .go-to-line atom-text-editor[mini]':
   'cmd-w': 'core:cancel'

-'.platform-win32 .go-to-line .mini.editor input':
+'.platform-win32 .go-to-line atom-text-editor[mini]':
   'ctrl-w': 'core:cancel'

-'.platform-linux .go-to-line .mini.editor input':
+'.platform-linux .go-to-line atom-text-editor[mini]':
   'ctrl-w': 'core:cancel'


Add getSelection method. Make getCursor return editors cursor var.

--- src/atom/editor.coffee
+++ src/atom/editor.coffee
@@ -175,8 +175,10 @@
       else
         @scrollLeft() + @width()

+    getCursor: -> @cursor
+    getSelection: -> @selection
+
     getCurrentLine: -> @buffer.getLine(@getCursorRow())
-    getCursor: -> @selection.cursor
     moveCursorUp: -> @cursor.moveUp()
     moveCursorDown: -> @cursor.moveDown()
     moveCursorRight: -> @cursor.moveRight()


Update activitylistitem.coffee

Update activitylistitem.coffee

--- client/Social/Activity/views/activitylistitem.coffee
+++ client/Social/Activity/views/activitylistitem.coffee
@@ -139,7 +139,7 @@

     body = fn body for fn in fns
     body = KD.utils.expandUsernames body, 'code'
-    body = emojify.replace body
+    body = emojify.replace body, 'code'

     return body


activity: render channel info container inside scroller

--- client/activity/lib/components/chatpane/index.coffee
+++ client/activity/lib/components/chatpane/index.coffee
@@ -54,6 +54,7 @@
     <Scroller
       ref="scrollContainer"
       onTopThresholdReached={@bound 'onTopThresholdReached'}>
+      {@renderChannelInfoContainer()}
       <ChatList
         isMessagesLoading={@props.thread?.getIn ['flags', 'isMessagesLoading']}
         loadedWithScroll={@props.thread?.getIn ['flags', 'loadedWithScroll']}
@@ -70,7 +71,6 @@

-          {@renderChannelInfoContainer()}
           {@renderBody()}
           {@props.children}


Correctly summarize composition input changes

--- src/trix/controllers/input_controller.coffee
+++ src/trix/controllers/input_controller.coffee
@@ -2,7 +2,7 @@
 #= require trix/operations/file_verification_operation

 {handleEvent, findClosestElementFromNode, findElementFromContainerAndOffset,
-  defer, makeElement, innerElementIsActive} = Trix
+  defer, makeElement, innerElementIsActive, summarizeStringChange} = Trix

 inputLog = Trix.Logger.get("input")

@@ -237,7 +237,8 @@
       if composedString? and composedString isnt @inputSummary.compositionStart
         @delegate?.inputControllerWillPerformTyping()
         @responder?.insertString(composedString)
-        @setInputSummary(textAdded: composedString, didDelete: @selectionIsExpanded())
+        {added, removed} = summarizeStringChange(@inputSummary.compositionStart, composedString)
+        @setInputSummary(textAdded: added, didDelete: Boolean(removed))

     input: (event) ->
       event.stopPropagation()


Lots of rendering enhancements

Lots of rendering enhancements

--- app.coffee
+++ app.coffee
@@ -9,12 +9,11 @@
 config(app)
 middleware(app)

-app.get '/', (req, res) ->
+app.get /^\/(\.(\w+))?$/, (req, res) ->
   today = dateLookup(moment().format("YYYY-MM-DD"))
   tomorrow = dateLookup(moment().add('days', 1).format('YYYY-MM-DD'))
-  res.format(
-
-    'text/plain': ->
+  response =
+    text: ->
       textResponse =  'Voiko tänään mennä baariin Töölössä?\n\n'
       if today
         textResponse += 'No ei voi ku on peli. '
@@ -28,10 +27,30 @@
           textResponse += 'Mut huomenna ei voi.'
         else
           textResponse += 'Niin voi huomennakin!'
+      res.type('text/plain')
       res.send 200, textResponse
-    'application/json': ->
-      res.send(200, q: 'Voiko tänään mennä baariin Töölössä?', a: {today: !today, tomorrow: !tomorrow})
-  )
+    json: ->
+      res.type('application/json')
+      res.send 200, q: 'Voiko tänään mennä baariin Töölössä?', a: {today: !today, tomorrow: !tomorrow}
+    # html: ->
+    #   res.type('text/html')
+    #   res.send 200, '<html></html>'
+
+  if req.params[1]? && req.params[1] != ''
+    if response[req.params[1]]?
+      response[req.params[1]]()
+    else
+      res.type 'text/plain'
+      res.render 406, 'Not acceptabble'
+  else
+    res.format(response)
+
+app.get '/time', (req, res) ->
+  res.type('text/plain')
+  text = "Today: #{moment().format("YYYY-MM-DD")}
+  \nTime: #{moment().format()}
+  \nTimezone: #{moment().format('ZZ')}"
+  res.send 200, text

 port = Number(process.env.PORT || 5000)


remove unnecessary comma

remove unnecessary comma

--- app.coffee
+++ app.coffee
@@ -10,7 +10,7 @@
   connection:
     host : 'localhost'
     user : 'foon'
-    database : 'foon',
+    database : 'foon'
     charset : 'utf8'
 )
 bookshelf = require('bookshelf')(knex)


Remove use of deprecated express API

Remove use of deprecated express API

> express deprecated res.send(status, body):
> Use res.status(status).send(body) instead

--- app.coffee
+++ app.coffee
@@ -201,11 +201,11 @@
 			# hash first because Woltlab Community Framework uses double salted hashes
 			bcrypt.hash reqAuth.pass, auth.users[reqAuth.name].passwd, (err, hash) ->
 				if err?
-					res.send 500, '500 Internal Server Error'
+					res.status(500).send '500 Internal Server Error'
 					return
 				bcrypt.compare hash, auth.users[reqAuth.name].passwd, (err, result) ->
 					if err?
-						res.send 500, '500 Internal Server Error'
+						res.status(500).send '500 Internal Server Error'
 						return
 					if result
 						callback reqAuth.name
@@ -444,7 +444,7 @@
 askForCredentials = (req, res) ->
 	res.type 'txt'
 	res.setHeader 'WWW-Authenticate', 'Basic realm="Please provide proper username and password to access this package"'
-	res.send 401, 'Please provide proper username and password to access this package'
+	res.status(401).send 'Please provide proper username and password to access this package'

 app.all '/', (req, res) ->
 	callback = (username) ->
@@ -557,7 +557,7 @@
 		do writer.endElement
 		do writer.endDocument
 		res.setHeader 'Last-Modified', lastUpdate.toUTCString()
-		res.send 200, (do writer.toString).replace /\{\{packageServerHost\}\}/g, host
+		res.status(200).send (do writer.toString).replace /\{\{packageServerHost\}\}/g, host

 	checkAuth req, res, callback

@@ -569,12 +569,12 @@
 				if isAccessible username, req.params[0], req.params[1]
 					debug "#{username} downloaded #{req.params[0]}/#{req.params[1].toLowerCase()}"
 					logDownload req.params[0], req.params[1]
-					res.download "#{config.packageFolder}/#{req.params[0]}/#{req.params[1].toLowerCase()}.tar", "#{req.params[0]}_v#{req.params[1]}.tar", (err) -> res.send 404, '404 Not Found' if err?
+					res.download "#{config.packageFolder}/#{req.params[0]}/#{req.params[1].toLowerCase()}.tar", "#{req.params[0]}_v#{req.params[1]}.tar", (err) -> res.status(404).send '404 Not Found' if err?
 				else
 					debug "#{username} tried to download #{req.params[0]}/#{req.params[1].toLowerCase()}"
 					askForCredentials req, res
 			else
-				res.send 404, '404 Not Found'
+				res.status(404).send '404 Not Found'

 	checkAuth req, res, callback

@@ -583,7 +583,7 @@
 	host = config.basePath ? "#{req.protocol}://#{req.header 'host'}"
 	versionNumber = packageList?[req.params[0]]?.packageinformation?.version[0]
 	unless versionNumber?
-		res.send 404, '404 Not Found'
+		res.status(404).send '404 Not Found'
 		return
 	res.redirect 301, "#{host}/#{req.params[0]}/#{versionNumber.toLowerCase().replace (new RegExp ' ', 'g'), '_'}"

@@ -594,7 +594,7 @@
 		readPackages -> res.redirect 303, config.basePath ? "#{req.protocol}://#{req.header 'host'}/"

 # throw 404 on any unknown route
-app.all '*', (req, res) -> res.send 404, '404 Not Found'
+app.all '*', (req, res) -> res.status(404).send '404 Not Found'

 # Once the package list was successfully scanned once bind to the port
 readPackages -> app.listen config.port, config.ip


Add comment about tar entry stream consuming

--- app.coffee
+++ app.coffee
@@ -311,6 +311,7 @@
 									debug "Found #{entryHeader.name} in #{versionFile}"
 									if entryHeader.name isnt 'package.xml' or entryHeader.type isnt 'file'
 										entryStream.on 'end', -> do entryCallback
+										# we have to consume the entire stream, before parsing continues
 										do entryStream.resume
 										return
 									packageXmlFound = yes


redis

redis

--- app.coffee
+++ app.coffee
@@ -49,8 +49,7 @@
 app.set 'view engine', 'ejs'
 app.set 'views', path.join(__dirname, 'views')
 app.set 'view options', { layout: 'layout.ejs' }
-# uncomment after placing your favicon in /public
-#app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
+app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
 app.use partials()
 app.use logger('dev')
 app.use bodyParser.json()


Wrong method

Wrong method

--- app.coffee
+++ app.coffee
@@ -67,7 +67,7 @@
   if app_env == "production"
     # Start listening to a unix socket.

-    fs.futimesSync config.faye.socket, new Date(), new Date()
+    fs.utimesSync config.faye.socket, new Date(), new Date()
     fs.unlinkSync config.faye.socket

     oldmask = process.umask(0o0000)
@@ -84,7 +84,7 @@
   if app_env == "production"
     # Start listening to the secure port using SSL.

-    fs.futimesSync config.faye.socketSecure, new Date(), new Date()
+    fs.utimesSync config.faye.socketSecure, new Date(), new Date()
     fs.unlinkSync config.faye.socketSecure

     oldmask = process.umask(0o0000)


got rid of coffee test file, just gonna keep everything in javascript

--- app.coffee
+++ app.coffee
@@ -1,84 +0,0 @@
-window.app = new Backbone.Marionette.Application()
-
-app = window.app
-
-app.addRegions
-	mainRegion: '#content'
-
-console.log 'hello world'
-
-PilotModel = Backbone.Model.extend
-	defaults:
-		name: 'Unassigned',
-		rank: '--',
-		team: '--',
-		level: 0,
-		shipId: 0
-
-ShipModel = Backbone.Model.extend
-	defaults:
-		name: 'Unassigned'
-		health: 0
-		speed: 0
-		storage: 0
-
-# data
-raw = {}
-raw.Pilots = [
-	{id: 1, name: 'James T Kirk', rank: 'Captan', team: 'Federation', shipId: 1},
-	{id: 2, name: 'Gene Starwind', rank: 'Capitan', team: 'Space Pirates', shipId: 2},
-	{id: 3, name: 'Luke Skywalker', rank: 'Jedi Knight', team: 'Rebellion', shipId: 3},
-	{id: 4, name: 'Jack Sparrow', rank: 'Admiral', team: 'Pirates', shipId: 0}
-];
-raw.Ships = [
-	{id: 1, name: 'USS Enterprise', health: 100, speed: 5, storage: 19},
-	{id: 2, name: 'Outlaw Star', health: 75, speed: 6, storage: 11},
-	{id: 3, name: 'X-Wing Fighter', health: 100, speed: 5, storage: 2}
-];
-
-# data pools
-app.data = {}
-app.data.Pilots = new Backbone.Collection raw.Pilots
-app.data.Ships 	= new Backbone.Collection raw.Ships
-
-app.module "List", (List,app,Backbone,Marionette,$,_) ->
-	# Views
-	# -----
-
-	# Show a pilot
-	List.PilotItemView = Backbone.Marionette.ItemView.extend
-		template: '#tpl-PilotItemView',
-		tagName: 'tr',
-		tagClass: 'pilot-row',
-
-		models:
-			ship: (baseModel) ->
-				ship = app.data.Ships.get baseModel.id
-				if typeof ship != 'undefined'
-					ship
-				else
-					new ShipModel()
-
-		serializeData: ->
-			data = this.model.toJSON();
-			baseModel = this.model
-			_.each this.models, (getModel, index) ->
-				data[index] = getModel(baseModel).toJSON()
-			data
-
-	# show a list of Pilots
-	List.PilotListView = Backbone.Marionette.CompositeView.extend
-		itemView: List.PilotItemView
-		itemViewContainer: 'tbody'
-		template: '#tpl-PilotListView'
-
-	# initalizer
-	List.addInitializer = ->
-		console.log "hello world"
-		listView = new List.PilotListView
-			collection: app.data.Pilots
-		listView.render()
-		app.mainRegion.show listView
-	null
-
-console.log "bye bye from app.js"


removed unecessary authentication

removed unecessary authentication

--- app.coffee
+++ app.coffee
@@ -81,10 +81,10 @@
 app.get '/account', authenticated, (req, res) ->
   res.send user: req.user

-angularResource app, '/api/1', 'feeds', authenticated
-angularResource app, '/api/1', 'startups', authenticated
-angularResource app, '/api/1', 'users', authenticated
-angularResource app, '/api/1', 'jobs', authenticated
+angularResource app, '/api/1', 'feeds'
+angularResource app, '/api/1', 'startups'
+angularResource app, '/api/1', 'users'
+angularResource app, '/api/1', 'jobs'

 seed.init () ->
   http.createServer(app).listen app.get('port'), () ->


Support showing file hash in XML comment

--- app.coffee
+++ app.coffee
@@ -37,6 +37,7 @@
 tar = require 'tar'
 bcrypt = require 'bcrypt'
 watchr = require 'watchr'
+crypto = require 'crypto'

 xml =
 	parser: (require 'xml2js').Parser
@@ -68,6 +69,7 @@
 config.packageFolder += '/' unless /\/$/.test config.packageFolder
 config.enableManualUpdate ?= on
 config.enableStatistics ?= on
+config.enableHash ?= on

 # initialize express
 app = do express
@@ -396,10 +398,22 @@
 										currentVersion.requiredpackages = versionPackageXml.package?.requiredpackages?[0]
 										currentVersion.excludedpackages = versionPackageXml.package?.excludedpackages?[0]
 										currentVersion.timestamp = versionFileStat.mtime
-										currentPackage.versions[versionNumber] = currentVersion

-										logger.log "debug", "Finished parsing #{versionFile}"
-										versionsCallback null
+										finish = ->
+											currentPackage.versions[versionNumber] = currentVersion
+
+											logger.log "debug", "Finished parsing #{versionFile}"
+											versionsCallback null
+
+										if config.enableHash
+											hash = new crypto.Hash 'sha256'
+											fileStream = fs.createReadStream versionFile
+											fileStream.pipe hash
+											fileStream.on 'end', ->
+												currentVersion.hash = do hash.read
+												do finish
+										else
+											setImmediate finish
 							, (err) ->
 								if err?
 									fileCallback err
@@ -474,6 +488,7 @@

 				writer.writeAttribute 'accessible', if (isAccessible username, _package.name, versionNumber) then "true" else "false"
 				writer.writeAttribute 'critical', if (/pl/i.test versionNumber) then "true" else "false"
+				writer.writeComment "sha256:#{version.hash.toString 'hex'}" if config.enableHash

 				# write <fromversions>
 				if version.fromversions?.length


whitespace

whitespace

--- app.coffee
+++ app.coffee
@@ -4,6 +4,7 @@
 now = require("now")
 redis = require("redis")
 client = redis.createClient(9010, 'bass.redistogo.com')
+
 dbAuth = () -> client.auth('e212a2dcfe7eed6c849ddfce6c6c0e15')
 client.addListener('connected', dbAuth)
 client.addListener('reconnected', dbAuth)


Updated trackers

Updated trackers

--- app.coffee
+++ app.coffee
@@ -1,8 +1,9 @@
 trackers = [
-  [ 'udp://tracker.publicbt.com:80' ],
   [ 'udp://tracker.openbittorrent.com:80' ],
-  [ 'udp://open.demonii.com:1337' ],
-  [ 'udp://tracker.webtorrent.io:80' ],
+  [ 'udp://tracker.internetwarriors.net:1337' ],
+  [ 'udp://tracker.leechers-paradise.org:6969' ],
+  [ 'udp://tracker.coppersurfer.tk:6969' ],
+  [ 'udp://exodus.desync.com:6969' ],
   [ 'wss://tracker.webtorrent.io' ],
   [ 'wss://tracker.btorrent.xyz' ]
 ]


fix(table): apply role "group" to subtables

in compliance with http://www.w3.org/TR/wai-aria/roles#list

--- modules/directives/table/index.coffee
+++ modules/directives/table/index.coffee
@@ -3,5 +3,8 @@
 angular.module('bp.directives').directive 'bpTable', ->
   restrict: 'E'
   link: (scope, element, attrs) ->
-    element.attr
-      role: 'list'
+    role = if element.parents('bp-table').length
+      'group'
+    else
+      'list'
+    element.attr {role}


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera_fade.coffee
+++ src/camera_fade.coffee
@@ -53,7 +53,8 @@
       # => Sets the effect variables to their default state. This will the screen to fade from ransparent to black over the next 30 frames.

       camera.fadeOut
-
+        color: blue
+
       # => This effect will start off transparent and change to blue over 50 frames.

   @name fadeOut


Kites: Removed subscribe button on kite details view's header.

--- client/Social/Kites/Views/kitedetailsview.coffee
+++ client/Social/Kites/Views/kitedetailsview.coffee
@@ -6,11 +6,7 @@

     super options, data

-    @timeAgo    = new KDTimeAgoView {}, new Date @getData().createdAt
-    @button     = new KDButtonView
-      title     : "SUBSCRIBE"
-      cssClass  : "run"
-
+    @timeAgo     = new KDTimeAgoView {}, new Date @getData().createdAt
     @productForm = new KiteProductForm null, @getData()
     @productForm.on "PlanSelected", @bound "showPaymentModal"

@@ -56,9 +52,6 @@
             Version 0.1

Released {{> @timeAgo}}

-

-            {{> @button}}
-

     """