Comments

Comments

--- src/ievm.coffee
+++ src/ievm.coffee
@@ -165,6 +165,8 @@
   ensureOvaed: ->
     @ovaed().then (ovaed) -> ovaed or throw new Error 'ova not present'

+  # ### Action Methods
+
   # Start the virtual machine. Throws an exception if it is already running or
   # cannot be started. If the `headless` argument is `false` (the default) then
   # the VM will be started in GUI mode.
@@ -204,6 +206,8 @@
     @debug 'close'
     @exec('taskkill.exe', '/f', '/im', 'iexplore.exe').fail -> Q(true)

+  # Rearm the virtual machine, extending the license for 90 days. Unfortunately,
+  # rearming is only supported by the Win7 virtual machines at this time.
   rearm: (delay=30000) -> @ensureNotMissing().then => @ensureRunning().then =>
     @ensureRearmsLeft().then =>
       @debug 'rearm'
@@ -214,36 +218,46 @@
             @exec('schtasks.exe', '/run', '/tn', 'activate').then =>
               Q.delay(delay).then => @restart()

-  # Uninstall the VM.
+  # Uninstall the virtual machine. Removes the virtual machine and hdd from
+  # VirtualBox, keeping the archive or ova on disk.
   uninstall: -> @ensureNotMissing().then => @ensureNotRunning().then =>
     @debug 'uninstall'
     @vbm 'unregistervm', '--delete'

-  # Install the VM.
+  # Install the virtual machine through ievms. Throws an exception if it is
+  # already installed.
   install: -> @ensureMissing().then =>
     @debug 'install'
     @constructor.ievms @ievmsEnv(), @debug.bind @

-  # Reinstall the VM.
+  # Reinstall the virtual machine through ievms. Throws an exception if it is
+  # running or not installed.
   reinstall: -> @uninstall().then => @install()

-  # Clean the VM.
+  # Restore the virtual machine to the `clean` snapshot created by ievms. Throws
+  # an exception if it is missing or currently running.
   clean: (force=false) -> @ensureNotMissing().then =>
     @ensureNotRunning().then =>
       @debug 'clean'
       @vbm 'snapshot', 'restore', 'clean'

-  # Delete the archive.
+  # Delete the archive file for the virtual machine. If the ova is not present,
+  # the archive must be redownloaded to reinstall the virtual machine. Throws
+  # an exception if the archive is not present.
   unarchive: -> @ensureArchived().then =>
     @debug 'unarchive'
     Q.nfcall fs.unlink, @fullArchive()

-  # Delete the ova.
+  # Delete the ova file for the virtual machine. If the archive is not present,
+  # it must be redownloaded to reinstall the virtual machine. Throws an
+  # exception if the ova is not present.
   unova: -> @ensureOvaed().then =>
     @debug 'unova'
     Q.nfcall fs.unlink, fullOva()

-  # Execute a command in the VM.
+  # Execute a command in the virtual machine. Throws an exception if it is
+  # not installed or not running, or if the command fails. Waits for guest
+  # control before proceeding.
   exec: (cmd, args...) -> @ensureNotMissing().then => @ensureRunning().then =>
     @waitForGuestControl().then =>
       @debug "exec: #{cmd} #{args.join ' '}"
@@ -256,21 +270,14 @@
       ]
       @vbm 'guestcontrol', args...

+  # Take a screenshot of the virtual machine and save it to disk. Throws an
+  # exception if it is not installed or not running, or if the screenshot
+  # command fails.
   screenshot: (file) -> @ensureNotMissing().then => @ensureRunning().then =>
     @debug 'screenshot'
     @vbm 'controlvm', 'screenshotpng', file

-  debug: (msg) ->
-    @_debug ?= debug "iectrl:#{@name}"
-    @_debug msg
-
-  # Build an environment hash to pass to ievms for installation.
-  ievmsEnv: ->
-    IEVMS_VERSIONS: @version
-    REUSE_XP: if @version in [7, 8] and @os is 'WinXP' then 'yes' else 'no'
-    INSTALL_PATH: @constructor.ievmsHome
-    HOME: process.env.HOME
-    PATH: process.env.PATH
+  # ### Attribute Methods

   # Determine the name of the zip file as used by modern.ie.
   archive: ->
@@ -279,6 +286,7 @@
     # Simply replace dashes and spaces with an underscore and add `.zip`.
     "#{@name.replace ' - ', '_'}.zip"

+  # Determine the full path to the archive file.
   fullArchive: -> path.join @constructor.ievmsHome, @archive()

   # Determine the name of the ova file as used by modern.ie.
@@ -286,31 +294,16 @@
     return 'IE6 - WinXP.ova' if @name in ['IE7 - WinXP', 'IE8 - WinXP']
     "#{@name}.ova"

+  # Determine the full path to the ova file.
   fullOva: -> path.join @constructor.ievmsHome, @ova()

   # Generate the full URL to the modern.ie archive.
   url: -> 'http://virtualization.modern.ie/vhd/IEKitV1_Final/VirtualBox/OSX/' +
     @archive()

-  # Run a `VBoxManage` command and promise the stdout contents.
-  vbm: (args...) ->
-    @_vbmQueue ?= Q()
-    @_vbmQueue = @_vbmQueue.then =>
-      deferred = Q.defer()
-      command = @constructor.vbm args.shift(), [@name].concat args
-      child_process.exec command, (err, stdout, stderr) =>
-        return deferred.reject err if err?
-        deferred.resolve stdout
-      deferred.promise
-
-  # Parse the "machinereadable" `VBoxManage` vm info output format.
-  parseInfo: (s) ->
-    obj = {}
-    for line in s.trim().split "\n"
-      pieces = line.split '='
-      obj[pieces.shift()] = pieces.join('=').replace(/^"/, '').replace /"$/, ''
-    obj
-
+  # Retrieve and parse the virtual machine info from `VBoxManage showvminfo`.
+  # If `E_ACCESSDENIED` is caught, the command will be retried up to 3 times
+  # before rejecting the promise.
   info: (retries=3, delay=250) ->
     @vbm('showvminfo', '--machinereadable').then(@parseInfo).fail (err) =>
       return Q VMState: 'missing' if err.message.match /VBOX_E_OBJECT_NOT_FOUND/
@@ -329,7 +322,7 @@
   # the modern.ie website.
   uploaded: ->
     # Return the cached uploaded date if available.
-    return (Q.fcall => @_uploaded) if @_uploaded?
+    return Q @_uploaded if @_uploaded?
     # Defer a 'HEAD' request to the archive URL to determine the `last-modified`
     # time and date.
     deferred = Q.defer()
@@ -345,6 +338,92 @@
     req.end()
     deferred.promise

+  # Promise getter/setter for VM metadata.
+  meta: (data) -> if data? then @setMeta data else @getMeta()
+
+  # Promise a boolean indicating whether the VM is missing.
+  missing: -> @status().then (status) => status is @constructor.status.MISSING
+
+  # Promise a boolean indicating whether the VM is running.
+  running: -> @status().then (status) => status is @constructor.status.RUNNING
+
+  # Promise a boolean indicating whether the VM is expired.
+  expired: -> @expires().then (expires) => !expires? or expires < new Date
+
+  # Promise a boolean indicating whether the archive exists on disk.
+  archived: ->
+    deferred = Q.defer()
+    fs.exists @fullArchive(), (archived) -> deferred.resolve archived
+    deferred.promise
+
+  # Promise a boolean indicating whether the archive exists on disk.
+  ovaed: ->
+    deferred = Q.defer()
+    fs.exists @fullOva(), (ovaed) -> deferred.resolve ovaed
+    deferred.promise
+
+  # Promise a `Date` object representing when the VM will expire.
+  expires: -> @missing().then (missing) =>
+    return null if missing
+    thirtyDays = 30 * 1000 * 60 * 60 * 24
+    ninetyDays = thirtyDays * 3
+
+    # XP virtual machines expire after 30 days from creation. Others get 90.
+    if @os is 'WinXP' then return @hddCreated().then (created) ->
+      new Date created.getTime() + thirtyDays
+
+    # Try to fetch last rearm date from metadata.
+    @rearmDates().then (rearms) =>
+      if rearms.length > 0
+        # Add ninety days to the most recent rearm date.
+        new Date rearms[rearms.length - 1].getTime() + ninetyDays
+      else
+        # Fall back to the original date when the hdd was last modified.
+        @hddCreated().then (created) -> new Date created.getTime() + ninetyDays
+
+  # Promise an array of rearm dates or empty array if none exist.
+  rearmDates: -> @meta().then (meta) =>
+    return [] unless meta.rearms? and meta.rearms.length?
+    new Date d for d in meta.rearms
+
+  # Promise the number of rearms left for the VM.
+  rearmsLeft: -> @rearmDates().then (rearms) =>
+    @constructor.rearms[@os] - rearms.length
+
+  # ### Utilities
+
+  # Output a debug message for the virtual machine.
+  debug: (msg) ->
+    @_debug ?= debug "iectrl:#{@name}"
+    @_debug msg
+
+  # Build an environment hash to pass to ievms for installation.
+  ievmsEnv: ->
+    IEVMS_VERSIONS: @version
+    REUSE_XP: if @version in [7, 8] and @os is 'WinXP' then 'yes' else 'no'
+    INSTALL_PATH: @constructor.ievmsHome
+    HOME: process.env.HOME
+    PATH: process.env.PATH
+
+  # Run a `VBoxManage` command and promise the stdout contents.
+  vbm: (args...) ->
+    @_vbmQueue ?= Q()
+    @_vbmQueue = @_vbmQueue.then =>
+      deferred = Q.defer()
+      command = @constructor.vbm args.shift(), [@name].concat args
+      child_process.exec command, (err, stdout, stderr) =>
+        return deferred.reject err if err?
+        deferred.resolve stdout
+      deferred.promise
+
+  # Parse the "machinereadable" `VBoxManage` vm info output format.
+  parseInfo: (s) ->
+    obj = {}
+    for line in s.trim().split "\n"
+      pieces = line.split '='
+      obj[pieces.shift()] = pieces.join('=').replace(/^"/, '').replace /"$/, ''
+    obj
+
   # Parse the ievms meta data stored in the VirtualBox `extradata`.
   parseMeta: (data) -> JSON.parse data.replace 'Value: ', ''

@@ -353,9 +432,6 @@

   # Promise to get the VM metadata. Returns empty object on failure.
   getMeta: -> @vbm('getextradata', 'ievms').then(@parseMeta).fail (err) -> Q {}
-
-  # Promise getter/setter for VM metadata.
-  meta: (data) -> if data? then @setMeta data else @getMeta()

   # Promise the UUID of the VM's hdd.
   hddUuid: -> @info().then (info) =>
@@ -371,50 +447,7 @@
   # Promise an `fs.stat` object for the VM's base hdd file.
   hddStat: -> @hdd().then (hdd) => Q.nfcall fs.stat, hdd.Location

-  # Promise a `Date` object representing when the VM will expire.
-  expires: -> @missing().then (missing) =>
-    return null if missing
-    ninetyDays = 90 * 1000 * 60 * 60 * 24
-    if @os is 'WinXP' then return @uploaded().then (uploaded) ->
-      new Date uploaded.getTime() + ninetyDays
-    @meta().then (meta) =>
-      if meta.rearms? and meta.rearms.length > 0
-        # Add ninety days to the most recent rearm date.
-        new Date meta.rearms[meta.rearms.length - 1] + ninetyDays
-      else if meta.installed?
-        # Add ninety days to the install date from metadata.
-        new Date meta.installed + ninetyDays
-      else
-        # Fall back to the original date when the hdd was last modified.
-        @hddStat().then (stat) => new Date stat.mtime.getTime() + ninetyDays
-
-  # Promise an array of rearm dates or empty array if none exist.
-  rearms: -> @meta().then (meta) => meta.rearms ? []
-
-  # Promise the number of rearms left for the VM.
-  rearmsLeft: -> @rearms().then (rearms) =>
-    @constructor.rearms[@os] - rearms.length
-
-  # Promise a boolean indicating whether the VM is missing.
-  missing: -> @status().then (status) => status is @constructor.status.MISSING
-
-  # Promise a boolean indicating whether the VM is running.
-  running: -> @status().then (status) => status is @constructor.status.RUNNING
-
-  # Promise a boolean indicating whether the VM is expired.
-  expired: -> @expires().then (expires) => !expires? or expires < new Date
-
-  # Promise a boolean indicating whether the archive exists on disk.
-  archived: ->
-    deferred = Q.defer()
-    fs.exists @fullArchive(), (archived) -> deferred.resolve archived
-    deferred.promise
-
-  # Promise a boolean indicating whether the archive exists on disk.
-  ovaed: ->
-    deferred = Q.defer()
-    fs.exists @fullOva(), (ovaed) -> deferred.resolve ovaed
-    deferred.promise
+  hddCreated: -> @hddStat().then (stat) => stat.mtime

   _waitForStatus: (statuses, deferred, delay=1000) ->
     statuses = [].concat statuses


Only display scoreboard when things have gone successfully.

--- web/coffee/scoreboard.coffee
+++ web/coffee/scoreboard.coffee
@@ -4,10 +4,14 @@
 load_scoreboard = ->
   apiCall "GET", "/api/scoreboard", {}
   .done (data) ->
-    $("#scoreboard-tabs").html renderScoreboardTabs({
-      data: data.data
-      renderScoreboard: renderScoreboard
-    })
+    switch data["status"]
+      when 1
+        $("#scoreboard-tabs").html renderScoreboardTabs({
+          data: data.data
+          renderScoreboard: renderScoreboard
+        })
+      when 0
+        apiNotify(data)

 $ ->
   load_scoreboard()


test(test/e2e/cli-test.coffee): Tweak CacheControl response header value

Removed spaces between response directives. Additionally, corrected misspelled 'cacheing'.

--- test/e2e/cli-test.coffee
+++ test/e2e/cli-test.coffee
@@ -385,7 +385,8 @@
         app.options '/machines', (req, res, next) ->
           allow = ['OPTIONS', 'HEAD', 'GET']
           res.setHeader 'Allow', allow.join ','
-          res.setHeader 'Cache-Control', 'no-cache, no-store, must-revalidate'
+          disableCache = ['no-cache', 'no-store', 'must-revalidate']
+          res.setHeader 'Cache-Control', disableCache.join ','
           res.status(204).end()
           next()

@@ -448,9 +449,9 @@
         allow = optionsResponse.headers['Allow']
         expect(allow).to.equal('OPTIONS,HEAD,GET')

-      it 'OPTIONS response should disable cacheing of it', () ->
+      it 'OPTIONS response should disable caching of it', () ->
         cacheControl = optionsResponse.headers['Cache-Control']
-        expect(cacheControl).to.equal('no-cache, no-store, must-revalidate')
+        expect(cacheControl).to.equal('no-cache,no-store,must-revalidate')

       it 'OPTIONS and HEAD responses should not have bodies', () ->
         expect(optionsResponse.body).to.be.empty


Iterate through current set of testUsers

- See if a user, can GET /users/their.id

--- test/routes/users.coffee
+++ test/routes/users.coffee
@@ -49,15 +49,14 @@
       b.credentials.should.have.property 'secret'
       done()

-  it.skip 'can get each user individually', (done)->
-    request (base '/users'), options(), (e,r,b)->
-      iterator = (u, cb)->
-        request (base "/users/#{u.id}"), options(u), (e,r,b)->
-          r.statusCode.should.be.equal 200
-          UserTestHelper.validate b
-          cb()
+  it 'can get each user individually', (done)->
+    iterator = (u, cb)->
+      request (base "/users/#{u.id}"), options(u), (e,r,b)->
+        r.statusCode.should.be.equal 200
+        UserTestHelper.validate b
+        cb()

-      async.eachLimit b, 100, iterator, done
+    async.eachLimit testUsers, 100, iterator, done

   it 'cant have two users with the same email', (done)->
     t = "testUser#{uuid.v1()}@testuser.com"


Add some constants

Add some constants

--- src/main.coffee
+++ src/main.coffee
@@ -1,3 +1,11 @@
+WIDTH = 800
+HEIGHT = 600
+
+CELL_COLUMNS = WIDTH / 10
+CELL_ROWS = HEIGHT / 10
+
+cells = null
+
 preload = ->
   game.load.image 'cell', 'dist/assets/cell.jpg'


update

update


Fix for https://github.com/atom/node-pathwatcher/issues/102

--- src/main.coffee
+++ src/main.coffee
@@ -15,6 +15,9 @@
     @start()

   onEvent: (event, filePath, oldFilePath) ->
+    filePath = path.normalize(filePath) if filePath
+    oldFilePath = path.normalize(oldFilePath) if oldFilePath
+
     switch event
       when 'rename'
         # Detect atomic write.


switch @map implementation to @_map_errors

--- src/main.coffee
+++ src/main.coffee
@@ -41,7 +41,7 @@
 $stringify                = require 'pull-stringify'
 $values                   = require 'pull-stream/sources/values'
 pull                      = require 'pull-stream'
-map                       = pull.map.bind pull
+# map                       = pull.map.bind pull
 pull_through              = require 'pull-through'
 pull_async_map            = require 'pull-stream/throughs/async-map'
 pull_many                 = require 'pull-many'
@@ -276,7 +276,7 @@
     when 1 then null
     else throw new Error "method arity #{arity} not implemented"
   #.........................................................................................................
-  return map method
+  return @_map_errors method

 #-----------------------------------------------------------------------------------------------------------
 @$ = @remit = ( hint, method ) ->


Remove trailing space

Remove trailing space

--- drivers/javascript/net.coffee
+++ drivers/javascript/net.coffee
@@ -66,7 +66,7 @@
         # Buffer data, execute return results if need be
         @buffer = Buffer.concat([@buffer, buf])

-        while @buffer.length >= 12
+        while @buffer.length >= 12
             token = @buffer.readUInt32LE(0) + 0x100000000 * @buffer.readUInt32LE(4)

             responseLength = @buffer.readUInt32LE(8)


fixed time zones on tests

fixed time zones on tests

--- test/integration/metricsAPITests.coffee
+++ test/integration/metricsAPITests.coffee
@@ -188,9 +188,9 @@
             done err
           else
             res.body.should.have.length 2
-            res.body[0].load.should.have.equal 1
-            res.body[0].avgResp.should.have.equal 149
-            res.body[0].timestamp.should.have.equal '2014-07-18T13:00:00+02:00'
+            res.body[0].load.should.equal 1
+            res.body[0].avgResp.should.equal 149
+            moment(res.body[0].timestamp).utc().format().should.equal '2014-07-18T11:00:00+00:00'
             done()

     describe '*getGlobalStatusMetrics()', ->
@@ -235,9 +235,9 @@
             done err
           else
             res.body.should.have.length 1
-            res.body[0].load.should.have.equal 1
-            res.body[0].avgResp.should.have.equal 149
-            res.body[0].timestamp.should.have.equal '2014-07-18T00:00:00+02:00'
+            res.body[0].load.should.equal 1
+            res.body[0].avgResp.should.equal 149
+            moment(res.body[0].timestamp).utc().format().should.equal '2014-07-17T22:00:00+00:00'
             done()

     describe '*getStatusMetrics()', ->


update author format

update author format

--- src/plex.coffee
+++ src/plex.coffee
@@ -10,7 +10,7 @@
 #   hubot plex now playing - show what is currently playing
 #
 # Author
-#   James Walker <walkah@walkah.net>
+#   walkah

 module.exports = (robot) ->
   robot.respond /plex on(\s+)?deck/i, (msg) ->


Temporary debug mode

Temporary debug mode

--- prviewer.coffee
+++ prviewer.coffee
@@ -124,6 +124,7 @@
 app.get '/', ensureAuthenticated, (req, res) ->
   github = new GitHubAPI(
     version: '3.0.0'
+    debug: true
     customHeaders:
       # Needed for the new GitHub API
       'User-Agent': 'pull-request-viewer'


Call atom.getWindowState() instead of accessing property directly

--- src/packages/collaboration/lib/session.coffee
+++ src/packages/collaboration/lib/session.coffee
@@ -91,7 +91,7 @@

   createDocument: ->
     @site.createDocument
-      windowState: atom.windowState
+      windowState: atom.getWindowState()
       collaborationState:
         guest: {description: '', candidate: '', ready: false}
         host: {description: '', candidate: ''}


Correct broker url

Correct broker url

--- config/main.staging.coffee
+++ config/main.staging.coffee
@@ -158,7 +158,7 @@
     certFile    : ""
     keyFile     : ""
     webProtocol : 'http:'
-    webHostname : "stage-broker-#{version}.in.koding.com"
+    webHostname : "stage-broker-#{version}.sj.koding.com"
     webPort     : null
     authExchange: authExchange
     authAllExchange: authAllExchange


Check that options is an Obect

Check that options is an Obect

--- timestampable.coffee
+++ timestampable.coffee
@@ -10,6 +10,7 @@
   systemId: '0'

 behaviour = (options = {}) ->
+  check options, Object

   {createdAt, createdBy, updatedAt, updatedBy, systemId} =
     _.defaults options, @options, defaults


fix for copy arrays

fix for copy arrays

--- tools/objects.coffee
+++ tools/objects.coffee
@@ -273,13 +273,22 @@
     ##
     ##
     ##
-    copy: (obj, addon)->
-        _obj = {}
-        for key, value of obj
-            _obj[key] = value
+    copy: (obj, addon)->
+
+        if objects.isArray obj
+            _obj = []
+            for value in obj
+                _obj.push value
+
+        else
+            _obj = {}
+            for key, value of obj
+                _obj[key] = value

         if addon
-            @extend _obj, addon
+            _obj = @extend _obj, addon
+
+        _obj

     ##


Use EAD server, no K&A

Use EAD server, no K&A


Still use -o- prefix for Opera in config

--- updaters/browsers.coffee
+++ updaters/browsers.coffee
@@ -17,7 +17,9 @@
       info     = data.agents[name]
       future   = normalize(info.versions[-3..-1]).map (i) -> parseFloat(i)
       versions = intervals(normalize(info.versions[0..-4]))
-      result   = prefix: "-#{info.prefix}-"
+      result   = {}
+
+      result.prefix    = if name == 'opera' then '-o-' else "-#{info.prefix}-"
       result.minor      = true   if minor.indexOf(name) != -1
       result.future     = future if future.length
       result.versions   = versions.map (i) -> i[0]


pjax: waiting to call end callback until after transitions have been started (fix for rio image width bug after pjax)

--- app/_src/pjaxnavigation.coffee
+++ app/_src/pjaxnavigation.coffee
@@ -43,7 +43,6 @@
     @$content.on('pjax:start', @onPjaxStart)
     @$content.on('pjax:popstate', @onPopState)
     @$content.on('pjax:end', @onPjaxEnd)
-    @$content.on('pjax:end', @onEndCallback)

   # slides in hero and slides out content
@@ -128,6 +127,7 @@
           # fast transition between other pages
           @showContent()
       @updateBodyPageId(options)
+      @onEndCallback() if @onEndCallback
     )


Fix crash on no localStorage provided

Fix crash on no localStorage provided

--- index.cjsx
+++ index.cjsx
@@ -142,8 +142,8 @@
   if window.getStore?
     api_mst_shipgraph = window.getStore('const.$shipgraph')
   else
-    return if !localStorage.start2Body?
     {api_mst_shipgraph} = JSON.parse localStorage.start2Body
+  return if !api_mst_shipgraph?
   {_ships, _decks, _teitokuLv} = window
   shipgraph[ship.api_filename] = ship.api_id for ship in api_mst_shipgraph
   getSubtitles()
@@ -154,6 +154,8 @@
     stickyFor: stickyFor

 handleGameResponse = (e) ->
+  if e.detail.path.includes('start2')
+    initialize()
   clearTimeout(timeoutHandle)

 handleGetResponseDetails = (e) ->


Add indexes in background

Add indexes in background

--- app/coffee/MongoManager.coffee
+++ app/coffee/MongoManager.coffee
@@ -116,12 +116,12 @@

 	ensureIndices: () ->
 		# For finding all updates that go into a diff for a doc
-		db.docHistory.ensureIndex { doc_id: 1, v: 1 }
+		db.docHistory.ensureIndex { doc_id: 1, v: 1 }, { background: true }
 		# For finding all updates that affect a project
-		db.docHistory.ensureIndex { project_id: 1, "meta.end_ts": 1 }
+		db.docHistory.ensureIndex { project_id: 1, "meta.end_ts": 1 }, { background: true }
 		# For finding updates that don't yet have a project_id and need it inserting
-		db.docHistory.ensureIndex { doc_id: 1, project_id: 1 }
+		db.docHistory.ensureIndex { doc_id: 1, project_id: 1 }, { background: true }
 		# For finding project meta-data
-		db.projectHistoryMetaData.ensureIndex { project_id: 1 }
+		db.projectHistoryMetaData.ensureIndex { project_id: 1 }, { background: true }
 		# TTL index for auto deleting week old temporary ops
-		db.docHistory.ensureIndex { expiresAt: 1 }, { expireAfterSeconds: 0 }
+		db.docHistory.ensureIndex { expiresAt: 1 }, { expireAfterSeconds: 0, background: true }


dematerialize record in any kind of created states in ssh key

--- app/controllers/ssh-key.coffee
+++ app/controllers/ssh-key.coffee
@@ -56,7 +56,7 @@
       model = @get('model')
       console.log model.get('currentState.stateName')
       if model.get('currentState.stateName') == 'root.empty' ||
-           model.get('currentState.stateName') == 'root.loaded.created.uncommitted'
+           model.get('currentState.stateName').indexOf('root.loaded.created') != -1
         @store.dematerializeRecord(model)

       @set('model', null)


add matchers tests and fix

add matchers tests and fix

--- app/core/utils/matchers.coffee
+++ app/core/utils/matchers.coffee
@@ -48,6 +48,7 @@
             val == value

     (item) ->
+      return false unless item?
       _any = false
       for key,matcher of obj
         if matcher(item[key])


Fix bug (with my understanding of CoffeeScript)

--- src/util.coffee
+++ src/util.coffee
@@ -1,5 +1,5 @@
 # Utility functions ---------------------------------------

 extend = (dest, src) ->
-  dest[name] = src[name] for name in src when src[name] and !dest[name]
+  dest[key] = value for key, value of src when !dest[key]
   dest


brightening up the random colors since we get black sometimes

--- src/util.coffee
+++ src/util.coffee
@@ -43,7 +43,7 @@
   return a.x * b.x + a.y * b.y

 randomColor = ->
-  '#'+Math.floor(Math.random()*16777215).toString(16)
+  'rgba('+ Math.floor(Math.random()*155+100) + ',' + Math.floor(Math.random()*155+100)+','+Math.floor(Math.random()*155+100)+',255)'

 module.exports = {
   length: length


Scope form data as attribute when creating request

--- app/scripts/controllers.coffee
+++ app/scripts/controllers.coffee
@@ -43,10 +43,11 @@
   .controller 'RequestCreateCtrl', ($scope, $location, Request, RequestForm, flash) ->
     $scope.formTemplate = RequestForm 'wps001', $location.search()
     # FIXME: Should not hardcode the service code here
-    $scope.form =
-      service_code: "wps001"
+    $scope.form = {}
     $scope.save = () ->
-      Request.save $scope.form, (request) ->
-        console.log "Successfully created request", request
+      form =
+        service_code: "wps001"
+        attribute: $scope.form
+      Request.save form, (request) ->
         if request._status == 'OK'
           flash.success = 'Request successfully created!'


rm log

rm log

--- src/wrap.coffee
+++ src/wrap.coffee
@@ -209,7 +209,6 @@
             {source, body} = opts
         else
             {source, body} = @readFile(file)
-        console.log "addEntry", opts.body?, typeof(source), typeof(body)

         try required = @detective.find(body)
         catch err


fix: stack object bug

fix: stack object bug

--- src/yaku.coffee
+++ src/yaku.coffee
@@ -216,9 +216,14 @@
 					sStack = p[$settlerStack]
 					p = p[$prePromise]

+			stack = if reason
+				reason.stack or reason
+			else
+				reason
+
 			console.error (
 				'Unhandled rejection Error:' +
-				reason + sStack + hStack
+				stack + sStack + hStack
 			).replace ///.+#{__filename}.+\n///g, ''

 		return
@@ -495,8 +500,7 @@

 	scheduleUnhandledRejection = genScheduler 100, (p) ->
 		if p[$hasUnhandledRejection]
-			val = p._value.stack or p._value
-			Yaku.onUnhandledRejection val, p
+			Yaku.onUnhandledRejection p._value, p
 		return

 	callHanler = (handler, value) ->


Remove duplicate methods from bad merge

Remove duplicate methods from bad merge

--- src/trix/controllers/editor_controller.coffee
+++ src/trix/controllers/editor_controller.coffee
@@ -31,19 +31,6 @@
     @toolbarController = new Trix.ToolbarController @toolbarElement
     @toolbarController.delegate = this
     @toolbarController.updateActions()
-
-  createText: ->
-    if @textElement.textContent.trim()
-      Trix.Text.fromHTML(@textElement.innerHTML)
-    else if @inputElement?.value
-      Trix.Text.fromJSON(@inputElement.value)
-    else
-      new Trix.Text
-
-  saveSerializedText: ->
-    @textareaElement.value = @textElement.innerHTML
-    Trix.DOM.trigger(@textareaElement, "input")
-    @inputElement?.value = @text.asJSON()

   # Composition controller delegate


minor bugfix

minor bugfix

--- example_project/segmentation/static/js/common/util.coffee
+++ example_project/segmentation/static/js/common/util.coffee
@@ -32,12 +32,9 @@
 # non-CORS version
 get_cors_url = (url) ->
   if url.indexOf('?') == -1
-    if url.indexOf("?origin=") == -1
-      url + '?origin=' + window.location.host
-    else
-      url
+    url + '?origin=' + window.location.host
   else
-    if url.indexOf("&origin=") == -1
+    if url.indexOf("?origin=") == -1 and url.indexOf("&origin=") == -1
       url + '&origin=' + window.location.host
     else
       url


Fix bug where opening a history item would open multiple tabs

--- lib/slickgrid/selection-models/row-selection-model.coffee
+++ lib/slickgrid/selection-models/row-selection-model.coffee
@@ -52,8 +52,7 @@
             @grid.setCellCssStyles("copy_Flash", obj2)

         if e.keyCode == 13
-            for pane in atom.workspace.getPanes()
-                atom.commands.dispatch(atom.views.getView(pane), 'application:new-file')
+            atom.commands.dispatch(atom.views.getView(atom.workspace.getPanes()[0]), 'application:new-file')
             setTimeout( () =>
                 atom.workspace.getActiveTextEditor().insertText(data[@lastCell.y]["query"].toString())
             , 50)


don't clean bower directory enables developers to check it out

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -11,7 +11,6 @@
 		bower:
 			install:
 				options:
-					cleanBowerDir: true
 					cleanTargetDir: true
 					copy: true
 					layout: (type, component) ->


Add alternative test:acceptance:docker command, using separate docker repo

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -82,6 +82,8 @@
 				"""
 			dockerTests:
 				command: 'docker run -v "$(pwd):/document-updater" --rm --name doc-updater-test sharelatex-docupdater-tests'
+			dockerTests2:
+				command: 'docker run -v "$(pwd):/app" --rm sl-acceptance-test-runner'

 		availabletasks:
 			tasks:
@@ -144,6 +146,12 @@
 		['shell:buildDockerImage', 'shell:dockerTests']
 	)

+	grunt.registerTask(
+		'test:acceptance:docker2',
+		"Run acceptance tests inside docker container",
+		['shell:dockerTests2']
+	)
+
 	grunt.registerTask 'test:acceptance', 'Run the acceptance tests (use --grep=<regex> for individual tests)', ['compile:acceptance_tests', 'mochaTest:acceptance']

 	grunt.registerTask 'run', "Compile and run the document-updater-sharelatex server", ['compile', 'bunyan', 'execute']


default grunt task: auto test on changes

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -2,6 +2,10 @@

 	grunt.initConfig
 		pkg: grunt.file.readJSON 'package.json'
+		watch:
+			test:
+				files: ['*.js', 'tests/*.coffee', '!tests/all.coffee']
+				tasks: ['test']
 		concat:
 			test:
 				files:
@@ -45,8 +49,10 @@
 	grunt.loadNpmTasks 'grunt-contrib-coffee'
 	grunt.loadNpmTasks 'grunt-contrib-concat'
 	grunt.loadNpmTasks 'grunt-contrib-clean'
+	grunt.loadNpmTasks 'grunt-contrib-watch'

 	grunt.registerTask 'test', [ 'concat:test', 'coffee:test'
 	                             'connect', 'mocha_phantomjs'
 	                             'clean:test' ]
 	grunt.registerTask 'release', ['copy', 'uglify']
+	grunt.registerTask 'default', ['watch:test']


ignore max_line_length warnings

ignore max_line_length warnings

As detailed in https://github.com/slara/generator-reveal/issues/45

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -30,7 +30,7 @@
             jshint:
                 files: ['js/*.js']
                 tasks: ['jshint']
-
+
         connect:

             livereload:
@@ -48,6 +48,8 @@
             options:
                 indentation:
                     value: 4
+                max_line_length:
+                    level: 'ignore'

             all: ['Gruntfile.coffee']

@@ -76,7 +78,7 @@
                     filter: 'isFile'
                 }]

-
+
         buildcontrol:

             options:
@@ -88,7 +90,7 @@
                 options:
                     remote: 'git@github.com:ceres-pallas/machine-learning-presentation.git'
                     branch: 'gh-pages'
-
+

     # Load all grunt tasks.
@@ -130,13 +132,13 @@
             'copy'
         ]

-
+
     grunt.registerTask 'deploy',
         'Deploy to Github Pages', [
             'dist'
             'buildcontrol'
         ]
-
+

     # Define default task.
     grunt.registerTask 'default', [


Don't look for less files under src/

Don't look for less files under src/

This is no longer needed now that packages have been extracted from
this folder.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -36,7 +36,6 @@
     glob_to_multiple:
       expand: true
       src: [
-        'src/**/*.less'
         'static/**/*.less'
       ]
       dest: appDir


enable deploy task

enable deploy task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,13 +1,17 @@
 module.exports = (grunt) ->
   grunt.initConfig

-    options:
-      build_directory: 'build'
+    directories:
+      build: '<%= directories.dev %>'
+      dev: 'build'
+      release: 'release'
+      ':release':
+        build: '<%= directories.release %>'

     browserify:
       app:
         files: [
-          '<%= options.build_directory %>/js/app.js': [
+          '<%= directories.build %>/js/app.js': [
             'app/**/*.coffee'
             'lib/**/*.coffee', '!lib/books/**/*.coffee', '!lib/movies/**/*.coffee'
           ]
@@ -21,8 +25,9 @@
           ]

     clean:
-      target: '<%= options.build_directory %>'
-      release: 'release/*'
+      dev: '<%= directories.dev %>'
+      release: '<%= directories.release %>/*'
+      target: '<%= directories.build %>/*'

     coffeelint:
       app: ['lib/*.coffee']
@@ -33,36 +38,45 @@
     connect:
       server:
         options:
-          base: '<%= options.build_directory %>'
+          base: '<%= directories.build %>'

     copy:
       app:
         expand: true
         cwd: 'app'
-        dest: '<%= options.build_directory %>'
+        dest: '<%= directories.build %>'
         src: ['**/*', '!**/*.coffee', '!**/*.{coffee,jade,scss}']
         filter: 'isFile'
+
+    githubPages:
+      target:
+        src: '<%= directories.release %>'

     jade:
       app:
         expand: true
         cwd: 'app'
         src: '**/*.jade'
-        dest: '<%= options.build_directory %>'
+        dest: '<%= directories.build %>'
         ext: '.html'
       options:
         pretty: true
+        ':release':
+          pretty: false

     sass:
       app:
         expand: true
         cwd: 'app'
-        dest: '<%= options.build_directory %>'
+        dest: '<%= directories.build %>'
         src: ['css/**.scss']
         ext: '.css'
         filter: 'isFile'
       options:
         sourcemap: true
+        ':release':
+          sourcemap: false
+          style: 'compressed'

     shell:
       makeBuildDir:
@@ -101,7 +115,22 @@

   require('load-grunt-tasks')(grunt)

-  grunt.registerTask 'build', ['clean', 'browserify', 'copy', 'jade', 'sass']
-  # grunt.registerTask 'build:release', ['clean:release', 'browserify:release', 'copy:release', 'jade:release']
-  # grunt.registerTask 'deploy', ['build:release', 'githubPages:target']
+  grunt.registerTask 'context', (contextName) ->
+    contextKey = ":#{contextName}"
+    installContexts = (obj) ->
+      recursiveMerge obj, obj[contextKey] if contextKey of obj
+      for k, v of obj
+        installContexts v if typeof v == 'object' and not k.match(/^:/)
+    recursiveMerge = (target, source) ->
+      for k, v of source
+        if k of target and typeof v == 'object'
+          recursiveMerge target[k], v
+        else
+          target[k] = v
+    installContexts grunt.config.data
+    return
+
+  grunt.registerTask 'build', ['clean:target', 'browserify', 'copy', 'jade', 'sass']
+  grunt.registerTask 'build:release', ['context:release', 'build']
+  grunt.registerTask 'deploy', ['build:release', 'githubPages:target']
   grunt.registerTask 'default', ['build', 'connect', 'watch']


feat(grunt): remove banner support for minified HTMLs

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -622,7 +622,6 @@
     "uncss_inline"
     "cacheBust"
     "concurrent:dist"
-    "usebanner"
     "cleanempty"
   ]


fix(grunt): config not corectly checked before upgrading

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -568,12 +568,18 @@

   grunt.registerTask "amsf-func-preupdate", "Update ASMF (preprocess)", ->
     # Check if config exists
-    if !grunt.file.exists('_amsf.yml')
-      grunt.task.run [
-        "copy:amsf__config__to_app"
-      ]
+    if !grunt.file.exists("_amsf.yml")
+      if grunt.file.exists("_amsf/_config.yml")
+        grunt.file.copy("_amsf/_config.yml", "_amsf.yml")
+      else
+        grunt.task.run [
+          "copy:amsf__config__to_app"
+        ]

   grunt.registerTask "amsf-func-postupdate", "Update ASMF (postprocess)", ->
+    # Remove deprecated directory
+    if grunt.file.exists("_amsf")
+      grunt.file.delete("_amsf")

   # Defined tasks
   grunt.registerTask "theme-upgrade", "Upgrade specific theme from AMSF cache to app", [


v1.0.0-rc1

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -36,8 +36,8 @@
     exec = require("child_process").exec
     done = this.async()
     releaseVersion = grunt.template.process("<%= pkg.version %>")
-    console.log "git ci -am \"v#{releaseVersion}\" && git tag v#{releaseVersion}"
-    child = exec "git ci -am \"v#{releaseVersion}\" && git tag v#{releaseVersion}", (error, stdout, stderr) ->
+
+    child = exec "git ci -am \"v#{releaseVersion}\" ; git tag v#{releaseVersion}", (error, stdout, stderr) ->
       console.log("Error running git tag: " + error) if error?
       done(!error?)


Fix failing test script from bad vendor path.

"Can't find variable: Phaser" because site/lib only gets populated on
`grunt publish`.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -118,7 +118,7 @@
             requireConfig:
               paths:
                 test: '../tests/js'
-          vendor: [ 'site/lib/{dat.gui,phaser,underscore}.js' ]
+          vendor: [ 'lib/{dat.gui,phaser,underscore}.js' ]

     processhtml:
       site:


Minor improvements on Gruntfile.

Minor improvements on Gruntfile.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -62,7 +62,7 @@
         },

         coffee: {
-            mainDevelopment: {
+            dev: {
                 options: {join: false},
                 files: {
                     "app/dist/app.js": [
@@ -72,7 +72,7 @@
                 }
             },

-            mainProduction: {
+            pro: {
                 options: {join: false},
                 files: {"app/dist/_app.js": ["app/coffee/**/*.coffee"]}
             }
@@ -147,22 +147,22 @@
     grunt.loadNpmTasks('grunt-contrib-htmlmin')
     grunt.loadNpmTasks('grunt-contrib-coffee')

-    grunt.registerTask('production', [
+    grunt.registerTask('pro', [
         'less',
-        'coffee:mainProduction',
+        'coffee:pro',
         'uglify',
         'htmlmin',
     ])

-    grunt.registerTask('development', [
+    grunt.registerTask('dev', [
         'less',
-        'coffee:mainDevelopment',
+        'coffee:dev',
         'concat:libs',
         'htmlmin',
     ])

     grunt.registerTask('default', [
-        'development',
+        'dev',
         'connect:devserver',
         'watch'
     ])


Add back lint as part of CI

Add back lint as part of CI

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -192,7 +192,7 @@

   grunt.registerTask('compile', ['coffee', 'less', 'cson'])
   grunt.registerTask('lint', ['coffeelint', 'csslint', 'lesslint'])
-  grunt.registerTask('ci', ['partial-clean', 'update-atom-shell', 'build', 'test'])
+  grunt.registerTask('ci', ['lint', 'partial-clean', 'update-atom-shell', 'build', 'test'])
   grunt.registerTask('deploy', ['update-atom-shell', 'build', 'codesign'])
   grunt.registerTask('default', ['update-atom-shell', 'build', 'set-development-version', 'install'])


No longer compiles to js

No longer compiles to js

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -3,10 +3,6 @@
 	coffeelintConfig = grunt.file.readJSON('coffeelint-config.json')

 	grunt.initConfig
-		coffee:
-			main:
-				files:
-					'dist/connect-instagram-proxy.js': 'src/connect-instagram-proxy.coffee'

 		coffeelint:
 			main:
@@ -17,7 +13,7 @@
 		watch:
 			main:
 				files: ['test/**', 'src/**', 'libs/**', 'utils/**']
-				tasks: ['coffeelint', 'coffee', 'mochaTest']
+				tasks: ['coffeelint', 'mochaTest']

 		mochaTest:
 			main:
@@ -30,7 +26,7 @@
 	tasks =
 		build: ['test']
 		default: ['testWatch']
-		test: ['coffeelint', 'coffee', 'mochaTest']
+		test: ['coffeelint', 'mochaTest']
 		testWatch: ['test', 'watch']

 	grunt.registerTask taskName, taskArray for taskName, taskArray of tasks


Revert "Bump grunt-qunit timeout to 20s from 5s to try fix Travis" [ci skip]

This reverts commit 34eba4fee5c259781a4af6401ff9511f04a6e9c6.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -115,8 +115,6 @@
         dest: 'gh-pages/index.html'
     qunit:
       all:
-        options:
-          timeout: 20000
         expand: yes
         src: 'tests/*.unit.html'
     sass:


removed vows, added mocha dependencies

removed vows, added mocha dependencies

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -17,18 +17,6 @@
         reporters: ['progress']
       single:
         singleRun: true
-
-  vows:
-    all:
-      src: "<%= allTests %>"
-      options:
-        reporter: "spec"
-    allXunit:
-      src: "<%= allTests %>"
-      dest: "testResults.xml"
-      options:
-        reporter: "Xunit"
-  allTests: "tests/*"

     open:
       client:
@@ -119,6 +107,7 @@
   grunt.loadNpmTasks 'grunt-open'
   grunt.loadNpmTasks 'grunt-nodemon'
   grunt.loadNpmTasks 'grunt-concurrent'
+  grunt.loadNpmTasks 'grunt-simple-mocha'
   # grunt.loadNpmTasks 'grunt-karma'
   # grunt.loadNpmTasks 'grunt-vows-runner'


remove gruntfile

remove gruntfile

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,18 +0,0 @@
-
-module.exports = (grunt) ->
-
-  grunt.initConfig(
-    coffee: {
-      compile: {
-        expand: true
-        cwd: 'src/'
-        src: ['**/*.iced']
-        dest: 'lib/'
-        ext: '.js'
-      }
-    }
-  )
-
-  grunt.loadNpmTasks('grunt-iced-coffee')
-
-  grunt.registerTask('default', ['coffee'])


Removing mochacov:coverage on travis-ci

Removing mochacov:coverage on travis-ci

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -41,4 +41,4 @@
   grunt.registerTask('test', 'mochacov:test')

   grunt.registerTask('default', 'watch')
-  grunt.registerTask('travis', ['check', 'mochacov:coverage'])
+  grunt.registerTask('travis', 'check')


[off] auto open server url in development

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -318,7 +318,7 @@
   grunt.registerTask "server", (target) ->
     return grunt.task.run([
       "build"
-      "open"
+      # "open"
       "connect:dist:keepalive"
     ])  if target is "dist"
     grunt.task.run [
@@ -331,7 +331,7 @@
       "compass:server"
       "livereload-start"
       "connect:livereload"
-      "open"
+      # "open"
       "watch"
     ]


Use src-dest format

Use src-dest format

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -61,16 +61,19 @@
           dumpLineNumbers: "all"

         files:
-          "<%= core.app %>/assets/css/app.css": ["<%= recess.test.files.src %>"]
-
-      dist:
-        files:
-          "<%= core.app %>/assets/css/app.css": ["<%= recess.test.files.src %>"]
+          src: ["<%= recess.test.files.src %>"]
+          dest: "<%= core.app %>/assets/css/app.css"
+
+      dist:
+        files:
+          src: ["<%= recess.test.files.src %>"]
+          dest: "<%= less.server.files.dest %>"

     autoprefixer:
       dist:
         files:
-          "<%= core.app %>/assets/css/app.css": ["<%= core.app %>/assets/css/app.css"]
+          src: ["<%= less.server.files.dest %>"]
+          dest: "<%= less.server.files.dest %>"

     htmlmin:
       dist:


added build and release tasks

added build and release tasks

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -37,15 +37,29 @@
         files: ['test/**/*Spec.js']
         tasks: ['jasmine']

+    exec:
+      publish: 'git push origin master && npm publish'
+      commitRelease: 'git commit bower.json easy-date.min.js package.json -m "Release v<%= pkg.version %>"'
+
+    bump:
+      options:
+        files: ['package.json', 'bower.json']
+        updateConfigs: ['pkg']
+        pushTo: 'remote'

   grunt.loadNpmTasks 'grunt-contrib-coffee'
   grunt.loadNpmTasks 'grunt-contrib-uglify'
   grunt.loadNpmTasks 'grunt-contrib-watch'
   grunt.loadNpmTasks 'grunt-karma'
   grunt.loadNpmTasks 'grunt-contrib-jasmine'
+  grunt.loadNpmTasks 'grunt-exec'
+  grunt.loadNpmTasks 'grunt-bump'

   grunt.registerTask 'test', [ 'jasmine' ]
   grunt.registerTask 'dev', [ 'coffee', 'jasmine', 'watch' ]
   grunt.registerTask 'default', [ 'test' ]

+  grunt.registerTask 'build', [ 'test', 'bump-only', 'uglify']
+  grunt.registerTask 'release', ['exec:commitRelease', 'exec:publish']
+
   return


Not embedding html into directive on watch.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -158,7 +158,7 @@
     watch:
       js:
         files: ["src/**/*.coffee", "src/*.coffee"]
-        tasks: ["coffee", "concat:appJs", "clean", "copy:public", "embed:html"]
+        tasks: ["coffee", "concat:appJs", "clean", "copy:public"]
         options: interrupt: true
       css:
         files: ["src/css/*.styl"]


Unset Unix domain socket for tests.

Unset Unix domain socket for tests.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -50,7 +50,7 @@
   grunt.registerTask 'test', 'Run unit tests.', ->
     done = @async()

-    cmd = "IMPROMPTU_PORT=2934 impromptu server"
+    cmd = "IMPROMPTU_PORT=2934 IMPROMPTU_UNIX_DOMAIN_SOCKET='' impromptu server"

     exec "#{cmd} shutdown", (err, stdout, stderr) ->
       server = exec "#{cmd} foreground"


Fixing tests..

Fixing tests..

--- test/strawpoll_test.coffee
+++ test/strawpoll_test.coffee
@@ -13,4 +13,4 @@
     require('../src/strawpoll')(@robot)

   it 'registers a respond listener', ->
-    expect(@robot.respond).to.have.been.calledWith(/strawpoll/).withArgs(1, 2, 3)
+    expect(@robot.respond).to.have.been.calledWith(/strawpoll/, 1, 2, 3)


[fix] This closes #157 and fixes the init spec (should set AUTO_WATCH).

--- test/unit/init.spec.coffee
+++ test/unit/init.spec.coffee
@@ -222,10 +222,9 @@
       replacements = m.getReplacementsFromAnswers answers {browsers: ['Chrome', 'Firefox']}
       expect(replacements.BROWSERS).toBe "'Chrome', 'Firefox'"

-
     it 'should set AUTO_WATCH', ->
-      replacements = m.getReplacementsFromAnswers answers {autoWatch: 'yes'}
+      replacements = m.getReplacementsFromAnswers answers {autoWatch: true}
       expect(replacements.AUTO_WATCH).toBe 'true'

-      replacements = m.getReplacementsFromAnswers answers {autoWatch: 'no'}
+      replacements = m.getReplacementsFromAnswers answers {autoWatch: false}
       expect(replacements.AUTO_WATCH).toBe 'false'


proof of the spritesheet working

proof of the spritesheet working

--- client/client.coffee
+++ client/client.coffee
@@ -55,7 +55,7 @@
         clip.position.x = 32
         clip.position.y = 64

-        grass1 = PIXI.Sprite.fromFrame "grass_01"
+        grass1 = PIXI.Sprite.fromFrame "U14"
         grass1.position.x = 200
         grass1.position.y = 64


thingy: fix bug where Thingyverse#ready didn't change ready flag.

--- client/thingy.coffee
+++ client/thingy.coffee
@@ -834,6 +834,8 @@
       delete @_.partials_subkeys[ id ]
       delete @_.partials_to_create[ id ]

+    @_.ready = true
+
     this

   # See {Heron.Dictionary#batch}.


Referrer System : Fixed issues with MR.

Referrer System : Fixed issues with MR.

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsPersReferralSystem.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsPersReferralSystem.coffee
@@ -42,75 +42,72 @@

   showRedeemReferralPointModal: ()->
-    KD.remote.api.JReferral.fetchRedeemableReferrals { type: "disk" }, (err, referals)=>
+    vmController = KD.getSingleton("vmController")
+    vmController.fetchVMs yes, (err, vms)=>
       return KD.showError err if err
-      return @notify_ "You dont have any referrals" if not referals or referals.length < 1
+      return @notify_ "You don't have any VMs. Please create one VM" if not vms or vms.length < 1

-      @modal = modal = new KDModalViewWithForms
-        title                   : "Redeem Your Referral Points"
-        content                 : ""
-        overlay                 : yes
-        width                   : 500
-        height                  : "auto"
-        tabs                    :
-          forms                 :
-            Redeem               :
-              callback          : =>
-                @modal.modalTabs.forms.Redeem.buttons.redeemButton.showLoader()
-                @emit "RedeemReferralPointSubmitted", @
-              buttons           :
-                redeemButton    :
-                  title         : "Redeem"
-                  style         : "modal-clean-gray"
-                  type          : "submit"
-                  loader        :
-                    color       : "#444444"
-                    diameter    : 12
-                  callback      : -> @hideLoader()
-                cancel          :
-                  title         : "Cancel"
-                  style         : "modal-cancel"
-                  callback      : (event)-> modal.destroy()
-              fields            :
-                vmToResize    :
-                  label         : "Select a WM to resize"
-                  itemClass     : KDSelectBox
-                  type          : "select"
-                  name          : "vmToResize"
-                  validate      :
-                    rules       :
-                      required  : yes
-                    messages    :
-                      required  : "You must select a VM!"
-                  selectOptions : (cb)->
-                    vmController = KD.getSingleton("vmController")
-                    vmController.fetchVMs yes, (err, vms)=>
-                      return KD.showError err if err
+      KD.remote.api.JReferral.fetchRedeemableReferrals { type: "disk" }, (err, referals)=>
+        return KD.showError err if err
+        return @notify_ "You dont have any referrals" if not referals or referals.length < 1
+
+        @modal = modal = new KDModalViewWithForms
+          title                   : "Redeem Your Referral Points"
+          content                 : ""
+          overlay                 : yes
+          width                   : 500
+          height                  : "auto"
+          tabs                    :
+            forms                 :
+              Redeem               :
+                callback          : =>
+                  @modal.modalTabs.forms.Redeem.buttons.redeemButton.showLoader()
+                  @emit "RedeemReferralPointSubmitted", @
+                buttons           :
+                  redeemButton    :
+                    title         : "Redeem"
+                    style         : "modal-clean-gray"
+                    type          : "submit"
+                    loader        :
+                      color       : "#444444"
+                      diameter    : 12
+                    callback      : -> @hideLoader()
+                  cancel          :
+                    title         : "Cancel"
+                    style         : "modal-cancel"
+                    callback      : (event)-> modal.destroy()
+                fields            :
+                  vmToResize    :
+                    label         : "Select a WM to resize"
+                    itemClass     : KDSelectBox
+                    type          : "select"
+                    name          : "vmToResize"
+                    validate      :
+                      rules       :
+                        required  : yes
+                      messages    :
+                        required  : "You must select a VM!"
+                    selectOptions : (cb)->
                       options = for vm in vms
                         ( title : vm, value : vm)
                       cb options
-
-                sizes           :
-                  label         : "Select Size"
-                  itemClass     : KDSelectBox
-                  type          : "select"
-                  name          : "size"
-                  validate      :
-                    rules       :
-                      required  : yes
-                    messages    :
-                      required  : "You must select a size!"
-                  selectOptions : (cb)=>
-                    options = []
-                    previousTotal = 0
-                    referals.forEach (referal, i)->
-
-                      console.log "referal.amount"
-                      console.log referal.amount
-
-                      previousTotal += referal.amount
-                      options.push ( title : "#{previousTotal} #{referal.unit}" , value : previousTotal)
-                    cb options
+                  sizes           :
+                    label         : "Select Size"
+                    itemClass     : KDSelectBox
+                    type          : "select"
+                    name          : "size"
+                    validate      :
+                      rules       :
+                        required  : yes
+                      messages    :
+                        required  : "You must select a size!"
+                    selectOptions : (cb)=>
+                      options = []
+                      previousTotal = 0
+                      referals.forEach (referal, i)->
+                        previousTotal += referal.amount
+                        options.push ( title : "#{previousTotal} #{referal.unit}" , value : previousTotal)
+                      cb options

   loadView: ->


Fix issue #3498

Fix issue #3498

--- coffee-script.coffee
+++ coffee-script.coffee
@@ -124,13 +124,17 @@
 # The CoffeeScript REPL uses this to run the input.
 exports.eval = (code, options = {}) ->
   return unless code = code.trim()
-  Script = vm.Script
-  if Script
+  createContext = vm.Script.createContext ? vm.createContext
+
+  isContext = vm.isContext ? (ctx) ->
+    options.sandbox instanceof createContext().constructor
+
+  if createContext
     if options.sandbox?
-      if options.sandbox instanceof Script.createContext().constructor
+      if isContext options.sandbox
         sandbox = options.sandbox
       else
-        sandbox = Script.createContext()
+        sandbox = createContext()
         sandbox[k] = v for own k, v of options.sandbox
       sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox
     else
@@ -303,4 +307,3 @@
     "  at #{formatSourcePosition frame, getSourceMapping}"

   "#{err.toString()}\n#{frames.join '\n'}\n"
-


better structure on info

better structure on info

--- coffee_server.coffee
+++ coffee_server.coffee
@@ -62,9 +62,7 @@
   api_name: API.name,
   api_version: API.version,
   api_git_repo_url: API.github,
-  info: {
-    geodata: geodata_info
-  }
+  geodata: geodata_info
 })


subtract canvas offset and rename pointer offset methods, FF and chrome behaving well

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -107,7 +107,7 @@
     @element = document.createElement('div')
     @element.className = "mark"

-    @element.style.left = @elementXOffset(e) + "px"
+    @element.style.left = @pointerXInElement(e) + "px"
     @element.style.position =  'absolute'
     @element.style.top = e.target.offsetTop + "px"
     @element.style.height = @canvas.height - 13 + 'px' # subtract border height
@@ -122,7 +122,7 @@
     @element.addEventListener 'mouseover', (e) => @hovering = true
     @element.addEventListener 'mouseout', (e) => @hovering = false
     @element.addEventListener 'mousedown', (e) => @onMouseDown(e)
-    @element.addEventListener 'click', (e) => @canvasGraph.marks.remove(@) if @elementYOffset(e) < 15
+    @element.addEventListener 'click', (e) => @canvasGraph.marks.remove(@) if @pointerYInElement(e) < 15
     window.addEventListener 'mousemove', (e) => @onMouseMove(e)
     window.addEventListener 'mouseup', (e) => @onMouseUp(e)

@@ -152,14 +152,17 @@
     @dataXMax = @canvasGraph.toDataXCoord(@canvasXMax)

   updateCursor: (e) ->
-    if @elementYOffset(e) < 15
+    console.log "E", e.layerX
+    console.log @pointerXInElement e
+    if @pointerYInElement(e) < 15
       @element.style.cursor = "pointer"
-    else if ((Math.abs @elementXOffset(e) - (@canvasXMax-@canvasXMin)) < 10) || @elementXOffset(e) < 10
+    else if ((Math.abs @pointerXInElement(e) - (@canvasXMax-@canvasXMin)) < 10) || @pointerXInElement(e) < 10
       @element.style.cursor = "ew-resize"
     else
       @element.style.cursor = "move"

   onMouseMove: (e) ->
+    console.log "ONMOUSEMOVE"
     e.preventDefault()
     @draw(e) if @dragging
     @move(e) if @moving
@@ -168,13 +171,13 @@
   onMouseDown: (e) ->
     e.preventDefault()
     @element.parentNode.appendChild(@element) #move to end of container for z index
-    if (Math.abs @elementXOffset(e) - (@canvasXMax-@canvasXMin)) < 10
+    if (Math.abs @pointerXInElement(e) - (@canvasXMax-@canvasXMin)) < 10
       @startingPoint = @canvasXMin
       @dragging = true
-    else if @elementXOffset(e) < 10
+    else if @pointerXInElement(e) < 10
       @startingPoint = @canvasXMax
       @dragging = true
-    else if @elementYOffset(e) > 15
+    else if @pointerYInElement(e) > 15
       @moving = true
       @pointerOffset = ((e.pageX) - @canvasXMin)

@@ -189,9 +192,9 @@

   toCanvasXPoint: (e) -> e.pageX-@canvas.getBoundingClientRect().left - window.scrollX

-  elementXOffset: (e) -> e.offsetX || e.clientX - e.target.offsetLeft + window.pageXOffset
-
-  elementYOffset: (e) -> e.offsetY || e.clientY - e.target.offsetTop + window.pageYOffset
+  pointerXInElement: (e) -> e.offsetX || e.clientX - e.target.offsetLeft + window.pageXOffset - @canvas.getBoundingClientRect().left
+
+  pointerYInElement: (e) -> e.offsetY || e.clientY - e.target.offsetTop + window.pageYOffset - @canvas.getBoundingClientRect().top

 module?.exports = CanvasGraph: CanvasGraph, Marks: Marks, Mark: Mark


code documentation

code documentation

--- 360.coffee
+++ 360.coffee
@@ -1,15 +1,15 @@
 ### Util (open) {{{1 ###
-# General Util {{{2
+# General Utility functions {{{2
 floatPart = (n) -> n - Math.floor(n)
-extend = (target, sources...) ->
+nextTick = (fn) -> setTimeout fn, 0
+identityFn = (e) -> e
+nop = -> undefined
+runOnce = (fn) -> (args...) -> if fn then fn args...; fn = undefined else undefined
+extend = (target, sources...) -> #{{{3
   for source in sources
     for key, val of source
       target[key] = val
   target
-nextTick = (fn) -> setTimeout fn, 0
-identityFn = (e) -> e
-nop = -> undefined
-runOnce = (fn) -> (args...) -> if fn then fn args...; fn = undefined else undefined
 asyncEach = (arr, fn, done) -> #{{{3
   done = runOnce done
   remaining = arr.length
@@ -20,23 +20,24 @@
   undefined

 # Browser abstractions, only added here, because of requirement of no dependencies, - would otherwise use jquery or similar {{{2
+onComplete = (fn) -> do f = -> if document.readyState == "interactive" or document.readyState == "complete" then fn() else setTimeout f, 10 #{{{3
 setStyle = (elem, obj) -> #{{{3
   for key, val of obj
     try
-      elem.style[key] = val
+      elem.style[key] = val
     catch e
       e
   elem
-onComplete = (fn) -> do f = -> if document.readyState == "interactive" or document.readyState == "complete" then fn() else setTimeout f, 10 #{{{3
 elemAddEventListener = (elem, type, fn) -> #{{{3
   if elem.addEventListener
     elem.addEventListener type, fn, false
   else
     elem.attachEvent "on"+type, fn

-# Browser shim {{{2
+# Browser shims {{{2
 Date.now ?= -> (+ new Date())
-body = document.getElementsByTagName("body")[0]
+body = document.getElementsByTagName("body")[0] # TODO: run this after onload
+
 # Browser utils {{{2
 cacheImgs = (urls, callback) -> #{{{3
   loadImg = (url, done) ->
@@ -44,6 +45,7 @@
     img.src = url
     img.onload = -> done()
   asyncEach urls, loadImg, callback
+
 maximize = (elem) -> #{{{3
   oldbody = document.createElement "div"
   oldbody.style.display = "none"
@@ -68,7 +70,6 @@
 touchHandler = undefined
 setTouch = undefined
 do ->
-  # TODO: mostly dummy so far...
   touch = undefined
   setTouch = (t) -> touch = t

@@ -143,8 +144,6 @@
     handler

 # 360º specific (proprietary) {{{1
-# Controller {{{2
-
 do ->
   zoomSize = 200
   eventHandler = undefined
@@ -187,7 +186,7 @@
     elem.appendChild img
     nextTick -> get360Config()

-    # get config+imagelist from server {{{3
+    # Get config+imagelist from server (DUMMY IMPLEMENTATION) {{{3
     get360Config = ->
       nextTick -> # TODO: replace with  async ajax from server
         serverConfig =
@@ -224,7 +223,8 @@
           done()
       showNext()

-    updateImage = -> #{{{3
+    # Update the current viewed image {{{3
+    updateImage = ->
       img.src = cfg.imageURLs[floatPart(currentAngle/Math.PI/2) * cfg.imageURLs.length | 0]

     # init controls {{{3
@@ -240,6 +240,7 @@
       eventHandler.click = (t) -> if t.isMouse
         t.zoom360 = true
         nextTick -> setTouch t
+
     # Zoom handling {{{3
     doZoom = (t) ->
       zoomLens = document.getElementById "zoomLens360"


Issue #801 -- Empty catch statements immediately preceding outdents.

--- rewriter.coffee
+++ rewriter.coffee
@@ -200,7 +200,7 @@
       if tag is 'ELSE' and @tag(i - 1) isnt 'OUTDENT'
         tokens.splice i, 0, @indentation(token)...
         return 2
-      if tag is 'CATCH' and @tag(i + 2) in ['TERMINATOR', 'FINALLY']
+      if tag is 'CATCH' and @tag(i + 2) in ['OUTDENT', 'TERMINATOR', 'FINALLY']
         tokens.splice i + 2, 0, @indentation(token)...
         return 4
       if tag in SINGLE_LINERS and @tag(i + 1) isnt 'INDENT' and


Added login page link back.

Added login page link back.

--- picoCTF-web/web/coffee/front-page.coffee
+++ picoCTF-web/web/coffee/front-page.coffee
@@ -39,7 +39,9 @@
           <Input type="password" valueLink={@props.password} addonBefore={lockGlyph} label="Password"/>
           <Row>
             <Col md={6}>
-              {if @props.status == "Register" then
 else <ButtonInput type="submit">Login</ButtonInput>}
+              {if @props.status == "Register" then \
+                Go back to Login.
+              else <ButtonInput type="submit">Login</ButtonInput>}
             </Col>
             <Col md={6}>
               Need to reset your password?
@@ -116,6 +118,9 @@
     @setState update @state,
         page: $set: page

+  componentDidMount: ->
+    $("input").prop 'required', true
+
   render: ->
     links =
     username: @linkState "username"


Add popup option when adding a waterpoint to map

--- app/scripts/services.coffee
+++ app/scripts/services.coffee
@@ -211,24 +211,22 @@
       # add a layer selector
       layerSelector = L.control.layers(baseMaps, overlayMaps).addTo(map)

-      mapData =
-        map: map
-        markerLayer: markerLayer
-
       @clearMarkers = () ->
-        mapData.markerLayer.clearLayers()
-
-      @addWaterpoint = (wp) ->
+        markerLayer.clearLayers()
+
+      @addWaterpoint = (wp, popup) ->
         [lng,lat] = wp.location.coordinates
         m = L.marker L.latLng(lat,lng),
           stroke: false
           opacity: 0.8
           fillColor: statusColor(wp.status_group)
-
-        mapData.markerLayer.addLayer(m)
+        if popup
+          m.bindPopup popup
+
+        markerLayer.addLayer(m)

       @zoomToMarkers = () ->
-        mapData.map.fitBounds(mapData.markerLayer.getBounds())
+        map.fitBounds(markerLayer.getBounds())

       return this


revert pbd in model

revert pbd in model

--- app/scripts/services.coffee
+++ app/scripts/services.coffee
@@ -234,6 +234,20 @@
         SR_type: 'LVM'
         usage: 10 * giga # in bytes
       }
+
+      # PBDs
+      'd399326b-1dc5-49f1-94c1-84f154a4ce9c': {
+        type: 'PBD'
+        attached: true
+        host: 'b52ebcdb-72e0-45f6-8ec8-2c84ca24d0ec'
+        SR: 'ba305307-db94-4f1b-b9fb-dbbbd269cd3d'
+      }
+      '5fe2a577-3591-49e4-82cf-083698625a48': {
+        type: 'PBD'
+        attached: false
+        host: 'ae1a5bac-ac38-4577-bd75-251628549558'
+        SR: '81e31c8f-9d84-4fa5-b5ff-174e36cc366f'
+      }
     }

     # Injects the UUID in the objects.
@@ -246,6 +260,10 @@
       (byTypes[type] ?= []).push object

     # Creates reflexive links & compute additional statistics.
+    for PBD in byTypes.PBD ? []
+      (objects[PBD.host].$PBDs ?= []).push PBD.$UUID
+      (objects[PBD.SR].$PBDs ?= []).push PBD.$UUID
+
     for VM in byTypes.VM ? []
       if VM.CPUs?.length
         CPU_usage = 0
@@ -266,23 +284,13 @@
       host.$running_VMs = running_VMs
       host.$vCPUs = vCPUs

-      local_SRs = []
-      shared_SRs = []
       for SR_UUID in host.SRs ? []
         SR = objects[SR_UUID]
-
         SR.$host = host.$UUID
-        if SR.shared
-          shared_SRs.push SR_UUID
-        else
-          local_SRs.push SR_UUID
-      host.$local_SRs = local_SRs
-      host.$shared_SRs = shared_SRs

     for pool in byTypes.pool ? []
       running_hosts = []
       running_VMs = []
-      SRs = []
       VMs = []
       for host_UUID in pool.hosts ? []
         host = objects[host_UUID]
@@ -290,11 +298,9 @@
         host.$pool = pool.$UUID
         running_hosts.push host if 'Running' == host.power_state
         running_VMs.push host.$running_VMs...
-        SRs.push host.$shared_SRs...
         VMs.push host.VMs...
       pool.$running_hosts = running_hosts
       pool.$running_VMs = running_VMs
-      pool.$SRs = SRs
       pool.$VMs = VMs

     {


generate random genes for wild pokemon

generate random genes for wild pokemon

--- app/services/pokemon.coffee
+++ app/services/pokemon.coffee
@@ -1,15 +1,38 @@
 `import breeds from '../helpers/breeds'`
+
+stats = [
+    'hp'
+    'attack'
+    'defense'
+    'spAttack'
+    'spDefense'
+    'speed'
+]

 startingStats = ->
     hp: 10
     attack: 5
     defense: 5
-    special_attack: 5
-    special_defense: 5
+    spAttack: 5
+    spDefense: 5
     speed: 5

+randomGenes = (strength = 'weak') ->
+    genes = { }
+    for stat in stats
+        genes[stat] = randomGene strength

-advanceToLevel = (startingStats, breed) ->
+    genes
+
+randomGene = (strength) ->
+    list = switch strength
+        when 'weak' then [0, 1, 2]
+        when 'medium' then [0, 1, 2, 3]
+        when 'strong' then [0, 1, 2, 3, 4]
+
+    _.sample list
+
+advanceToLevel = (stats, breed) ->
     false

 PokemonService = Ember.Object.extend
@@ -18,7 +41,18 @@
             throw error: "Unknown Breed: #{breed}"

         breed = breeds[breed]
-        startingStats = startingStatus()
-        advanceToLevel startingStats, breed
+        stats = startingStatus()
+        genes = randomGenes()
+
+
+        levelUp() for [1..level]

 `export default PokemonService`
+
+###
+        0   1   2   3   4   5   6   7   8   9
+        80  85  90  95  100 105 110 115 120 125
+weak   [---------]
+medium [-------------]
+strong [-----------------]
+###


Enabled sliding

Enabled sliding

--- _slidez/slidez.coffee
+++ _slidez/slidez.coffee
@@ -21,17 +21,17 @@
         "margin-top": "#{-($(@element).height() + 4) / 2.0}px"
       })

-    @element.html(@element.html() + "<p>#{@x} / #{@y}</p>")
-    @hide(true)
-
-  show: (immediate) => @css({ opacity: 1 }, immediate)
-  hide: (immediate) => @css({ opacity: 0 }, immediate)
+  moveIn: (immediate) => @css({ opacity: 1, x: 0, y: 0 }, immediate)
+  moveOutLeft: (immediate) => @css({ opacity: 0, x: -1000, y: 0 }, immediate)
+  moveOutRight: (immediate) => @css({ opacity: 0, x: 1000, y: 0 }, immediate)
+  moveOutUp: (immediate) => @css({ opacity: 0, x: 0, y: -1000 }, immediate)
+  moveOutDown: (immediate) => @css({ opacity: 0, x: 0, y: 1000 }, immediate)

   css: (style, immediate) =>
     if immediate == true
       @element.css(style)
     else
-      @element.transition(style, 500, "ease")
+      @element.transition(style, 1000, "ease")
     this

 class Chapter
@@ -67,7 +67,14 @@
       .filter((c) => c.slides.length > 0)
       .value()
     @current = _.first(@chapters)
-    @currentChapter().currentSlide().show(true)
+
+    _.each(@chapters, (c) ->
+      _.each(c.slides, (s) ->
+        s.moveOutRight(true) unless s.x == 0
+        s.moveOutDown(true) unless s.y == 0
+      )
+    )
+    @currentChapter().currentSlide().moveIn(true)

   keydown: (event) =>
     switch event.keyCode
@@ -75,32 +82,30 @@
         curr = @currentChapter()
         next = @previousChapter()
         if next?
-          curr.currentSlide().hide()
-          next.currentSlide().show()
+          curr.currentSlide().moveOutRight()
+          next.currentSlide().moveIn()
           @current = next
       when 39 # right
         curr = @currentChapter()
         next = @nextChapter()
         if next?
-          curr.currentSlide().hide()
-          next.currentSlide().show()
+          curr.currentSlide().moveOutLeft()
+          next.currentSlide().moveIn()
           @current = next
       when 38 # up
         curr = @currentChapter().currentSlide()
         next = @currentChapter().previousSlide()
         if next?
-          curr.hide()
-          next.show()
+          curr.moveOutDown()
+          next.moveIn()
           @currentChapter().current = next
       when 40 # down
         curr = @currentChapter().currentSlide()
         next = @currentChapter().nextSlide()
         if next?
-          curr.hide()
-          next.show()
+          curr.moveOutUp()
+          next.moveIn()
           @currentChapter().current = next

-  resize: (event) =>
-    # TODO

 window.slidez = new Slidez()


Remove unused test ident client

Remove unused test ident client

--- plugins/dotstorm/test/socket.spec.coffee
+++ plugins/dotstorm/test/socket.spec.coffee
@@ -22,15 +22,10 @@
           common.identifiedSockjsClient server, session, "one@mockmyid.com", (theclient) ->
             client = theclient
             done()
-        (done) ->
-          common.identifiedSockjsClient server, session2, "two@mockmyid.com", (theclient) ->
-            client2 = theclient
-            done()
       ], done

   after (done) ->
     client.close()
-    client2.close()
     common.shutDown(server, done)


fix the “undefined undefined” in invitation email.

--- salvus/hub.coffee
+++ salvus/hub.coffee
@@ -2115,11 +2115,10 @@
                         else
                             cb()
                             # send an email to the user -- async, not blocking user.
-                            # TODO: this can take a while -- we need to take some actionif it fails, e.g., change a setting in the projects table!
-                            s = @signed_in_mesg
+                            # TODO: this can take a while -- we need to take some action
+                            # if it fails, e.g., change a setting in the projects table!
                             send_email
                                 to      : email_address
-                                from    : if s? then "#{s.first_name} #{s.last_name} <#{s.email_address}>" else undefined
                                 subject : "SageMathCloud Invitation"
                                 body    : email.replace("https://cloud.sagemath.com", "Sign up at https://cloud.sagemath.com using the email address #{email_address}.")
                                 cb      : (err) =>
@@ -4788,7 +4787,7 @@
     opts = defaults opts,
         subject : required
         body    : required
-        from    : 'SageMathCloud <wstein@uw.edu>'          # obviously change this at some point.  But it is the best "reply to right now"
+        from    : 'SageMathCloud <wstein@uw.edu>'  # obviously change this at some point.  But it is the best "reply to right now"
         to      : required
         cc      : ''
         cb      : undefined


Send entire payload to Sidekiq

Send entire payload to Sidekiq

--- plugins/email/index.coffee
+++ plugins/email/index.coffee
@@ -8,7 +8,7 @@
     sidekiq = config.sidekiq
     delete config.sidekiq

-    sidekiq.enqueue SIDEKIQ_WORKER, [event.trigger.type, event.error.id, config, event.trigger.message],
+    sidekiq.enqueue SIDEKIQ_WORKER, [event.trigger.type, event.error.id, config, event.trigger.message, event],
       retry: false
       queue: SIDEKIQ_QUEUE


Autocomplete: don't wait for viewappended to create the views

--- src/components/autocomplete/autocompletecontroller.coffee
+++ src/components/autocomplete/autocompletecontroller.coffee
@@ -32,7 +32,7 @@

     super options, data

-    mainView.on 'focus', @bound "updateDropdownContents"
+    mainView.on 'focus', @bound 'updateDropdownContents'

     @lastPrefix          = null
     @selectedItemData    = []
@@ -40,14 +40,15 @@
     @selectedItemCounter = 0
     @readyToShowDropDown = yes

+    @createDropDown()
+    @getAutoCompletedItemParent()
+
   reset:->
     subViews = @itemWrapper.getSubViews().slice()
     for item in subViews
       @removeFromSubmitQueue item

   loadView:(mainView)->
-    @createDropDown()
-    @getAutoCompletedItemParent()
     @setDefaultValue()

     mainView.on 'keyup', @utils.debounce 300, (@bound "keyUpOnInputView")


use score's converted mode

use score's converted mode

--- resources/assets/lib/report-score.coffee
+++ resources/assets/lib/report-score.coffee
@@ -71,7 +71,7 @@

     $.ajax
       type: 'POST'
-      url: laroute.route 'scores.report', score: @props.score.id, mode: @props.score.beatmap.mode
+      url: laroute.route 'scores.report', score: @props.score.id, mode: @props.score.mode
       data:
         { comments }
       dataType: 'json'


:lipstick:

:lipstick:

--- src/packages/collaboration/spec/collaboration-spec.coffee
+++ src/packages/collaboration/spec/collaboration-spec.coffee
@@ -76,13 +76,10 @@
         expect(repositoryMirrored).toBe true

     it "reports on the participants of the channel", ->
+      hostSession.one 'started', startedHandler = jasmine.createSpy("startedHandler")
       hostSession.start()

-      waitsFor "host session to start", (started) ->
-        participants = null
-        hostSession.one 'started', (participantsArg) ->
-          participants = participantsArg
-          started()
+      waitsFor "host session to start", -> startedHandler.callCount > 0

-        runs ->
-          expect(participants).toEqual [login: 'hubot', clientId: hostSession.clientId]
+      runs ->
+        expect(startedHandler).toHaveBeenCalledWith [login: 'hubot', clientId: hostSession.clientId]


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -4,7 +4,7 @@

 player = GameObject()

-player.include TimedEvent
+player.include TimedEvents

 @see GameObject


remove step from game object default events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -47,4 +47,4 @@
     if typeof fn is "function"
       fn.apply(self)
     else
-      self.send()+      self.send(fn)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/title_screen.coffee
+++ src/title_screen.coffee
@@ -1,5 +1,5 @@
 ###*
-The Ttit class provides a method to display moving text onscreen, fading out the text over the effect duration.
+The Title Screen class provides a method to display moving text onscreen, fading out the text over the effect duration.

 By default, images are loaded asynchronously. A proxy object is
 returned immediately. Even though it has a draw method it will not


user can save repository

user can save repository


Improve server error when proxy can't retrieve user

--- server/controllers/authentication.coffee
+++ server/controllers/authentication.coffee
@@ -12,7 +12,7 @@
 module.exports.registerIndex = (req, res, next) ->
     User.first (err, user) ->
         if err?
-            error = new Error err.code
+            error = new Error "[Error to access cozy user] " + err.code
             error.status = 500
             error.template =
                 name: 'error'


restore title property in theme api tests

--- server/test/integration/api_theme.coffee
+++ server/test/integration/api_theme.coffee
@@ -120,14 +120,14 @@
       themeJson = body

       assert.equal themeJson.length, themes.length
-      jsonNames = _.map(themeJson, (theme)->
-        theme.name
+      jsonTitles = _.map(themeJson, (theme)->
+        theme.title
       )
-      themeNames = _.map(themes, (theme)->
-        theme.name
+      themeTitles = _.map(themes, (theme)->
+        theme.title
       )

-      assert.deepEqual jsonNames, themeNames
+      assert.deepEqual jsonTitles, themeTitles
       done()
     )
   ).catch((err) ->


Remove saveHelpDialogSettings, it's unused.

It seems this was probably used at some point before the introduction of
settings.set() in the front end.  It isn't used at all, now.

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -83,9 +83,6 @@
     isEnabledForUrl: not rule or rule.passKeys
     passKeys: rule?.passKeys or ""
   }
-
-saveHelpDialogSettings = (request) ->
-  Settings.set("helpDialog_showAdvancedCommands", request.showAdvancedCommands)

 # Retrieves the help dialog HTML template from a file, and populates it with the latest keybindings.
 # This is called by options.coffee.
@@ -651,7 +648,6 @@
   copyToClipboard: copyToClipboard
   pasteFromClipboard: pasteFromClipboard
   isEnabledForUrl: isEnabledForUrl
-  saveHelpDialogSettings: saveHelpDialogSettings
   selectSpecificTab: selectSpecificTab
   refreshCompleter: refreshCompleter
   createMark: Marks.create.bind(Marks)


Add minor fix

Add minor fix


redirect to index on login

redirect to index on login

--- app/authenticators/irene.coffee
+++ app/authenticators/irene.coffee
@@ -15,6 +15,10 @@
   session: Ember.inject.service()
   ajax: Ember.inject.service()

+  transitionTo: (route)->
+    applicationRoute = Ember.getOwner(@).lookup("route:application")
+    applicationRoute.transitionTo route
+
   authenticate: (identification, password) ->
     ajax = @get "ajax"
     session = @get "session"
@@ -30,6 +34,7 @@
         b64token = getB64Token data.user, data.token
         session.set 'data.b64token', b64token
         resolve data
+        that.transitionTo ENV['ember-simple-auth']["routeAfterAuthentication"]
       .catch (reason) ->
         alert reason
         reject reason
@@ -45,6 +50,7 @@
         b64token = getB64Token data.user, data.token
         session.set 'data.b64token', b64token
         resolve data
+        that.transitionTo ENV['ember-simple-auth']["routeIfAlreadyAuthenticated"]
       .catch (reason)->
         alert reason
         localStorage.clear()
@@ -66,5 +72,4 @@
         location.reload()

-
 `export default IreneAuthenticator;`


clarified comment

clarified comment

--- app/components/eui-popup.coffee
+++ app/components/eui-popup.coffee
@@ -16,7 +16,7 @@
   highlighted: undefined # Option currently highlighted
   action: undefined # Controls what happens if option is clicked. Select it or perform Action

-  previousFocus: null # Where the user's focus was before the popup was launched
+  previousFocus: null # Where the user's focus was before the popup was opened (only for keyboard nav)

   hide: ->
     @set('isOpen', false)


Refactor services.coffee

Refactor services.coffee

--- app/controllers/services.coffee
+++ app/controllers/services.coffee
@@ -5,8 +5,10 @@
   return ({app, initPlugins}) ->
     router.use auth.ensureAuthenticated

-    sendErr = (res, msg) ->
-      res.send {error: msg}
+    sendErr = (res, err) ->
+      console.error(err)
+      error = err.message || err
+      res.send {error}

     extractActiveRepo = (req, res, next) ->
       ActiveRepo.findOne {repoId: req.params.repoId, sourceProviderName: req.params.sourceProviderName, userId: req.user._id}, (err, activeRepo) ->
@@ -16,37 +18,36 @@
         next()

     # TODO change to pOSt for ajax goodness
-    # TODO async.waterfall()
     router.get '/activate/:sourceProviderName/:repoId/:serviceName', extractActiveRepo, (req, res, next) ->
       activeRepo = req.activeRepo
-      if _.contains(activeRepo.activeServices, req.params.serviceName)
-        req.flash('error', 'Service already active!')
-        return res.redirect '/dashboard'
-      service = _.findWhere initPlugins.services, {NAME: req.params.serviceName}
+      {sourceProviderName, serviceName} = req.params
+      if _.contains(activeRepo.activeServices, serviceName)
+        return sendErr(res, new Error('Service already active.'))
+      service = _.findWhere initPlugins.services, {NAME: serviceName}
       service.activateServiceForRepo activeRepo, (activateServiceError, successMessage) ->
-        next(activateServiceError) if activateServiceError
-        activeRepo.activeServices.push req.params.serviceName
+        return sendErr(res, activateServiceError) if activateServiceError?
+        activeRepo.activeServices.push serviceName
         activeRepo.markModified 'activeServices'
         activeRepo.save (saveError, savedActiveRepo) ->
-          return sendErr(res, saveError.message) if saveError
+          return sendErr(res, saveError) if saveError?
           repoIdString = savedActiveRepo._id.toString()
           queueMap[repoIdString] ?= async.queue(repoQueueWorker, 1)
           queueMap[repoIdString].push {repo: savedActiveRepo, initPlugins, serviceToInitialize: service}, (queueProcessError) ->
-            return sendErr(res, queueProcessError.message) if queueProcessError
-            res.send(successMessage)
+            return sendErr(res, queueProcessError) if queueProcessError?
+            res.send({success: successMessage || 'Successfully activated service.'})

     router.get '/deactivate/:sourceProviderName/:repoId/:serviceName', extractActiveRepo, (req, res, next) ->
-      service = _.findWhere initPlugins.services, {NAME: req.params.serviceName}
       activeRepo = req.activeRepo
-      if not _.contains(activeRepo.activeServices, req.params.serviceName)
-        req.flash('error', "Could not deactivate #{service.DISPLAY_NAME} - it was not active!")
-        return res.redirect '/dashboard'
+      {sourceProviderName, serviceName} = req.params
+      if not _.contains(activeRepo.activeServices, serviceName)
+        return sendErr(res, new Error("Could not deactivate #{service.DISPLAY_NAME} - it was not active."))
+      service = _.findWhere initPlugins.services, {NAME: serviceName}
       service.deactivateServiceForRepo activeRepo, (deactivateServiceError, successMessage) ->
-        next(deactivateServiceError) if deactivateServiceError
-        activeRepo.activeServices = _.without activeRepo.activeServices, req.params.serviceName
+        return sendErr(res, deactivateServiceError) if deactivateServiceError?
+        activeRepo.activeServices = _.without activeRepo.activeServices, serviceName
         activeRepo.markModified 'activeServices'
         activeRepo.save (saveError) ->
-          next(saveError) if saveError
-          res.send(successMessage)
+          return sendErr(res, saveError) if saveError?
+          res.send({success: successMessage || 'Successfully deactivated service.'})

     app.use '/services', router


WIP stacks: use published counts for summaries instead of counting components

--- ui.coffee
+++ ui.coffee
@@ -84,12 +84,12 @@
     if stack?
       if count is 1
         "1 #{stack} #{@displayNameSingular}"
-      else
+      else if count
         "#{count} #{stack} #{@displayNamePlural}"
     else
       if count is 1
         "1 #{@displayNameSingular}"
-      else
+      else if count
         "#{count} #{@displayNamePlural}"

   getCounterTemplate: (count, rules) ->
@@ -198,17 +198,12 @@

   summary: (owner) ->
     owner ?= Template.currentData().owner
-    counts = {}
-    # Go directly to the collection to sidestep the transform
-    # (could also use transform=null but this is faster)
-    CBGA.Components.find _container: [@panel.owner, owner._id, @container],
-      fields: type: 1
-    .forEach (doc) ->
-      counts[doc.type] ?= 0
-      counts[doc.type] += 1
-      return
-    for type, count of counts
-      @rules.getComponentType(type).summary(count)
+    CBGA.ContainerCounts.find
+      ownerType: @panel.owner
+      owner: owner._id
+      name: @container
+    .map (container) =>
+      @rules.getComponentType(container.type).summary(container.count)

   getOwner: (elementOrView) ->
     # elementOrView can also be undefined for the current view


fix metadata editor tests

fix metadata editor tests

[#103014778]

--- spec/javascripts/itsi_editor_spec.coffee
+++ spec/javascripts/itsi_editor_spec.coffee
@@ -37,16 +37,17 @@

     beforeAll ->
       @props =
-        metadata:
+        data:
           name: "activity name"
           description: "activity description"
           update_url: "fake_update_url"

     it "uses props for default values", ->
       metadataEditor = jasmine.react.renderComponent "itsi_authoring/metadata_editor", @props
-      tags = jasmine.react.findTags metadataEditor, ["input", "textarea"]
-      expect(tags.input.getDOMNode().value).toBe(@props.metadata.name)
-      expect(tags.textarea.getDOMNode().value).toBe(@props.metadata.description)
+      heading = jasmine.react.findTag metadataEditor, "h1"
+      description = jasmine.react.findClass metadataEditor, "ia-section-text-value"
+      expect(heading.getDOMNode().innerHTML).toBe(@props.data.name)
+      expect(description.getDOMNode().innerHTML).toBe(@props.data.description)

     it "does not save when no changes are made", ->
@@ -55,6 +56,8 @@
         lastAlert = {type: type, text: text}
       metadataEditor = jasmine.react.renderComponent "itsi_authoring/metadata_editor", @props

+      jasmine.react.click (jasmine.react.findClass metadataEditor, "ia-section-editor-edit")
+
       jasmine.react.itsi.captureSave metadataEditor

       expect(lastAlert.type).toBe("warn")
@@ -63,32 +66,35 @@

     it "saves when name changes are made", ->
       metadataEditor = jasmine.react.renderComponent "itsi_authoring/metadata_editor", @props
+      jasmine.react.click (jasmine.react.findClass metadataEditor, "ia-section-editor-edit")

       jasmine.react.itsi.changeTag metadataEditor, "input", "New activity name"
       request = jasmine.react.itsi.captureSave metadataEditor

-      expect(request.url).toBe("fake_update_url")
+      expect(request.url).toBe("fake_update_url.json")
       expect(request.params).toBe("lightweight_activity%5Bname%5D=New+activity+name&_method=PUT")

     it "saves when description changes are made", ->
       metadataEditor = jasmine.react.renderComponent "itsi_authoring/metadata_editor", @props
+      jasmine.react.click (jasmine.react.findClass metadataEditor, "ia-section-editor-edit")

       jasmine.react.itsi.changeTag metadataEditor, "textarea", "New activity description"
       request = jasmine.react.itsi.captureSave metadataEditor

-      expect(request.url).toBe("fake_update_url")
+      expect(request.url).toBe("fake_update_url.json")
       expect(request.params).toBe("lightweight_activity%5Bdescription%5D=New+activity+description&_method=PUT")

     it "saves when name and description changes are made", ->
       metadataEditor = jasmine.react.renderComponent "itsi_authoring/metadata_editor", @props
+      jasmine.react.click (jasmine.react.findClass metadataEditor, "ia-section-editor-edit")

       jasmine.react.itsi.changeTag metadataEditor, "input", "New activity name"
       jasmine.react.itsi.changeTag metadataEditor, "textarea", "New activity description"
       request = jasmine.react.itsi.captureSave metadataEditor

-      expect(request.url).toBe("fake_update_url")
+      expect(request.url).toBe("fake_update_url.json")
       expect(request.params).toBe("lightweight_activity%5Bname%5D=New+activity+name&lightweight_activity%5Bdescription%5D=New+activity+description&_method=PUT")

   describe "section editor element", ->


add touchstart event to close tutorial

add touchstart event to close tutorial

--- tutorial/tutorial.coffee
+++ tutorial/tutorial.coffee
@@ -53,6 +53,7 @@
     @el.fadeIn(250)
     @showSlide(1)
     window.addEventListener "click", @exitIfClickOutside
+    window.addEventListener "touchstart", @exitIfClickOutside

   exitIfClickOutside: (e) => @exit() if e.target.id is "tutorial"

@@ -76,6 +77,7 @@
   exit: =>
     @el.fadeOut(250)
     window.removeEventListener "click", @exitIfClickOutside
+    window.removeEventListener "touchstart", @exitIfClickOutside

   showIfNewUser: ->
     tutorialSeen = User.current?.preferences?.kelp?.tutorial_seen


Fix textinput -> text_input in main.coffee

--- bokehjs/src/coffee/main.coffee
+++ bokehjs/src/coffee/main.coffee
@@ -133,7 +133,7 @@
   # widgets
   Bokeh.HBox           = require("widget/hbox")
   Bokeh.VBox           = require("widget/vbox")
-  Bokeh.TextInput      = require("widget/textinput")
+  Bokeh.TextInput      = require("widget/text_input")
   Bokeh.CrossFilter    = require("widget/crossfilter")

   exports.Bokeh = Bokeh


fix icons path for undefiend theme

fix icons path for undefiend theme

--- bootstrap-themer-server.coffee
+++ bootstrap-themer-server.coffee
@@ -31,11 +31,13 @@

   if addTheme
     themeName = ThemeCollection.findOne('main').theme
-    themeLess = """
-    // THEME: #{themeName}
-    """
+    themeLess = ""
     if themeName and themeName isnt 'null'
-        # theme less
+        # add theme less
+        themeLess+= """
+        // THEME: #{themeName}
+
+        """
         themeLess+= fs.readFileSync "#{themesPath}#{themeName}/variables.less", 'utf8'
         themeLess+= fs.readFileSync "#{themesPath}#{themeName}/bootswatch.less", 'utf8'


Update science page help text

Update science page help text

--- app/pages/lab/science-case.cjsx
+++ app/pages/lab/science-case.cjsx
@@ -10,7 +10,7 @@

   render: ->

-
This page is for you to describe your research motivations and goals to the volunteers. Feel free to add detail, but try to avoid jargon. This page renders markdown, so you can format it and add images (externally hosted for now) and links. The site will show your team members with their profile pictures and roles to the side of the text.

+
This page is for you to describe your research motivations and goals to the volunteers. Feel free to add detail, but try to avoid jargon. This page renders markdown, so you can format it and add images via the Media Library and links. The site will show your team members with their profile pictures and roles to the side of the text.

         <AutoSave resource={@props.project}>
           Science case


fixed coffeelint errors on workers/social/lib/social/models/emailnotification.coffee

--- workers/social/lib/social/models/emailnotification.coffee
+++ workers/social/lib/social/models/emailnotification.coffee
@@ -1,5 +1,5 @@
-{Model, Base, ObjectId, secure, signature} = require 'bongo'
-{extend} = require 'underscore'
+{ Model, Base, ObjectId, secure, signature } = require 'bongo'
+{ extend } = require 'underscore'
 KodingError = require '../error'

 { v4: createId } = require 'node-uuid'
@@ -66,11 +66,11 @@
     groupInvite          :
       eventType          : ['Invited']
       contentTypes       : ['JGroup'],
-      definition         : "when someone invites you to their group"
+      definition         : 'when someone invites you to their group'
     groupRequest         :
       eventType          : ['ApprovalRequested', 'InvitationRequested']
       contentTypes       : ['JGroup'],
-      definition         : "when someone requests membership to group"
+      definition         : 'when someone requests membership to group'
     groupApproved        :
       eventType          : ['Approved']
       contentTypes       : ['JGroup'],
@@ -78,23 +78,23 @@
     groupJoined          :
       eventType          : ['GroupJoined']
       contentTypes       : ['JGroup'],
-      definition         : "when a member joins your group"
+      definition         : 'when a member joins your group'
     groupLeft            :
       eventType          : ['GroupLeft']
       contentTypes       : ['JGroup'],
-      definition         : "when a member leaves your group"
+      definition         : 'when a member leaves your group'

-  @checkEmailChoice = (options, callback)->
+  @checkEmailChoice = (options, callback) ->

-    {username, contentType, event} = options
+    { username, contentType, event } = options

     JUser = require './user'
-    JUser.someData {username}, {email:1, emailFrequency:1}, (err, cursor)->
+    JUser.someData { username }, { email:1, emailFrequency:1 }, (err, cursor) ->
       if err
         console.error "Could not load user record for #{username}"
         callback err
-      else cursor.nextObject (err, user)->
-        {emailFrequency, email} = user
+      else cursor.nextObject (err, user) ->
+        { emailFrequency, email } = user
         unless emailFrequency?
           callback null
         else
@@ -107,9 +107,9 @@
                   return
           callback null

-  @create = (data, callback=->)->
+  @create = (data, callback = -> ) ->

-    {actor, receiver, event, contents, bcc} = data
+    { actor, receiver, event, contents, bcc } = data

     return callback null  if receiver.type is 'unregistered'

@@ -143,18 +143,18 @@
                              when contentType in type.contentTypes \
                              and event in type.eventType][0][0]?[0]

-    selector = {event, receiver, contentId}
+    selector = { event, receiver, contentId }
     if sender instanceof ObjectId
     then selector.sender = sender
     else selector.senderEmail = sender

-    JMailNotification.count selector, (err, count)->
+    JMailNotification.count selector, (err, count) ->
       if not err and count is 0
         notification = new JMailNotification extend selector, {
-          eventFlag, activity, unsubscribeId: getUniqueId()+getUniqueId()+'', bcc
+          eventFlag, activity, unsubscribeId: getUniqueId() + getUniqueId() + '', bcc
         }
         # console.log "OK good to go."
-        notification.save (err)->
+        notification.save (err) ->
           if err then console.error err
           else
             callback null
@@ -162,13 +162,13 @@
       # else
       #   console.log "Already exists"

-  @unsubscribeWithId = (unsubscribeId, email, opt, callback)->
+  @unsubscribeWithId = (unsubscribeId, email, opt, callback) ->

-    JMailNotification.one {unsubscribeId}, (err, notification)->
+    JMailNotification.one { unsubscribeId }, (err, notification) ->
       if err or not notification then callback err
       else
         JAccount = require './account'
-        JAccount.one {_id: notification.receiver}, (err, account)->
+        JAccount.one { _id: notification.receiver }, (err, account) ->
           if err or not account then callback err
           else
             prefs = {}
@@ -179,14 +179,16 @@
               prefs.daily = false
             else
               prefs[notification.eventFlag] = false
-              {definition} = flags[notification.eventFlag]
+              { definition } = flags[notification.eventFlag]
             username = account.profile.nickname
             JUser = require './user'
-            JUser.one {username}, (err, user)->
+            JUser.one { username }, (err, user) ->
               if err or not user then callback err
               else if user.email isnt email
                 callback new KodingError 'Unsubscribe token does not match given email.'
-              else account.setEmailPreferences user, prefs, (err)->
+              else account.setEmailPreferences user, prefs, (err) ->
                 if err then callback err
                 else
                   callback null, "You will no longer get e-mails #{definition}"
+
+


GitProvider: decode content before generating the stack

--- workers/social/lib/social/models/gitprovider/index.coffee
+++ workers/social/lib/social/models/gitprovider/index.coffee
@@ -1,4 +1,5 @@
 { Base, signature } = require 'bongo'
+Encoder             = require 'htmlencode'
 Constants           = require './constants'
 GitHubProvider      = require './githubprovider'
 GitLabProvider      = require './gitlabprovider'
@@ -57,7 +58,7 @@
       requiredData      = requirementsParser rawContent
       config            = { requiredData, requiredProviders, importData }

-      convertedDoc = yamlToJson rawContent
+      convertedDoc = yamlToJson Encoder.htmlDecode rawContent
       if convertedDoc.err
         return callback new KodingError 'Failed to convert YAML to JSON'


Refactor checkout button to remove one-click-logic (checkout ctrl already doest it)

--- app/assets/javascripts/sprangular/directives/checkoutButton.coffee
+++ app/assets/javascripts/sprangular/directives/checkoutButton.coffee
@@ -6,31 +6,8 @@
     user: '='
   templateUrl: 'directives/checkout_button.html'
   controller: ($scope, $location, Cart, Checkout) ->
-    $scope.allowOneClick = false
     $scope.processing = false

-    $scope.$watch 'user', (user) ->
-      $scope.allowOneClick = user.allowOneClick
-
-    $scope.standardCheckout = ->
+    $scope.checkout = ->
       $scope.processing = true
       $location.path("/checkout")
-
-    $scope.oneClickCheckout = ->
-      $scope.processing = true
-
-      order = Cart.current
-      user = $scope.user
-
-      order.resetAddresses(user)
-      order.resetCreditCard(user)
-
-      Checkout.update('payment')
-        .then ->
-          $location.path('/checkout')
-
-    $scope.checkout = ->
-      if $scope.allowOneClick
-        $scope.oneClickCheckout()
-      else
-        $scope.standardCheckout()


syntax yo

syntax yo

--- src/packages/editor-stats/src/editor-stats-view.coffee
+++ src/packages/editor-stats/src/editor-stats-view.coffee
@@ -5,7 +5,7 @@

 module.exports =
 class EditorStatsView extends ScrollView
-  hours = 2
+  hours = 6

   time = (date) ->
     date.setTime(date.getTime() + 6e4)
@@ -63,7 +63,7 @@
     bars = vis.selectAll('rect.bar')
       .data(data)
     .enter().append('rect')
-      .attr('x', (d, i) -> console.log x(0); x(i))
+      .attr('x', (d, i) -> x i)
       .attr('y', (d) -> y d.value)
       .attr('width', x.rangeBand())
       .attr('class', 'bar')
@@ -76,7 +76,7 @@

       bars.data(newdata).transition()
         .attr('height', (d, i) ->  h - y(d.value))
-        .attr('y', (d, i) -> y(d.value))
+        .attr('y', (d, i) -> y d.value)

     setInterval update, 5000


Load program

Load program

--- src/config/programs.coffee
+++ src/config/programs.coffee
@@ -44,9 +44,10 @@
     signal

   # TODO: Break this out into a test config
+  # TODO: Find a more elegant way to match the label and display name
   _CHILDREN: [
-    {_CHILDREN: ['buffer:'], value: []}
-    {_CHILDREN: [DEFAULT, "forward", "right"], value: []}
+    {_LABEL: 'buffer:', _CHILDREN: ['buffer:']}
+    {_LABEL: DEFAULT, _CHILDREN: [DEFAULT, "forward", "right"]}
   ]
 }


Fix default split

Fix default split

--- app/lib/splits.coffee
+++ app/lib/splits.coffee
@@ -5,6 +5,7 @@
     default:
       header: 'Did you know'
       body: 'You can collect your favorite storm images and discuss them in Talk.'
+      isShown: -> true

     a:
       header: ''