main: Add commandline options instead of hardcoding

--- src/main.coffee
+++ src/main.coffee
@@ -5,19 +5,28 @@
 heroku = require './heroku'
 governor = require './governor'

+program = require 'commander'
+
+parse = (argv) ->
+  program
+    .option('--config <string>', 'Configuration string', String, '')
+    .option('--dry-run', 'Configuration string', Boolean, false)
+    .option('--oneshot', 'Run once instead of continously', Boolean, false)
+    .parse(argv)
+
 exports.main = () ->

-  # FIXME: add commandline options
-  cfgstr = process.env['GUV_CONFIG']
+  options = parse process.argv
+  options.config = process.env['GUV_CONFIG'] if not options.config

-  heroku.dryrun = true
-  cfg = config.parse cfgstr
+  heroku.dryrun = options['dry-run']
+  cfg = config.parse options.config
   guv = new governor.Governor cfg

-  guv.start()
+  if options.oneshot
+    guv.runOnce (err, state) ->
+      throw err if err
+      console.log state
+  else
+    guv.start()

-###
-  guv.runOnce (err, state) ->
-    throw err if err
-    debug 'run once', state
-###


use the same gravatar url that github does

--- js/inner/user.coffee
+++ js/inner/user.coffee
@@ -22,6 +22,7 @@
     plan: null
     parallelism: 1
     gravatar_id: null
+    github_id: null

   constructor: (json) ->
     super json,
@@ -64,7 +65,12 @@
     @gravatar_url = (size=200, force=false) =>
       @komp =>
         if @gravatar_id() and @gravatar_id() isnt ""
-          "https://secure.gravatar.com/avatar/#{@gravatar_id()}?s=#{size}"
+          url = "https://secure.gravatar.com/avatar/#{@gravatar_id()}?s=#{size}"
+          if @github_id()
+            hash = CryptoJS.MD5(@github_id().toString()).toString()
+            d = URI.encode("https://identicons.github.com/#{hash}.png")
+            url += "&d=#{d}"
+          url
         else if force
           "https://secure.gravatar.com/avatar/00000000000000000000000000000000?s=#{size}"


Fix for git 2.9

Fix for git 2.9

--- webpack/dist/tag.coffee
+++ webpack/dist/tag.coffee
@@ -20,5 +20,5 @@
 git 'push', '--tags', '--force', 'origin'
 git 'fetch'
 git 'checkout', '-f', 'dist'
-git 'merge', '-X', 'theirs', vX, '-m', vX
+git 'merge', '-X', 'theirs', '--allow-unrelated-histories', vX, '-m', vX
 git 'push'


Remove console.info on selfUser found

Remove console.info on selfUser found

--- www/js/views/app.coffee
+++ www/js/views/app.coffee
@@ -49,12 +49,11 @@
         success: (users) ->
           self.selfUser = Users.getSelf()

-          if self.selfUser
-            # Load up the app!
-            console.log "selfUser", self.selfUser
-          else
+          # If there's no "selfUser", we need to display an intro screen/login
+          # prompt and authorize the user's device.
+          if not self.selfUser
             console.info "No user with relationship: RELATIONSHIP_SELF found"
             self.currentView = new UserViews.Login
         error: ->
           # TODO: Obviously, make this better.
-          window.alert "Error loading podcasts data. Contact support: tofumatt@mozilla.com"
+          window.alert "Error loading data. Contact support: tofumatt@mozilla.com"


Don't bash over strip prefixes in .groc.json

--- lib/cli.coffee
+++ lib/cli.coffee
@@ -113,7 +113,7 @@
   # the extra options behavior that we require.
   utils.CLIHelpers.configureOptimist opts, optionsConfig, projectConfig
   #} We have one special case that depends on other defaults...
-  opts.default 'strip', Utils.guessStripPrefixes opts.argv.glob
+  opts.default 'strip', Utils.guessStripPrefixes opts.argv.glob unless projectConfig.strip?

   argv = utils.CLIHelpers.extractArgv opts, optionsConfig
   # If we're in tracing mode, the parsed options are extremely helpful.


Deleting a remote URL (git remote set-url --delete...)

--- src/repo.coffee
+++ src/repo.coffee
@@ -198,6 +198,17 @@
     , (err, stdout, stderr) ->
       callback err

+  # Public: Delete a remote URL.
+  #
+  # name     - String name of the remote.
+  # url      - String url of the remote.
+  # callback - Receives `(err)`
+  #
+  remote_delete_url: (name, url, callback) ->
+    @git "remote set-url", {}, ["--delete", name, url]
+    , (err, stdout, stderr) ->
+      callback err
+
   # Public: Remove a remote.
   #
   # name     - String name of the remote.


! wip center while moving 2

! wip center while moving 2

--- lib/map.coffee
+++ lib/map.coffee
@@ -22,10 +22,11 @@
       callback();

   move: (fieldSize, scale) =>
-    centerWidth  = Math.ceil(@viewportWidth - @viewportWidth * scale) / 2
-    centerHeight = Math.ceil(@viewportHeight - @viewportHeight * scale) / 2
-    ax = -(@data.rx + 1) * fieldSize + centerWidth + @mapLayer.outsetX; # +1 begin outside of viewport
-    ay = -(@data.ry + 1) * fieldSize + centerHeight + @mapLayer.outsetY; # +1 begin outside of viewport
+    rx = @data.rx - Math.round((@fieldWidth - @fieldWidth * scale) / 2)
+    ry = @data.ry - Math.round((@fieldHeight - @fieldHeight * scale) / 2)
+    @data.setDataPosition(rx, ry);
+    ax = -(@data.rx + 1) * fieldSize + @mapLayer.outsetX; # +1 begin outside of viewport
+    ay = -(@data.ry + 1) * fieldSize + @mapLayer.outsetY; # +1 begin outside of viewport
     @mapLayer.mapMovedTo(ax, ay);

   create: () =>


Show 404 when deleting a non-existing task

--- lib/nbi.coffee
+++ lib/nbi.coffee
@@ -330,6 +330,11 @@
         if request.method == 'DELETE'
           db.tasksCollection.findOne({'_id' : taskId}, {'device' : 1}, (err, task) ->
             return throwError(err, response) if err
+            if not task?
+              response.writeHead(404)
+              response.end("Task not found")
+              return
+
             deviceId = task.device
             db.tasksCollection.remove({'_id' : taskId}, (err) ->
               return throwError(err, response) if err


fix(composer): don't show popout in composer on output

--- src/nylas-env.coffee
+++ src/nylas-env.coffee
@@ -361,7 +361,7 @@
     @getWindowType() is 'work'

   isComposerWindow: ->
-    @getWindowType() is 'composer'
+    @getWindowType() in ["composer", "composer-preload"]

   getWindowType: ->
     @getLoadSettings().windowType


Simplify pullVarAsArray (which makes it look unnecessary)

--- src/util.coffee
+++ src/util.coffee
@@ -3,7 +3,7 @@
 # determine rounding of axis labels
 formatAxis = (d, extra_digits=0) ->
     d = d[1] - d[0]
-    ndig = Math.floor( Math.log(d % 10) / Math.log(10) )
+    ndig = Math.floor( log10(d) )
     ndig = 0 if ndig > 0
     ndig = Math.abs(ndig) + extra_digits
     d3.format(".#{ndig}f")
@@ -16,10 +16,7 @@

 # Pull out a variable (column) from a two-dimensional array
 pullVarAsArray = (data, variable) ->
-    v = []
-    for i of data
-        v = v.concat data[i][variable]
-    v
+    (data[i][variable] for i of data)

 # Select a set of categorical colors
 # ngroup is positive integer


Oops, broke utf8 parsing.

Oops, broke utf8 parsing.


Fix parseInt bug

Fix parseInt bug

--- src/view.coffee
+++ src/view.coffee
@@ -23,9 +23,9 @@
     if hex.length is 4
       hex = hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]

-    r = Number.parseInt hex[1..2], 16
-    g = Number.parseInt hex[3..4], 16
-    b = Number.parseInt hex[5..6], 16
+    r = parseInt hex[1..2], 16
+    g = parseInt hex[3..4], 16
+    b = parseInt hex[5..6], 16

     r = Math.round (r + 128) / 2
     g = Math.round (g + 128) / 2


update meta_description (#5698)

update meta_description (#5698)

--- app/locale/zh-HANS.coco.coffee
+++ app/locale/zh-HANS.coco.coffee
@@ -2,8 +2,8 @@

   new_home:
     title: "CodeCombat - 硅谷原创AP官方权威认证青少年编程平台"
+    meta_description: "CodeCombat中国官方教学版，美国大学理事会认证，国际等级证书，AI世青赛全球独家技术伙伴。"
     meta_keywords: "青少年编程, 少儿编程, CodeCombat, CodeCombat中国, steam教育, python, javascript, 游戏化编程, 美国AP/CSP认证, AI世青赛技术支持平台"
-    meta_description: "CodeCombat（中国官方网址：koudashijie.com）于2013年成立于美国硅谷，是美国大学理事会权威认证的青少年编程学习平台和工信部赛迪人工智能大赛全球独家技术合作平台，学习者可以在CodeCombat学习后参加AP计算机考试，拿到世界一流名校如斯坦福大学、哈佛大学、麻省理工学院等学分减免政策，是全球公认的权威青少年计算机编程学习平台之一。"
     meta_og_url: "https://koudashijie.com"
     built_for_teachers_title: "一个以教师为中心的课程体系"
     built_for_teachers_blurb: "教孩子们写代码往往会觉得无从下手。 CodeCombat 旨在帮助所有的教育工作者传授学生学习和掌握当下最流行的两种计算机语言，JavaScript 和 Python。整个体系包含六门计算机科学课程，以及通过基于项目的游戏开发和网页开发单元巩固学习，教会孩子们一步步从基本语法到高级递归前进！"


Fixes typo

Fixes typo

--- app/pages/about/team-page.cjsx
+++ app/pages/about/team-page.cjsx
@@ -49,7 +49,7 @@
         title: 'Developer'
         bio: '''Responsible for building the Zooniverse's API infrastructure.
         Cam considers himself a music and fine wine connoisseur - others do not.
-        In his space time he enjoys playing an obscure form of rugby.'''
+        In his spare time he enjoys playing an obscure form of rugby.'''
       chrisLintott:
         title: 'Zooniverse PI'
         bio: '''Astronomer and founder of both Galaxy Zoo and the Zooniverse that grew from it,


Add content to how-to document on what happens when adding '!' to the fieldname in the manifest file

Add to the how to document a line or two to explain how to add a ‘!’ to the fieldname in the manifest file to make the column accessible only on Talk

--- app/pages/lab/how-to-page.cjsx
+++ app/pages/lab/how-to-page.cjsx
@@ -219,7 +219,7 @@

       After the first line, each row of the file contains information about 1 subject. The first field, corresponding with the "subject\_id" header, is a unique number that identifies the subject. The second field, which aligns with the "image\_name" header, contains the name of the image that's associated with that subject. These 2 fields are critically important: the image name is obviously important, and a unique identifier is important for matching your classifications to the rest of your data.

-      All the other fields are optional, but in general having more information in the manifest is better. Most projects include additional information in the manifest that helps them match the classifications and subjects to the other data they need for their research. The additional information in the manifest can also be made available to volunteers as they classify (some very keen volunteers find this extremely useful). Any fields with names that begin with “#” or “//” will *not* be shown to volunteers, such as the “#secret\_description” field in Kitteh Zoo. These hidden fields will still be returned to you in the classification file, so you can use these to include information helpful to your research without worrying about whether it might affect the classifications themselves. Information in fields that *don’t* begin with either “#” or “//” will be accessible to volunteers.
+      All the other fields are optional, but in general having more information in the manifest is better. Most projects include additional information in the manifest that helps them match the classifications and subjects to the other data they need for their research. The additional information in the manifest can also be made available to volunteers as they classify or in the Talk discussion tool (some very keen volunteers find this extremely useful). Any fields with names that begin with “#” or “//” will *not* be shown to volunteers, such as the “#secret\_description” field in Kitteh Zoo. These hidden fields will still be returned to you in the classification file, so you can use these to include information helpful to your research without worrying about whether it might affect the classifications themselves. There might be information that could helpful for the volunteers in discussions or further exploration in the Talk discsussion tool, but could bias the classifications if visible to volunteers while classifying. Any fields with names that begin with "!" *will not* be accessible to volunteers in the classification interface, but *will be*  available on Talk after classification. Information in fields that *don’t* begin with a “#”, “//”, or '!' will always be accessible to volunteers in both the classification interface and the Talk discussion tool.

       For now, let’s assume you’re just including the bare minimum of information, like:


No need to specifiy default API url.

No need to specifiy default API url.

--- routes/api.coffee
+++ routes/api.coffee
@@ -6,7 +6,7 @@
 constants = require '../constants'
 utils     = require '../utils'

-fulcrum = new Fulcrum({api_key: constants.api_key, url: 'https://api.fulcrumapp.com/api/v2/'})
+fulcrum = new Fulcrum({api_key: constants.api_key})
 router  = express.Router()

 router.get '/form', (req, res) ->


fixed identation

fixed identation

--- app/templates/_gulpfile.coffee
+++ app/templates/_gulpfile.coffee
@@ -33,8 +33,7 @@
 # -- Tasks ---------------------------------------------------------------------

 gulp.task 'browserify', ->
-  browserify
-    extensions: ['.coffee', '.js']
+  browserify extensions: ['.coffee', '.js']
     .transform coffeeify, global: true
     .require(src.main, { expose: module.shortcut})
     .ignore('coffee-script')


Allow false node.

Allow false node.

--- src/view/view.coffee
+++ src/view/view.coffee
@@ -148,7 +148,7 @@

   @accessor 'node',
     get: ->
-      if not @node
+      if not @node?
         node = @loadView()
         @set('node', node) if node
         @fire('viewDidLoad')


Deleted an unnecessary variable

Deleted an unnecessary variable

--- src/Node.coffee
+++ src/Node.coffee
@@ -101,7 +101,6 @@
   playAnimation: (animation) ->
     animTask = new DivSugar.Task()
     animTask.animation = animation
-    animTask._elapsedTime = 0
     animTask._cmdIndex = 0
     animTask._firstFrame = true
     animTask.onUpdate = (elapsedTime) => @_updateAnimation animTask, elapsedTime
@@ -111,9 +110,7 @@
     return animTask

   _updateAnimation: (animTask, elapsedTime) ->
-    animTask._elapsedTime += elapsedTime
-
-    while animTask._elapsedTime > 0
+    while elapsedTime > 0
       if animTask._cmdIndex >= animTask.animation.length
         animTask.destroy()
         return
@@ -145,12 +142,12 @@

           @_transform.set animTask._fromTransform if animTask._fromImageClip?

-          if animTask._totalTime > animTask._elapsedTime
-            animTask._currentTime += animTask._elapsedTime
-            animTask._elapsedTime = 0
+          if animTask._totalTime > elapsedTime
+            animTask._currentTime += elapsedTime
+            elapsedTime = 0
           else
+            elapsedTime -= animTask._totalTime
             animTask._currentTime = animTask._totalTime
-            animTask._elapsedTime -= animTask._totalTime
             animTask._cmdIndex++
             animTask._firstFrame = true

@@ -188,11 +185,11 @@
             animTask._firstFrame = false
             animTask._waitTime = command[1]

-          if animTask._waitTime > animTask._elapsedTime
-            animTask._waitTime -= animTask._elapsedTime
-            animTask._elapsedTime = 0
+          if animTask._waitTime > elapsedTime
+            animTask._waitTime -= elapsedTime
+            elapsedTime = 0
           else
-            animTask._elapsedTime -= animTask._waitTime
+            elapsedTime -= animTask._waitTime
             animTask._waitTime = 0
             animTask._cmdIndex++
             animTask._firstFrame = true


Add Workspace::onDidChangeActivePaneItem

Closes #3546

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -113,7 +113,7 @@
   # Extended: Invoke the given callback when a pane item is added to the
   # workspace.
   #
-  # * `callback` {Function} to be called panes are added.
+  # * `callback` {Function} to be called when panes are added.
   #   * `event` {Object} with the following keys:
   #     * `item` The added pane item.
   #     * `pane` {Pane} containing the added item.
@@ -121,6 +121,15 @@
   #
   # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
   onDidAddPaneItem: (callback) -> @paneContainer.onDidAddPaneItem(callback)
+
+  # Extended: Invoke the given callback when the active pane item changes.
+  #
+  # * `callback` {Function} to be called when the active pane item changes.
+  #   * `event` {Object} with the following keys:
+  #     * `activeItem` The active pane item.
+  #
+  # Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
+  onDidChangeActivePaneItem: (callback) -> @paneContainer.onDidChangeActivePaneItem(callback)

   # Extended: Invoke the given callback with all current and future panes items in
   # the workspace.


chore(web): fixed build

chore(web): fixed build

--- apps/actor-web/gulpfile.coffee
+++ apps/actor-web/gulpfile.coffee
@@ -41,21 +41,36 @@
 jsBundleFile = 'app-js.js'

 gulp.task 'browserify', ->
+  bundler
+    .bundle()
+    .pipe(source(jsBundleFile))
+    .pipe(buffer())
+    .pipe(gulpif(!argv.production, sourcemaps.init({loadMaps: true})))
+    .pipe(gulpif(!argv.production, sourcemaps.write('./')))
+    .pipe(gulp.dest('./dist/assets/js'))
+    .pipe(connect.reload())
+
+gulp.task 'browserify:watchify', ->
   watcher = watchify(bundler)

-  watcher.on 'update', ->
-    updateStart = Date.now()
-    console.log('Browserify started')
-    watcher.bundle()
-      .pipe(source(jsBundleFile))
-        ## uglify
-      .pipe(gulp.dest('./dist/assets/js'))
-      .pipe(connect.reload())
-    console.log('Browserify ended', (Date.now() - updateStart) + 'ms')
-  .bundle()
-  .pipe(source(jsBundleFile))
-  .pipe(gulp.dest('./dist/assets/js'))
-  .pipe(connect.reload())
+  watcher
+    .on 'error', gutil.log.bind(gutil, 'Browserify Error')
+    .on 'update', ->
+      updateStart = Date.now()
+      console.log('Browserify started')
+      watcher.bundle()
+        .pipe(source(jsBundleFile))
+        .pipe(buffer())
+        .pipe(sourcemaps.init({loadMaps: true}))
+          ## uglify
+        .pipe(sourcemaps.write('./'))
+        .pipe(gulp.dest('./dist/assets/js'))
+        .pipe(connect.reload())
+      console.log('Browserify ended', (Date.now() - updateStart) + 'ms')
+    .bundle()
+    .pipe(source(jsBundleFile))
+    .pipe(gulp.dest('./dist/assets/js'))
+

 gulp.task 'sass', ->
   gulp.src ['./app/**/*.scss']
@@ -111,7 +126,7 @@

 gulp.task 'build', ['assets', 'coffee', 'browserify', 'sass', 'html', 'usemin']

-gulp.task 'build:dev', ['assets', 'coffee', 'browserify', 'sass', 'html']
+gulp.task 'build:dev', ['assets', 'coffee', 'browserify:watchify', 'sass', 'html']

 gulp.task 'dev', ['build:dev', 'server', 'watch']


amqp: Debug in disconnect

amqp: Debug in disconnect

--- src/amqp.coffee
+++ src/amqp.coffee
@@ -30,6 +30,7 @@
         return callback null

   disconnect: (callback) ->
+    debug 'disconnect'
     @channel.close (err) =>
       debug 'close', err
       return callback err


Remove hardcoded home directory path

Remove hardcoded home directory path

--- manager.coffee
+++ manager.coffee
@@ -1,9 +1,12 @@
 httpProxy = require 'http-proxy'
 http = require 'http'
+path = require 'path'
 service = require './service'

+HOME = process.env.HOME or process.env.HOMEPATH or process.env.USERPROFILE
+
 DEFAULT_CONFIG =
-    dir: "/Users/adam/.wow"
+    dir: path.join HOME, ".wow"
     timeout: 20000

 class ServiceManager


remove return now

remove return now

--- lib/analytics.coffee
+++ lib/analytics.coffee
@@ -40,7 +40,6 @@
   el.append '<img src="' + url + '" style="display:none;" />'

 module.exports.registerCurrentUser = ->
-  return
   # Don't track admins
   return if sd.CURRENT_USER?.type == 'Admin'


Rewrite empty data logic

Rewrite empty data logic

--- static/script.coffee
+++ static/script.coffee
@@ -10,11 +10,9 @@
       xdata.unshift i.time[-9..-8] + '时'
       if i.pm2_5 != -1
         pm25_data.unshift i.pm2_5
+        aqi_data.unshift i.aqi
       else
         pm25_data.unshift '-'
-      if i.aqi != -1
-        aqi_data.unshift i.aqi
-      else
         aqi_data.unshift '-'
     myChart.hideLoading()
     option =


Clean up atom details section

Clean up atom details section

--- src/atom.coffee
+++ src/atom.coffee
@@ -226,40 +226,34 @@
     @emitter.on 'did-beep', callback

   ###
-  Section: Atom Metadata
-  ###
-
-  # Essential: Is the current window in development mode?
+  Section: Atom Details
+  ###
+
+  # Public: Is the current window in development mode?
   inDevMode: ->
     @getLoadSettings().devMode

-  # Essential: Is the current window running specs?
+  # Public: Is the current window running specs?
   inSpecMode: ->
     @getLoadSettings().isSpec

-  # Essential: Get the version of the Atom application.
+  # Public: Get the version of the Atom application.
   #
   # Returns the version text {String}.
   getVersion: ->
     @appVersion ?= @getLoadSettings().appVersion

-  # Essential: Determine whether the current version is an official release.
+  # Public: Determine whether the current version is an official release.
   isReleasedVersion: ->
     not /\w{7}/.test(@getVersion()) # Check if the release is a 7-character SHA prefix

-  # Essential: Get the directory path to Atom's configuration area.
+  # Public: Get the directory path to Atom's configuration area.
   #
   # Returns the absolute path to `~/.atom`.
   getConfigDirPath: ->
     @constructor.getConfigDirPath()

-  # Extended: Get the load settings for the current window.
-  #
-  # Returns an {Object} containing all the load setting key/value pairs.
-  getLoadSettings: ->
-    @constructor.getLoadSettings()
-
-  # Extended: Get the time taken to completely load the current window.
+  # Public: Get the time taken to completely load the current window.
   #
   # This time include things like loading and activating packages, creating
   # DOM elements for the editor, and reading the config.
@@ -268,6 +262,12 @@
   # if the window hasn't finished loading yet.
   getWindowLoadTime: ->
     @loadTime
+
+  # Public: Get the load settings for the current window.
+  #
+  # Returns an {Object} containing all the load setting key/value pairs.
+  getLoadSettings: ->
+    @constructor.getLoadSettings()

   ###
   Section: Managing The Atom Window


Check for options before trying to set them

--- src/auth.coffee
+++ src/auth.coffee
@@ -105,9 +105,10 @@
   @request.hook (xhr) ->
     xhr.setRequestHeader 'Authorization', 'Bearer ' + token

-  for option in optionalRequestHeaders
-    @request.hook (xhr) ->
-      xhr.setRequestHeader option.name, option.value
+  if options and options.length
+    for option in optionalRequestHeaders
+      @request.hook (xhr) ->
+        xhr.setRequestHeader option.name, option.value
   this


Avoid re-starting and re-stopping broadcast

--- lib/broadcast.coffee
+++ lib/broadcast.coffee
@@ -7,6 +7,10 @@
     atom.workspaceView.command "broadcast:stop", => @stop()

   start: ->
+    if server isnt null
+      console.error 'Broadcast has already started'
+      return
+
     editor = atom.workspace.activePaneItem
     console.log(editor)
     text = editor.getText()
@@ -23,6 +27,10 @@
     console.log('Broadcst started.')

   stop: ->
+    if server is null
+      console.error 'Broadcast has not started'
+      return
+
     if sockets.length > 0
       for socket in sockets
         socket.destroy()


We do that below

We do that below

--- scripts/rc.coffee
+++ scripts/rc.coffee
@@ -90,7 +90,6 @@
       [@score, @timestamp] = [score, now]
       cb(false, this)

-  # TODO(sshirokov): Take a timestamp to lookup by instead of just latest
   fetch: (cb) =>
     @storage.zscore @key("latest"), @who, (err, stamp) =>
       return cb(err, this) if err


use console.log not logger.log

use console.log not logger.log

we don't habe verbiouse lossing enabled that early in the apps lifecycle
also best not to require modules before enabling profiler

--- metrics.coffee
+++ metrics.coffee
@@ -27,20 +27,19 @@
 		appname = _name
 		collectDefaultMetrics({ timeout: 5000, prefix: Metrics.buildPromKey()})

-		logger = require("logger-sharelatex")

-		logger.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}")
+		console.log("ENABLE_TRACE_AGENT set to #{process.env['ENABLE_TRACE_AGENT']}")
 		if process.env['ENABLE_TRACE_AGENT'] == "true"
-			logger.log("starting google trace agent")
+			console.log("starting google trace agent")
 			traceAgent = require('@google-cloud/trace-agent')

 			traceOpts =
 				ignoreUrls: [/^\/status/, /^\/health_check/]
 			traceAgent.start(traceOpts)

-		logger.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}")
+		console.log("ENABLE_DEBUG_AGENT set to #{process.env['ENABLE_DEBUG_AGENT']}")
 		if process.env['ENABLE_DEBUG_AGENT'] == "true"
-			logger.log("starting google debug agent")
+			console.log("starting google debug agent")
 			debugAgent = require('@google-cloud/debug-agent')
 			debugAgent.start({
 				allowExpressions: true,
@@ -50,9 +49,9 @@
 				}
 			})

-		logger.log("ENABLE_PROFILE_AGENT set to #{process.env['ENABLE_PROFILE_AGENT']}")
+		console.log("ENABLE_PROFILE_AGENT set to #{process.env['ENABLE_PROFILE_AGENT']}")
 		if process.env['ENABLE_PROFILE_AGENT'] == "true"
-			logger.log("starting google profile agent")
+			console.log("starting google profile agent")
 			profiler = require('@google-cloud/profiler')
 			profiler.start({
 				serviceContext: {


Switches to using alphabetical tree view sorting

--- lib/directory.coffee
+++ lib/directory.coffee
@@ -185,7 +185,10 @@
         else
           files.push(new File({name, fullPath, symlink, realpathCache}))

-    directories.concat(files)
+    combined = directories.concat(files)
+
+    combined.sort (first, second) ->
+      first.name.toLowerCase().localeCompare(second.name.toLowerCase())

   # Public: Perform a synchronous reload of the directory.
   reload: ->


fix(lib): tmp fix OSX error dection difference

--- lib/directory.coffee
+++ lib/directory.coffee
@@ -14,7 +14,7 @@
   try
     fs.mkdirSync dir, mode
   catch error
-    if error and error.errno is 34
+    if error # and error.errno is 34
       directory.mkdir_parent path.dirname(dir), mode
       directory.mkdir_parent dir, mode
     else


Fix #123

Fix #123

--- lib/spark-dev.coffee
+++ lib/spark-dev.coffee
@@ -579,13 +579,17 @@
         # Handle errors
         @CompileErrorsView ?= require './views/compile-errors-view'
         errorParser ?= require 'gcc-output-parser'
-        errors = errorParser.parseString(e.errors[0]).filter (message) ->
-          message.type.indexOf('error') > -1
-        if errors.length == 0
+        if e.errors && e.errors.length
+          errors = errorParser.parseString(e.errors[0]).filter (message) ->
+            message.type.indexOf('error') > -1
+
+          if errors.length == 0
+            @SettingsHelper.setLocal 'compile-status', {error: e.output}
+          else
+            @SettingsHelper.setLocal 'compile-status', {errors: errors}
+            atom.commands.dispatch @workspaceElement, 'spark-dev:show-compile-errors'
+        else
           @SettingsHelper.setLocal 'compile-status', {error: e.output}
-        else
-          @SettingsHelper.setLocal 'compile-status', {errors: errors}
-          atom.commands.dispatch @workspaceElement, 'spark-dev:show-compile-errors'

         atom.commands.dispatch @workspaceElement, 'spark-dev:update-compile-status'
         @compileCloudPromise = null


S49757: Plan Estimate - link to field selection

--- kanban/KanbanAppSpec.coffee
+++ kanban/KanbanAppSpec.coffee
@@ -1,7 +1,8 @@
 Ext = window.Ext4 || window.Ext

 Ext.require [
-  'Rally.ui.report.StandardReport'
+  'Rally.ui.report.StandardReport',
+  'Rally.apps.kanban.KanbanApp'
 ]

 describe 'Rally.apps.kanban.KanbanApp', ->
@@ -189,4 +190,15 @@
       query = '(Name contains Foo)'
       @createApp(query: query).then =>
         filterInfo = @app.down('rallyfilterinfo')
-        expect(filterInfo.getQuery()).toBe query+        expect(filterInfo.getQuery()).toBe query
+
+  it 'should show plan estimate when plan estimate field is enabled', ->
+    @ajax.whenQuerying('userstory').respondWithCount(1)
+    @createApp(cardFields: "Name,Discussion,Tasks,Defects,PlanEstimate").then =>
+      expect(@app.getEl().down('.PlanEstimate')).not.toBeNull()
+
+  it 'should not show plan estimate when plan estimate field is disabled', ->
+    @ajax.whenQuerying('userstory').respondWithCount(1)
+    @createApp(cardFields: "Name,Discussion,Tasks,Defects").then =>
+      expect(@app.getEl().down('.PlanEstimate')).toBeNull()
+


migrate to new glyph-styles syntax

migrate to new glyph-styles syntax


create settings object from within oriDomi constructor

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -114,13 +114,14 @@

 class root.OriDomi

-  constructor: (@el, @settings = {}) ->
+  constructor: (@el, options) ->
     console.time 'oridomiConstruction'
     return @el if !oriDomiSupport

     if !(@ instanceof OriDomi)
       return new oriDomi @el, @settings

+    @settings = extendObj options, defaults
     silent = true if @settings.silent
     if !@el? or @el.nodeType isnt 1
       return !silent and console?.warn 'oriDomi: First argument must be a DOM element'
@@ -185,7 +186,6 @@
     contentHolder.classList.add 'oridomi-content'
     contentHolder.style.margin = '0'
     contentHolder.style.position = 'relative'
-

     hMask = document.createElement 'div'
     hMask.className = 'oridomi-mask-h'
@@ -602,14 +602,11 @@
       @

     else
-      settings = extendObj options, defaults
-
       for el in @
         instance = $.data el, 'oriDomi'
         if instance
           return instance
         else
-          $.data el, 'oriDomi', new OriDomi el, settings
+          $.data el, 'oriDomi', new OriDomi el, options

       @
-


separate setSpeed and setTweening methods

--- oridomi.coffee
+++ oridomi.coffee
@@ -587,6 +587,24 @@
       angle

+  # Allows other methods to change the tween duration or disable it altogether.
+  _setTweening: (speed) ->
+    # To loop through the shaders, derive the correct pair from the current anchor.
+    if @lastOp.anchor is 'left' or @lastOp.anchor is 'right'
+      shaderPair = ['left', 'right']
+    else
+      shaderPair = ['top', 'bottom']
+
+    # Loop through the panels in this anchor and set the transition duration to the new speed.
+    for panel, i in @panels[@lastOp.anchor]
+      panel.style[css.transitionDuration] = speed + 'ms'
+      if @shading
+        for side in shaderPair
+          @_shaders[@lastOp.anchor][side][i].style[css.transitionDuration] = speed + 'ms'
+
+    @
+
+
   # `_setShader` determines a shader's opacity based upon panel position, anchor, and angle.
   _setShader: (i, anchor, angle) ->
     # Store the angle's absolute value and generate an opacity based on `shadingIntensity`.
@@ -745,7 +763,7 @@
     # Change the cursor to the active `grabbing` state.
     @stageHolder.style.cursor = css.grabbing
     # Disable tweening to enable instant 1 to 1 movement.
-    @setSpeed false
+    @_setTweening 0
     # Derive the axis to fold on.
     @_touchAxis = if @lastOp.anchor is 'left' or @lastOp.anchor is 'right' then 'x' else 'y'
     # Set a reference to the last folded angle to accurately derive deltas.
@@ -805,7 +823,7 @@
     @_touchStarted = @_inTrans = false
     @stageHolder.style.cursor = css.grab
     # Enable tweening again.
-    @setSpeed true
+    @_setTweening @settings.speed
     # Pass callback final value.
     @settings.touchEndCallback @["_#{ @_touchAxis }Last"]

@@ -826,27 +844,9 @@
   # ==============

-  # Allows other methods to change the tween duration or disable it altogether.
   setSpeed: (speed) ->
-    # If the speed value is `true` reset the speed to the original settings.
-    # Set it to zero if `false`.
-    if typeof speed is 'boolean'
-      speed = if speed then @settings.speed + 'ms' else '0ms'
-
-    # To loop through the shaders, derive the correct pair from the current anchor.
-    if @lastOp.anchor is 'left' or @lastOp.anchor is 'right'
-      shaderPair = ['left', 'right']
-    else
-      shaderPair = ['top', 'bottom']
-
-    # Loop through the panels in this anchor and set the transition duration to the new speed.
-    for panel, i in @panels[@lastOp.anchor]
-      panel.style[css.transitionDuration] = speed
-      if @shading
-        for side in shaderPair
-          @_shaders[@lastOp.anchor][side][i].style[css.transitionDuration] = speed
-
-    @
+    @settings.speed = speed
+    @_setTweening true

   # Disables oriDomi slicing by showing the original, untouched target element.


fixed bridge bugs

fixed bridge bugs

--- oridomi.coffee
+++ oridomi.coffee
@@ -2,7 +2,7 @@
 # ### Fold up the DOM like paper.
 # 0.3.0

-# [http://oridomi.com](http://oridomi.com)
+# [oridomi.com](http://oridomi.com)
 # #### by [Dan Motzenbecker](http://oxism.com)

 # Copyright 2013, MIT License
@@ -1134,7 +1134,7 @@
   if typeof options is 'string'
     methodName = options
     # Check if method exists and warn if it doesn't.
-    unless typeof method = OriDomi::[methodName] is 'function'
+    unless typeof (method = OriDomi::[methodName]) is 'function'
       console?.warn "oriDomi: No such method `#{ methodName }`"
       return @

@@ -1144,8 +1144,8 @@
       console?.warn "oriDomi: Can't call #{ methodName }, oriDomi hasn't been initialized on this element"
       return @

-      # Call the requested method with arguments.
-      method.apply instance, [].slice.call(arguments)[1...]
+    # Call the requested method with arguments.
+    method.apply instance, [].slice.call(arguments)[1...]

     # Return selection.
     @


remove shading during _unfold()

remove shading during _unfold()

--- oridomi.coffee
+++ oridomi.coffee
@@ -992,7 +992,9 @@

       do (panel, i, delay) =>
         defer =>
-          @_transformPanel panel, 0, @_lastOp.anchor
+          @_transformPanel panel, 0, anchor
+          @_setShader i, anchor, 0 if @_shading
+
           setTimeout =>
             showEl panel.children[0]
             if i is len - 1
@@ -1000,7 +1002,9 @@
               callback?()
               @_lastOp.fn    = @accordion
               @_lastOp.angle = 0
+
             defer => panel.style[css.transitionDuration] = @_config.speed
+
           , delay + @_config.speed * .25


Removed unnecessary snippets and added new ones

--- snippets/php.cson
+++ snippets/php.cson
@@ -14,33 +14,28 @@
     'body': 'Debug::dump(${1});'

   #  Fields
+  'OptionsetField':
+    'prefix': 'optionsetfield'
+    'body': 'OptionsetField::create(\'${1:name}\',\'${2:title}\',\'${3:datalist}\')$0'
+  'DropdownField':
+    'prefix': 'dropdownfield'
+    'body': 'DropdownField::create(\'${1:name}\',\'${2:title}\',\'${3:datalist}\')$0'
   'HTMLEditorField':
     'prefix': 'htmlfield'
     'body': 'HtmlEditorField::create(\'${1:name}\',\'${2:title}\')$0'
-  'HTMLEditorFieldInTab':
-    'prefix': 'htmlfieldtab'
-    'body': '\\$fieldsields->addFieldToTab(\'Root.${1:Main}\', HtmlEditorField::create(\'${2:name}\',\'${3:title}\'))$0;\n'
-
   'UploadField':
     'prefix': 'uploadfield'
     'body': 'UploadField::create(\'${1:name}\',\'${2:title}\'))$0;\n'
-  'UploadFieldInTab':
-    'prefix': 'uploadfieldtab'
-    'body': '\\$fields->addFieldToTab(\'Root.${1:Main}\', UploadField::create(\'${2:name}\',\'${3:title}\'))$0;\n'
-
   'TextField':
     'prefix': 'textfield'
     'body': 'TextField::create(\'${1:name}\',\'${2:title}\')$0'
-  'TextFieldInTab':
-    'prefix': 'textfieldtab'
-    'body': '\\$fields->addFieldToTab(\'Root.${1:Main}\', TextField::create(\'${2:name}\',\'${3:title}\'))$0;\n'
-
   'TextareaField':
     'prefix': 'textareafield'
-    'body': 'TextareaField::create(\'${1:name}\',\'${2:title}\',\'${3:rows}\',\'${4:cols}\')$0'
-  'TextareaFieldInTab':
-    'prefix': 'textareafieldtab'
-    'body': '\\$fields->addFieldToTab(\'Root.${1:Main}\', TextareaField::create(\'${2:name}\',\'${3:title}\'))$0;\n'
+    'body': 'TextareaField::create(\'${1:name}\',\'${2:title}\')$0'
+  'GridField':
+    'prefix': 'gridfield'
+    'body': 'GridField::create(\'${1:name}\',\'${2:title}\',\'${3:datalist}\',\'${4:configuration}\')$0'
+

   #  Tabs
   'addFieldToTab':


Fix bug with event target in Data API.

Fix bug with event target in Data API.

--- src/data.coffee
+++ src/data.coffee
@@ -35,32 +35,32 @@
   # Handler for [data-cart-add] click events.
   add: (e) ->
     e.preventDefault()
-    $element = jQuery(e.target)
-    CartJS.Core.addItem $element.data('cartAdd'), $element.data('cartQuantity')
+    $this = jQuery(this)
+    CartJS.Core.addItem $this.data('cartAdd'), $this.data('cartQuantity')

   # Handler for [data-cart-remove] click events.
   remove: (e) ->
     e.preventDefault()
-    $element = jQuery(e.target)
-    CartJS.Core.removeItem $element.data('cartRemove')
+    $this = jQuery(this)
+    CartJS.Core.removeItem $this.data('cartRemove')

   # Handler for [data-cart-remove-id] click events.
   removeById: (e) ->
     e.preventDefault()
-    $element = jQuery(e.target)
-    CartJS.Core.removeItemById $element.data('cartRemoveId')
+    $this = jQuery(this)
+    CartJS.Core.removeItemById $this.data('cartRemoveId')

   # Handler for [data-cart-update] click events.
   update: (e) ->
     e.preventDefault()
-    $element = jQuery(e.target)
-    CartJS.Core.updateItem $element.data('cartUpdate'), $element.data('cartQuantity')
+    $this = jQuery(this)
+    CartJS.Core.updateItem $this.data('cartUpdate'), $this.data('cartQuantity')

   # Handler for [data-cart-update-id] click events.
   updateById: (e) ->
     e.preventDefault()
-    $element = jQuery(e.target)
-    CartJS.Core.updateItemById $element.data('cartUpdateId'), $element.data('cartQuantity')
+    $this = jQuery(this)
+    CartJS.Core.updateItemById $this.data('cartUpdateId'), $this.data('cartQuantity')

   # Handler for [data-cart-clear] click events.
   clear: (e) ->
@@ -69,7 +69,7 @@

   # Handler for [data-cart-toggle] change events.
   toggle: (e) ->
-    $input = jQuery(e.target)
+    $input = jQuery(this)
     id = $input.data('cartToggle')
     if $input.is(':checked')
       CartJS.Core.addItem(id)
@@ -78,7 +78,7 @@

   # Handler for [data-cart-toggle-attribute] change events.
   toggleAttribute: (e) ->
-    $input = jQuery(e.target)
+    $input = jQuery(this)
     attribute = $input.data('cartToggleAttribute')
     CartJS.Core.setAttribute(attribute, if $input.is(':checked') then 'Yes' else '')

@@ -86,7 +86,7 @@
   submit: (e) ->
     e.preventDefault()

-    dataArray = jQuery(e.target).serializeArray()
+    dataArray = jQuery(this).serializeArray()

     id = undefined
     quantity = undefined


fix #13 测试性别

fix #13 测试性别

--- src/data.coffee
+++ src/data.coffee
@@ -21,6 +21,15 @@
     items: [
       '自己'
       '亲友'
+    ]
+  }
+  {
+    type: SELECT
+    title: '被测试人的性别？'
+    p: '男女五行属性不同，测试结果也不相同'
+    items: [
+      '男'
+      '女'
     ]
   }
   {


Stylistics

Stylistics

--- tooltips.coffee
+++ tooltips.coffee
@@ -1,171 +1,174 @@
 # Defaults

 Tooltip =
-	text: false
-	css: {top: 0, left: 0}
-	direction: 'tooltip--top'
+  text: false
+  css: {top: 0, left: 0}
+  direction: 'tooltip--top'

 dep = new Tracker.Dependency()
 offset = [10, 10]

 DIRECTION_MAP =
-	'n': 'tooltip--top'
-	's': 'tooltip--bottom'
-	'e': 'tooltip--right'
-	'w': 'tooltip--left'
+  'n': 'tooltip--top'
+  's': 'tooltip--bottom'
+  'e': 'tooltip--right'
+  'w': 'tooltip--left'

 # Tooltip functions

 getTooltip = ->
-	dep.depend()
-	return Tooltip
+  dep.depend()
+  return Tooltip

 setTooltip = (what, where) ->
-	Tooltip.css = where if where
-	Tooltip.text = what
-	dep.changed()
+  Tooltip.css = where if where
+  Tooltip.text = what
+  dep.changed()

 setPosition = (position, direction) ->
-	Tooltip.css = position
-	Tooltip.direction = DIRECTION_MAP[direction] if direction
-	dep.changed()
+  Tooltip.css = position
+  Tooltip.direction = DIRECTION_MAP[direction] if direction
+  dep.changed()

 hideTooltip = ->
-	setTooltip false
+  setTooltip false

 toggleTooltip = ->
-	if getTooltip().text then hideTooltip() else showTooltip null, $(this)
+  if getTooltip().text then hideTooltip() else showTooltip null, $(this)

 positionTooltip = ($el) ->
-	direction = $el.data('tooltip-direction') or 'n'
-	$tooltip = $(".tooltip")
+  direction = $el.data('tooltip-direction') or 'n'
+  $tooltip = $(".tooltip")

-	position = $el.offset()
-	offLeft = $el.data('tooltip-left')
-	offTop = $el.data('tooltip-top')
+  position = $el.offset()
+  offLeft = $el.data('tooltip-left')
+  offTop = $el.data('tooltip-top')

-	if _.isUndefined(offLeft)
-		offLeft = 0
-	else
-		hasOffsetLeft = true
+  if _.isUndefined(offLeft)
+    offLeft = 0
+  else
+    hasOffsetLeft = true

-	if _.isUndefined(offTop)
-		offTop = 0
-	else
-		hasOffsetTop = true
+  if _.isUndefined(offTop)
+    offTop = 0
+  else
+    hasOffsetTop = true

-	position.top = switch direction
-		when 'w', 'e' then (center vertically $tooltip, $el) + offTop
-		when 'n' then position.top - $tooltip.outerHeight() - (if hasOffsetTop then offTop else offset[1])
-		when 's' then position.top + $el.outerHeight() + (if hasOffsetTop then offTop else offset[1])
+  position.top = switch direction
+    when 'w', 'e' then (center vertically $tooltip, $el) + offTop
+    when 'n' then position.top - $tooltip.outerHeight() - \
+      (if hasOffsetTop then offTop else offset[1])
+    when 's' then position.top + $el.outerHeight() + (if hasOffsetTop then offTop else offset[1])

-	position.left = switch direction
-		when 'n', 's' then (center horizontally $tooltip, $el) + offLeft
-		when 'w' then position.left - $tooltip.outerWidth() - (if hasOffsetLeft then offLeft else offset[0])
-		when 'e' then position.left + $el.outerWidth() + (if hasOffsetLeft then offLeft else offset[0])
+  position.left = switch direction
+    when 'n', 's' then (center horizontally $tooltip, $el) + offLeft
+    when 'w' then position.left - $tooltip.outerWidth() - \
+      (if hasOffsetLeft then offLeft else offset[0])
+    when 'e' then position.left + $el.outerWidth() + (if hasOffsetLeft then offLeft else offset[0])

-	setPosition(position, direction)
+  setPosition(position, direction)

 showTooltip = (evt, $el) ->
-	$el = $el or $(this)
-	viewport = $el.data 'tooltip-disable'
+  $el = $el or $(this)
+  viewport = $el.data 'tooltip-disable'

-	if viewport and _.isString(viewport)
-		mq = window.matchMedia(viewport)
-		return false if mq.matches
+  if viewport and _.isString(viewport)
+    mq = window.matchMedia(viewport)
+    return false if mq.matches

-	content = if selector = $el.data 'tooltip-element'
-		$target = $(selector)
-		$target.length and $target.html()
-	else
-		$el.data('tooltip')
+  content = if selector = $el.data 'tooltip-element'
+    $target = $(selector)
+    $target.length and $target.html()
+  else
+    $el.data('tooltip')

-	setTooltip(content)
-	setPosition(top: 0, left: 0)
+  setTooltip(content)
+  setPosition(top: 0, left: 0)

-	Tracker.afterFlush -> positionTooltip($el)
-
+  Tracker.afterFlush -> positionTooltip($el)

 # Positioning

 center = (args) ->
-	middle = args[0] + args[1] / 2
-	middle - Math.round(args[2] / 2)
+  middle = args[0] + args[1] / 2
+  middle - Math.round(args[2] / 2)

 horizontally = ($el, $reference) ->
-	[$reference.offset().left, $reference.outerWidth(), $el.outerWidth()]
+  [$reference.offset().left, $reference.outerWidth(), $el.outerWidth()]

 vertically = ($el, $reference) ->
-	[$reference.offset().top, $reference.outerHeight(), $el.outerHeight()]
+  [$reference.offset().top, $reference.outerHeight(), $el.outerHeight()]

 # Exports

 Tooltips =
-	disable: false
-	set: setTooltip
-	get: getTooltip
-	hide: hideTooltip
-	setPosition: setPosition
+  disable: false
+  set: setTooltip
+  get: getTooltip
+  hide: hideTooltip
+  setPosition: setPosition

 # Enable/disable for viewports

 Template.tooltips.onCreated ->
-	@disabled = new ReactiveVar(Tooltips.disable)
+  @disabled = new ReactiveVar(Tooltips.disable)

-	if Tooltips.disable and _.isString(Tooltips.disable)
-		mq = window.matchMedia(Tooltips.disable)
-		@disabled.set(mq.matches)
+  if Tooltips.disable and _.isString(Tooltips.disable)
+    mq = window.matchMedia(Tooltips.disable)
+    @disabled.set(mq.matches)

-		mq.addListener (changed) =>
-		  @disabled.set(changed.matches)
-
+    mq.addListener (changed) =>
+      @disabled.set(changed.matches)

 # Template helpers

 Template.tooltips.helpers
-	display: ->
-		tip = getTooltip()
+  display: ->
+    tip = getTooltip()

-		if Template.instance().disabled.get() is true
-			return 'hide'
+    if Template.instance().disabled.get() is true
+      return 'hide'

-		if tip.text then 'show' else 'hide'
+    if tip.text then 'show' else 'hide'

-	position: ->
-		css = getTooltip().css
-		return "position: absolute; top: #{css.top}px; left: #{css.left}px;"
+  position: ->
+    css = getTooltip().css
+    return "position: absolute; top: #{css.top}px; left: #{css.left}px;"

-	content: ->
-		getTooltip().text
+  content: ->
+    getTooltip().text

-	direction: ->
-		getTooltip().direction
+  direction: ->
+    getTooltip().direction

 # Init

 Template.tooltip.onRendered ->

-	this.lastNode._uihooks =
-		insertElement: (node, next) ->
-			next.parentNode.insertBefore(node, next)
+  this.lastNode._uihooks =
+    insertElement: (node, next) ->
+      next.parentNode.insertBefore(node, next)

-		moveElement: (next) ->
-			Tooltips.hide()
-			next.parentNode.insertBefore(node, next)
+    moveElement: (next) ->
+      Tooltips.hide()
+      next.parentNode.insertBefore(node, next)

-		removeElement: (node) ->
-			Tooltips.hide()
-			node.parentNode.removeChild(node)
+    removeElement: (node) ->
+      Tooltips.hide()
+      node.parentNode.removeChild(node)

 Meteor.startup ->
+  $(document).on('mouseover', '[data-tooltip]:not([data-tooltip-trigger]),
+    [data-tooltip-element]:not([data-tooltip-trigger]), [data-tooltip-trigger="hover"]',
+    showTooltip)

-	$(document).on 'mouseover', '[data-tooltip]:not([data-tooltip-trigger]), [data-tooltip-element]:not([data-tooltip-trigger]), [data-tooltip-trigger="hover"]', showTooltip
+  $(document).on('mouseout', '[data-tooltip]:not([data-tooltip-trigger]),
+    [data-tooltip-element]:not([data-tooltip-trigger]), [data-tooltip-trigger="hover"]',
+    hideTooltip)

-	$(document).on 'mouseout', '[data-tooltip]:not([data-tooltip-trigger]), [data-tooltip-element]:not([data-tooltip-trigger]), [data-tooltip-trigger="hover"]', hideTooltip
-
-	$(document).on 'click', '[data-tooltip-trigger="click"]', toggleTooltip
-	$(document).on 'focus', '[data-tooltip-trigger="focus"]', showTooltip
-	$(document).on 'blur', '[data-tooltip-trigger="focus"]', hideTooltip
-	$(document).on 'tooltips:show', '[data-tooltip-trigger="manual"]', showTooltip
-	$(document).on 'tooltips:hide', '[data-tooltip-trigger="manual"]', hideTooltip
-	$(document).on 'tooltips:toggle', '[data-tooltip-trigger="manual"]', toggleTooltip
+  $(document).on 'click', '[data-tooltip-trigger="click"]', toggleTooltip
+  $(document).on 'focus', '[data-tooltip-trigger="focus"]', showTooltip
+  $(document).on 'blur', '[data-tooltip-trigger="focus"]', hideTooltip
+  $(document).on 'tooltips:show', '[data-tooltip-trigger="manual"]', showTooltip
+  $(document).on 'tooltips:hide', '[data-tooltip-trigger="manual"]', hideTooltip
+  $(document).on 'tooltips:toggle', '[data-tooltip-trigger="manual"]', toggleTooltip


reduce code complexity

reduce code complexity

--- src/game.coffee
+++ src/game.coffee
@@ -162,24 +162,19 @@

   showMines: (deadPosition) ->
-    for i in [0...@data.length]
+    for i in [0...@board.cases.length]
+      [x, y] = @coordFromPosition(i)
       if @data[i] is @entities.Mine
-        [x, y] = @coordFromPosition(i)
         @board.cases[i].g.remove()
         if i is deadPosition
           @board.cases[i] = new ExplodedMine @board.board, x, y
+        else if @board.cases[i].constructor is Flag
+          @board.cases[i] = new FlaggedMine @board.board, x, y
         else
-          if @board.cases[i].constructor is Flag
-            @board.cases[i] = new FlaggedMine @board.board, x, y
-          else
-            @board.cases[i] = new Mine @board.board, x, y
-
-    for i in [0...@board.cases.length]
-      if @board.cases[i].constructor is Flag and @data[i] isnt @entities.Mine
-        [x, y] = @coordFromPosition(i)
+          @board.cases[i] = new Mine @board.board, x, y
+      else if @board.cases[i].constructor is Flag
         @board.cases[i].g.remove()
         @board.cases[i] = new BadFlag @board.board, x, y
-

   gameOver: (deadPosition) =>


implement workspace injection

implement workspace injection

--- lib/ewg/haml/context.coffee
+++ lib/ewg/haml/context.coffee
@@ -18,6 +18,7 @@
       {
         log: log
         globals: new Globals(@config.globals)
+        ws: @config.ws
       }
     )


#147 indent by markdown header level ( gfm grammar specific )

--- lib/provider/symbols.coffee
+++ lib/provider/symbols.coffee
@@ -19,6 +19,21 @@
     @items = null
     @subscribeEditor(newEditor.onDidSave => @items = null)

+  itemForTag: ({position, name}) =>
+    row = position.row
+    {
+      point: @getFirstCharacterPointOfRow(row)
+      text: '  '.repeat(@getLevelForRow(row)) + name
+    }
+
+  getLevelForRow: (row) ->
+    # For gfm source, determine level by counting leading '#' chars( use header level ).
+    if @editor.getGrammar().scopeName is 'source.gfm'
+      lineText = @editor.lineTextForBufferRow(row)
+      (lineText.match(/#+/)?[0]?.length - 1) ? 0
+    else
+      @editor.indentationForBufferRow(row)
+
   getItems: ->
     return @items if @items?
     # We show full line text of symbol's line, so just care for which line have symbol.
@@ -26,7 +41,4 @@
     scopeName = @editor.getGrammar().scopeName
     new TagGenerator(filePath, scopeName).generate().then (tags) =>
       tags = _.uniq(tags, (tag) -> tag.position.row)
-      @items = tags.map ({position, name}) =>
-        point: @getFirstCharacterPointOfRow(position.row)
-        text: '  '.repeat(@editor.indentationForBufferRow(position.row)) + name
-      @items
+      @items = tags.map(@itemForTag.bind(this))


Update alternatives to KERB

Update alternatives to KERB

--- src/kerb.coffee
+++ src/kerb.coffee
@@ -1,11 +1,5 @@
 # Description:
-#   Make hubot list what tasty treats are available at Kerb Kings Cross (eat.st)
-#
-# Dependencies:
-#   None
-#
-# Configuration:
-#   None
+#   A Hubot script to check what's on KERB Kings Cross
 #
 # Commands:
 #   hubot what's on kerb
@@ -16,8 +10,8 @@

 jsdom = require "jsdom"

-days_of_week = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
-kerb_alternatives = ["Pret", "Wasabi", "Benito's Hat", "Burrito Café", "Kiosk"]
+days_of_week = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
+kerb_alternatives = ["Pret", "Wasabi", "Benito's Hat", "Giraffe", "Gran Sasso", "Kiosk", "Pizza Union", "Abokado", "Honest Burger"]

 getDate = (next_week, day_of_week_str) ->
   today = new Date()


Fix sentry issue 1094.

Fix sentry issue 1094.

There are units without coordinates, deal with it.

--- src/map-base-view.coffee
+++ src/map-base-view.coffee
@@ -85,12 +85,24 @@
         onMapClicked: (ev) -> # override

         calculateInitialOptions: ->
+            city = p13n.getCity()
+            unless city?
+                city = 'helsinki'
+            center = DEFAULT_CENTER[city]
+            # Default state without selections
+            defaults =
+                zoom: if (p13n.get('map_background_layer') == 'servicemap') then 10 else 5
+                center: center
             if @selectedPosition.isSet()
                 zoom: map.MapUtils.getZoomlevelToShowAllMarkers()
                 center: map.MapUtils.latLngFromGeojson @selectedPosition.value()
             else if @selectedUnits.isSet()
-                zoom: @getMaxAutoZoom()
-                center: map.MapUtils.latLngFromGeojson @selectedUnits.first()
+                unit = @selectedUnits.first()
+                if unit.get('location')?
+                    zoom: @getMaxAutoZoom()
+                    center: map.MapUtils.latLngFromGeojson(unit)
+                else
+                    return defaults
             else if @divisions.isSet()
                 boundaries = @divisions.map (d) =>
                     new L.GeoJSON d.get('boundary')
@@ -98,13 +110,6 @@
                 bounds = _.reduce boundaries, iteratee, L.latLngBounds([])
                 bounds: bounds
             else
-                city = p13n.getCity()
-                unless city?
-                    city = 'helsinki'
-                center = DEFAULT_CENTER[city]
-                # Default state without selections
-                zoom: if (p13n.get('map_background_layer') == 'servicemap') then 10 else 5
-                center: center

         postInitialize: ->
             @_addMouseoverListeners @allMarkers


clearing subpanels on render

clearing subpanels on render

--- src/mixins/detail.coffee
+++ src/mixins/detail.coffee
@@ -66,6 +66,9 @@
     return @subpanel

   bindAttributes: (attrs=null) ->
+    # clear subpanel
+    @subpanel = undefined
+
     if not attrs
       if @model?.attributes
         attrs = Object.keys @model.attributes


Set bootstrapScript and resourcePath params in URL.

--- src/main.coffee
+++ src/main.coffee
@@ -2,6 +2,8 @@
 delegate = require 'atom_delegate'
 path = require 'path'
 Window = require 'window'
+
+resourcePath = path.dirname(__dirname)

 # All opened windows.
 windows = []
@@ -10,12 +12,24 @@
 app.on 'window-all-closed', ->
   app.quit()

-delegate.browserMainParts.preMainMessageLoopRun = ->
-  win = new Window width: 800, height: 600, show: false
-  win.loadUrl "file://#{__dirname}/../static/index.html"
+openWindowWithParams = (pairs) ->
+  win = new Window width: 800, height: 600, show: false, title: 'Atom'

+  windows.push win
   win.on 'destroyed', ->
     windows.splice windows.indexOf(win), 1

-  windows.push win
+  url = "file://#{resourcePath}/static/index.html"
+  separator = '?'
+  for pair in pairs
+    url += "#{separator}#{pair.name}=#{pair.param}"
+    separator = '&' if separator is '?'
+
+  win.loadUrl url
   win.show()
+
+delegate.browserMainParts.preMainMessageLoopRun = ->
+  openWindowWithParams [
+    {name: 'bootstrapScript', param: 'window-bootstrap'},
+    {name: 'resourcePath', param: resourcePath},
+  ]


Rearrange menus

Rearrange menus

I'm not sure if anything was broken before, but nothing is broken right
now.

--- src/main.coffee
+++ src/main.coffee
@@ -6,6 +6,7 @@
 ipc = require('electron').ipcMain
 # Module to control application menu
 Menu = require('electron').Menu
+MenuItem = require('electron').MenuItem
 # Module that can open URLs
 shell = require('electron').shell
 _ = require 'lodash'
@@ -32,60 +33,51 @@
 buildMenu = (includeDevTools) ->
   # Get some helpers
   parentMenu = (label, role, submenu...) ->
-    {label, role, submenu}
+    realsub = new Menu()
+    realsub.append(x) for x in _.compact submenu
+    new MenuItem {label, role, submenu: realsub}
   miniItem = (label, accelerator, role) ->
-    unless role?
-      role = accelerator
-      accelerator = undefined
-    {label, accelerator, role}
+    new MenuItem {label, accelerator, role}
   fancyItem = (label, accelerator, click) ->
-    unless click?
-      click = accelerator
-      accelerator = undefined
-    {label, accelerator, click}
-  sep = -> {type: 'separator'}
+    new MenuItem {label, accelerator, click}
+  sep = -> new MenuItem {type: 'separator'}

-  template = [
-    parentMenu 'View', undefined,
-      fancyItem 'Reload', 'CmdOrCtrl+R', (item, focusedWindow) ->
-        focusedWindow?.reload()
-    parentMenu 'Window', 'window',
-      miniItem 'Minimize', 'CmdOrCtrl+M', 'minimize'
-      miniItem 'Close', 'CmdOrCtrl+W', 'close'
-    parentMenu 'Help', 'help',
-      fancyItem 'Relief Valve Website', ->
-        shell.openExternal 'http://code.mathphreak.me/ReliefValve'
-  ]
+  menu = new Menu()

-  if includeDevTools
-    devToolsAccelerator = if process.platform == 'darwin'
-      'Alt+Command+I'
-    else
-      'Ctrl+Shift+I'
-    template[0].submenu.push fancyItem(
-      'Toggle Developer Tools',
-      devToolsAccelerator,
-      (item, focusedWindow) ->
-        focusedWindow?.toggleDevTools()
-    )
-
-  if process.platform == 'darwin'
-    template.unshift parentMenu 'Relief Valve', undefined,
-      miniItem 'About Relief Valve', 'about'
+  if process.platform is 'darwin'
+    menu.append parentMenu 'Relief Valve', undefined,
+      miniItem 'About Relief Valve', undefined, 'about'
       sep()
       miniItem 'Hide Relief Valve', 'Command+H', 'hide'
       miniItem 'Hide Others', 'Command+Alt+H', 'hideothers'
-      miniItem 'Show All', 'unhide'
+      miniItem 'Show All', undefined, 'unhide'
       sep()
       fancyItem 'Quit', 'Command+Q', -> app.quit()
-    # Window menu.
-    template[2].submenu.push sep(), miniItem 'Bring All to Front', 'front'
-  else
-    # Help menu
-    template[2].submenu.push fancyItem 'About Relief Valve', ->
-      mainWindow.webContents.send 'menuItem', 'about'

-  menu = Menu.buildFromTemplate(template)
+  menu.append parentMenu 'View', undefined,
+      fancyItem 'Reload', 'CmdOrCtrl+R', (item, focusedWindow) ->
+        focusedWindow?.reload()
+      if includeDevTools
+        fancyItem 'Toggle Developer Tools',
+          if process.platform == 'darwin'
+            'Alt+Command+I'
+          else
+            'Ctrl+Shift+I'
+          , (item, focusedWindow) ->
+            focusedWindow?.toggleDevTools()
+  menu.append parentMenu 'Window', 'window',
+      miniItem 'Minimize', 'CmdOrCtrl+M', 'minimize'
+      miniItem 'Close', 'CmdOrCtrl+W', 'close'
+      if process.platform is 'darwin'
+        sep()
+        miniItem 'Bring All to Front', undefined, 'front'
+  menu.append parentMenu 'Help', 'help',
+      fancyItem 'Relief Valve Website', undefined, ->
+        shell.openExternal 'http://code.mathphreak.me/ReliefValve'
+      if process.platform isnt 'darwin'
+        fancyItem 'About Relief Valve', undefined, ->
+          mainWindow.webContents.send 'menuItem', 'about'
+
   Menu.setApplicationMenu menu

 # This method will be called when Electron has done everything


open new window linking to the issue

open new window linking to the issue

--- src/modules/graph.coffee
+++ src/modules/graph.coffee
@@ -16,7 +16,7 @@
         min = +Infinity ; max = -Infinity

         # Generate the actual closes.
-        rest = _.map collection, ({ closed_at, size, title }) ->
+        rest = _.map collection, ({ closed_at, size, title, html_url }) ->
             min = size if size < min
             max = size if size > max
             {
@@ -24,6 +24,7 @@
                 points: total -= size
                 size
                 title
+                html_url
             }

         # Now add a radius in a range (will be used for a circle).
@@ -149,10 +150,14 @@
         tooltip = null

         # Show when we closed an issue.
-        svg.selectAll("circle")
+        svg.selectAll("a.issue")
         .data(actual[1...]) # skip the starting point
         .enter()
-        .append("circle")
+        # A wrapping link.
+        .append('svg:a')
+        .attr("xlink:href", ({ html_url }) -> html_url )
+        .attr("xlink:show", 'new')
+        .append('svg:circle')
         .attr("cx", ({ date }) -> x date )
         .attr("cy", ({ points }) -> y points )
         .attr("r",  ({ radius }) -> 5 ) # fixed for now


BUG-FIX CoffeScript for loop end

BUG-FIX CoffeScript for loop end

--- src/neck.coffee
+++ src/neck.coffee
@@ -113,6 +113,7 @@
                 _.extend({}, {query: args}, options.params),
                 options.refresh,
                 options.replace
+            undefined
           )(route)
       @_router = new Backbone.Router routes: @routes
       @routes = undefined


Disabled presence_change hounding because it is Extremely Annoying

--- src/scripts/hound.coffee
+++ src/scripts/hound.coffee
@@ -121,10 +121,11 @@
     if not channel.name
       channel = { private: null, name: '' }
     hound user, channel
-  robot.adapter.client.on 'presence_change', (res) ->
-    if res.presence is 'active'
-      user = robot.adapter.client.rtm.dataStore.getUserById res.user
-      hound user, { private: null, name: '' }
+
+  # robot.adapter.client.on 'presence_change', (res) ->
+  #   if res.presence is 'active'
+  #     user = robot.adapter.client.rtm.dataStore.getUserById res.user
+  #     hound user, { private: null, name: '' }

   # Every five minutes, attempt to hound non-salaried users
   autoHoundJob = schedule.scheduleJob '*/5 * * * *', ->


fixed issue

fixed issue

--- src/poll.coffee
+++ src/poll.coffee
@@ -15,9 +15,7 @@
 class Option
 	constructor: () ->
 class Poll
-	options
 	constructor: (@id) ->
-		options = {}

 module.exports = (robot) ->
 	robot.respond /start poll (.*?)\s(option:\s?.*)+/i, (msg) ->


Force svg footprint pattern output to be in mm

--- src/svg-generator.coffee
+++ src/svg-generator.coffee
@@ -7,8 +7,7 @@
 svg_head = """
 <svg xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
-     xmlns:s="https://github.com/nturley/netlistsvg">
-
+     xmlns:s="https://github.com/nturley/netlistsvg"
 """

 svg_tail = """
@@ -315,7 +314,7 @@
     log.start "SVG symbols skin '#{@name}.svg'"
     mkdirp.sync "#{@dir}"
     fd = fs.openSync "#{@dir}/#{@name}.svg", 'w'
-    fs.writeSync fd, svg_head
+    fs.writeSync fd, svg_head + '>\n'
     fs.writeSync fd, netlistsvg_properties
     fs.writeSync fd, netlistsvg_style
     fs.writeSync fd, netlistsvg_builtins
@@ -334,8 +333,6 @@
       log.start "SVG footprint '#{patternName}.svg'"
       mkdirp.sync "#{@dir}/#{@name}"
       fd = fs.openSync "#{@dir}/#{@name}/#{patternName}.svg", 'w'
-      fs.writeSync fd, svg_head
-      fs.writeSync fd, pcbsvg_style
       @_generatePattern fd, pattern
       fs.writeSync fd, svg_tail
       fs.closeSync fd
@@ -407,9 +404,18 @@
     # Bounding box
     [minx, miny, width, height] = @_getBoundingBox(pattern)

+    fs.writeSync fd, """
+        #{svg_head}
+             width="#{width}mm"
+             height="#{height}mm"
+             viewBox="0 0 #{width} #{height}">
+
+    """
+    fs.writeSync fd, pcbsvg_style
+
     # Pattern start
     fs.writeSync fd, """
-    <g transform="translate(10, 10) scale(100, 100) translate(#{width/2}, #{height/2})">
+    <g transform="translate(#{width/2}, #{height/2})">

     """


:lipstick: e -> error

:lipstick: e -> error

--- src/theme-manager.coffee
+++ src/theme-manager.coffee
@@ -243,11 +243,11 @@
         @lessCache.cssForFile(lessStylesheetPath, [baseVarImports, less].join('\n'))
       else
         @lessCache.read(lessStylesheetPath)
-    catch e
+    catch error
       console.error """
         Error compiling less stylesheet: #{lessStylesheetPath}
-        Line number: #{e.line}
-        #{e.message}
+        Line number: #{error.line}
+        #{error.message}
       """

   stringToId: (string) ->


Fix flag

Fix flag

--- src/tools/routine.coffee
+++ src/tools/routine.coffee
@@ -89,7 +89,7 @@
         return

       asyncArgs = [argv0, '', routine.cookie(), start-1].concat asyncArgs
-      proc = sh.Exec "wscript.exe /B //E:JScript#{
+      proc = sh.Exec "wscript.exe //B //E:JScript#{
         (" \"#{arg}\"" for arg in asyncArgs).join('')}"
       exports._?.push ->
         unless proc.Status


fix requestAnimationFrame polyfill

fix requestAnimationFrame polyfill

--- src/utils/Vendors.coffee
+++ src/utils/Vendors.coffee
@@ -8,20 +8,17 @@
 vendors = ['ms', 'moz', 'webkit', 'o']
 x = 0

-loop
-	window.requestAnimationFrame = window["#{vendors[x]}RequestAnimationFrame"]
-	window.cancelAnimationFrame = window["#{vendors[x]}CancelAnimationFrame"] or window["#{vendors[x]}CancelRequestAnimationFrame"]
-	++x
-	break if x >= vendors.length or window.requestAnimationFrame is not undefined
-
+for vendor in vendors
+	break if window.requestAnimationFrame is not undefined
+	window.requestAnimationFrame = window["#{vendor}RequestAnimationFrame"]
+	window.cancelAnimationFrame = window["#{vendor}CancelAnimationFrame"] or window["#{vendor}CancelRequestAnimationFrame"]

 if window.requestAnimationFrame is undefined
 	window.requestAnimationFrame = (callback, element) ->
 		currTime = new Date().getTime()
 		timeToCall = Math.max 0, 16 - (currTime - lastTime)
-		id = window.setTimeout (-> callback currTime + timeToCall) timeToCall
 		lastTime = currTime + timeToCall
-		return id
+		window.setTimeout (-> callback currTime + timeToCall), timeToCall

 if window.cancelAnimationFrame is undefined
 	window.cancelAnimationFrame = (id) ->


Fix reference to deleted controller

Fix reference to deleted controller

--- app/application.coffee
+++ app/application.coffee
@@ -1,7 +1,6 @@
 Chaplin = require 'chaplin'
 mediator = require 'mediator'
 routes = require 'routes'
-SessionController = require 'controllers/session_controller'
 HeaderController = require 'controllers/header_controller'
 Layout = require 'views/layout'

@@ -49,7 +48,6 @@
     # and views which are needed the whole time, for example header, footer
     # or navigation views.
     # e.g. new NavigationController()
-    new SessionController()
     new HeaderController()

   # Create additional mediator properties


Bump version.

Bump version.

--- src/swag.coffee
+++ src/swag.coffee
@@ -1,5 +1,5 @@
 ###
-    Swag v0.0.3 <http://elving.github.com/swag/>
+    Swag v0.1.0 <http://elving.github.com/swag/>
     Copyright 2012 Elving Rodriguez <http://elving.me/>
     Available under MIT license <https://raw.github.com/elving/swag/master/LICENSE>
 ###


spelling!

spelling!

--- src/task.coffee
+++ src/task.coffee
@@ -16,14 +16,13 @@

 Method.define define, isString, isString, isFunction,
   (name, dependencies, action) ->
-    define name, (dependencies.split /\s/), action
+    define name, (dependencies.split /\s+/), action

 Method.define define, isString, isDefined,
-  (name, dependences) -> define name, dependences, ->
+  (name, dependencies) -> define name, dependencies, ->

 Method.define define, isString, isFunction,
   (name, action) -> define name, [], action
-

 run = (name = "default", visited = []) ->


fix callback call in fetchEditability

fix callback call in fetchEditability

The error parameter was missing since commit f738144ca9e36fc003dd5215a94505f8ab9518a0

--- client/app/models/event.coffee
+++ client/app/models/event.coffee
@@ -120,7 +120,7 @@
                     isEditable = @get('shareID') == sharing.get('id')
                     callback null, isEditable
         else
-            callback true
+            callback null, true

     fetchSharing: (callback) ->


Don't update view enabled class on show/hide

--- src/view.coffee
+++ src/view.coffee
@@ -31,6 +31,7 @@
 			@el = el

 		@customOutlets = {} if not @customOutlets?
+
 		# Add additional default custom outlets.
 		#if @el.attr('value') != null then @customOutlets.value =
 		#	get: (el) ->
@@ -213,17 +214,17 @@
 	removeClass: (classes) ->
 		@el.removeClass(classes)

-	enable: (recursive = true)->
+	enable: (recursive = true, updateClass = true)->
 		@enabled = true
-		@removeClass 'disabled'
+		@removeClass('disabled') if updateClass
 		if recursive is true
 			for viewName, view of @views
 				view.enable()
 		@

-	disable: (recursive = true) ->
+	disable: (recursive = true, updateClass = true) ->
 		@enabled = false
-		@addClass 'disabled'
+		@addClass('disabled') if updateClass
 		if recursive is true
 			for viewName, view of @views
 				view.disable()
@@ -231,12 +232,12 @@

 	show: ->
 		@hidden = false
-		@enable()
+		@enable(true, false)
 		@removeClass('hidden')

 	hide: ->
 		@hidden = true
-		@disable()
+		@disable(true, false)
 		@addClass('hidden')

 	hideAction: -> @hide()


no need to strip the shebang

no need to strip the shebang

--- src/wrap.coffee
+++ src/wrap.coffee
@@ -120,7 +120,7 @@
         return this

     readFile: (file) ->
-        body = fs.readFileSync(file, 'utf-8').replace(/^#![^\n]*\n/, "")
+        body = fs.readFileSync(file, 'utf-8')
         for fn in @filters
             body = fn.call(this, body, file)
         return body


some html for rss

some html for rss

--- apps/rss/routes.coffee
+++ apps/rss/routes.coffee
@@ -14,5 +14,5 @@
       limit: PAGE_SIZE
     error: res.backboneError
     success: (articles) ->
-      res.set('Content-Type', 'text/xml')
+      res.set('Content-Type', 'application/rss+xml')
       res.render('news', { articles: articles })


Add the Config.list() method, fix Config.set()

--- system/Config.coffee
+++ system/Config.coffee
@@ -25,10 +25,16 @@
       @fs.close handle
       return value

+    list: -> @fs.getDir(@dir)
+
     set: (key, value) ->
-      handle = @fs.open @dir + "/" + key
-      @fs.write value
-      @fs.close handle
-      return value
+      if fs.exists
+        @fs.createFile @dir, key, value
+        return true
+      else
+        handle = @fs.open @dir + "/" + key
+        @fs.write value
+        @fs.close handle
+        return true

   return Config


Shell: module description is now `base shell`

--- coffee/src/shells/shell.coffee
+++ coffee/src/shells/shell.coffee
@@ -21,7 +21,7 @@
 Shell.controls = []

 # Description of the shell
-description = ''
+description = 'base shell'

 class Shell.Model extends Backbone.Model


Shell.Model: use data directly (clone for safety)

--- coffee/src/shells/shell.coffee
+++ coffee/src/shells/shell.coffee
@@ -44,7 +44,7 @@
     unless shellClass?
       UndefinedShellError data.shell

-    new shellClass.Model data: data
+    new shellClass.Model _.clone data


Add missing options to Meteor default optionss

--- src/Meteor.coffee
+++ src/Meteor.coffee
@@ -24,6 +24,8 @@
       "root-url"    : process.env.ROOT_URL || null
       "mongo-url"   : process.env.MONGO_URL || null
       "settings"    : null
+      "production"  : false
+      "production"  : false
       "production"  : false
       "once"        : false
     }


Remove unused type -> source map

Remove unused type -> source map

--- server/lib/presenters/indicator.coffee
+++ server/lib/presenters/indicator.coffee
@@ -2,14 +2,6 @@
 moment = require('moment')

 HeadlineService = require('../services/headline')
-
-TYPE_SOURCE_MAP =
-  esri:
-    name: 'Environment Agency - Abu Dhabi'
-    url: 'http://www.ead.ae'
-  worldBank:
-    name: 'World Bank Database'
-    url: 'http://data.worldbank.org'

 DATE_FORMAT = 'D MMM YYYY'


fix(vm.create): VIFs param is optional (#499)

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -224,6 +224,7 @@

   # Virtual interfaces to create for the new VM.
   VIFs: {
+    optional: true
     type: 'array'
     items: {
       type: 'object'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -123,9 +123,9 @@

   # The order of theses includes is important for
   # the way in wich they modify the camera view transform
-
+
   for moduleName in Camera.defaultModules
-    self.include "Camera.#"
+    self.include "Camera.#{moduleName}"
   self.include(Camera.Zoom)
   self.include(Camera.Rotate)
   self.include(Camera.Shake)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -136,4 +136,6 @@

 Camera.defaultModules = [
   "ZSort"
+  "Zoom"
+
 ]


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -41,7 +41,7 @@
     )

     I.scroll.x = I.scroll.x.clamp(I.cameraBounds.left, I.cameraBounds.right - I.screen.width)
-    I.scroll
+    I.scroll.y = I.scr

   followTypes =
     centered: (object) ->


added new resources from April 25 2016

added new resources from April 25 2016

--- src/coffin.coffee
+++ src/coffin.coffee
@@ -73,6 +73,7 @@
         DHCPOptions: null
         EIP: null
         EIPAssociation: null
+        Host: null
         Instance: null
         InternetGateway: null
         NatGateway: null


set the timeout of cli test to 30 seconds

--- test/cli.coffee
+++ test/cli.coffee
@@ -17,6 +17,8 @@

 describe 'Cli#Init', ->

+  @timeout 30000
+
   before clean

   it 'should check the target directory and throw error when target is not empty', ->


reference env.TOKENURL and OAUTH2_SCOPE

reference env.TOKENURL and OAUTH2_SCOPE

--- test/env.coffee
+++ test/env.coffee
@@ -1,4 +1,3 @@
-agent = require 'https-proxy-agent'
 domain = process.env.DOMAIN || 'mob.myvnc.com'

 module.exports =
@@ -13,8 +12,8 @@
 	group: { name: 'group1' }
 	getTokens: ->
 		new Promise (fulfill, reject) ->
-			url = 'https://mob.myvnc.com/org/oauth2/token/'
-			scope = [ "https://mob.myvnc.com/org/users", "https://mob.myvnc.com/mobile"]
+			url = process.env.TOKENURL
+			scope = process.env.OAUTH2_SCOPE?.split(' ') || [ 'User', 'Mobile' ]
 			Promise
 				.all [
 					sails.services.oauth2.token url, module.exports.client, module.exports.users[0], scope


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animated.coffee
+++ test/animated.coffee
@@ -496,7 +496,9 @@

   animation.update()

-  equal animation.I.currentFrameIndex, 0
+  # hack for testing: events fire, then the currentFrameIndex
+  # is updated, so I'm testing against the correct event index + 1
+  equal animation.I.currentFrameIndex, 0 + 1
   ok whiteParticlesFired, "White particle effect fired"

   animation.update()
@@ -504,11 +506,14 @@
   animation.update()
   animation.update()

+
+  equal animation.I.currentFrameIndex, 4 + 1
   ok blueParticlesFired, "Blue particle effect fired"
   ok greenParticlesFired, "Green particle effect fired"

   animation.update()

+  equal animation.I.currentFrameIndex, 5 + 1
   ok chompSoundFired, "Chomp sound effect fired"

 test "should set hflip and vflip values", ->


Stubbed out tests

Stubbed out tests

--- test/app_spec.coffee
+++ test/app_spec.coffee
@@ -5,7 +5,20 @@
 expect = chai.expect

-describe 'TestRunner', ->
+describe 'Easel Backbone View', ->
+
+   it 'Should accept a c.Stage reference on instantiation', ->
+
+   it 'Should create a base c.Container instance', ->
+
+   it 'Should add the container to the main stage on render', ->
+
+   it 'Should remove the container from the main stage on remove', ->
+
+   it 'Should add all passed in children to the container', ->
+
+   it 'Should bind all custom DisplayObject events', ->
+
+   it 'Should unbind all DisplayObject events on remove', ->

-  it 'Should test something', ->


Upgrade to node v0.10.12.

Upgrade to node v0.10.12.

--- src/config.coffee
+++ src/config.coffee
@@ -14,7 +14,7 @@
     process.env.ATOM_PACKAGES_URL ? 'http://atom.iriscouch.com/registry/_design/apm/_view/atom_packages'

   getNodeVersion: ->
-    process.env.ATOM_NODE_VERSION ? '0.10.9'
+    process.env.ATOM_NODE_VERSION ? '0.10.12'

   getUserConfigPath: ->
     path.resolve(__dirname, '..', '.apmrc')


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -102,6 +102,6 @@

   player.update()

-
+  equals pl

 module()


Add cordova detection

Add cordova detection

--- src/device.coffee
+++ src/device.coffee
@@ -70,9 +70,12 @@

 device.fxosTablet = ->
   device.fxos() and _find 'tablet'
-
+
 device.meego = ->
   _find 'meego'
+
+device.cordova = ->
+  window.cordova && location.protocol == 'file:'

 device.mobile = ->
   device.androidPhone() or device.iphone() or device.ipod() or device.windowsPhone() or device.blackberryPhone() or device.fxosPhone() or device.meego()
@@ -155,9 +158,12 @@

 else if device.meego()
   _addClass "meego mobile"
-
+
 else
   _addClass "desktop"
+
+if device.cordova()
+  _addClass "cordova"

 # Orientation Handling


version bump to 0.0.2

version bump to 0.0.2

--- src/emblem.coffee
+++ src/emblem.coffee
@@ -2,7 +2,7 @@
 this.Emblem = {}
 Emblem = this.Emblem

-Emblem.VERSION = "0.0.1"
+Emblem.VERSION = "0.0.2"

 module.exports = Emblem


just match serif or monospace, not whole font

--- src/format.coffee
+++ src/format.coffee
@@ -190,7 +190,7 @@
       'monospace' : "'Courier New', monospace"
     }, (cssValue) =>
       for key,value of @styles
-        return key if value.indexOf(cssValue) >= 0
+        return key if value.indexOf(key) > -1
       return false
     )


Add help info about the `open` command

Add help info about the `open` command

--- src/github.coffee
+++ src/github.coffee
@@ -10,12 +10,12 @@
 #   HUBOT_GITHUB_REPOS_MAP (format: "{\"web\":\"frontend\",\"android\":\"android\",\"ios\":\"ios\",\"platform\":\"web\"}"
 #
 # Commands:
+#   hubot github open - Shows a list of open pull requests for the repo of this room
 #   hubot github notification hh:mm - I'll remind about open pull requests in this room at hh:mm every weekday.
 #   hubot github list notifications - See all pull request notifications for this room.
 #   hubot github notifications in every room - Be nosey and see when other rooms have their notifications set
 #   hubot github delete hh:mm notification - If you have a notification at hh:mm, I'll delete it.
 #   hubot github delete all notifications - Deletes all notifications for this room.
-#   hubot github open - Shows a list of open pull requests for the repo of this room
 #
 # Author:
 #   ndaversa
@@ -162,6 +162,7 @@
       I can remind you about open pull requests for the repo that belongs to this channel
       Use me to create a notification, and then I'll post in this room every weekday at the time you specify. Here's how:

+      #{robot.name} github open - Shows a list of open pull requests for the repo of this room
       #{robot.name} github notification hh:mm - I'll remind about open pull requests in this room at hh:mm every weekday.
       #{robot.name} github list notifications - See all pull request notifications for this room.
       #{robot.name} github notifications in every room - Be nosey and see when other rooms have their notifications set


modified

modified

--- src/jisilu.coffee
+++ src/jisilu.coffee
@@ -33,11 +33,24 @@
       json: true

     request options, (err,res, body)->
-      callback err, body # unless err?
+      callback(err, body) # unless err?
       #jj = (each for each in body.rows when each.id is "150152")
       #console.log jj[0].cell

+  getSymbols: (category, callback)->
+    @get category, (err, body)->
+      if err?
+        callback err,null
+        return
+
+      cell = switch category
+        when 'fundm' then "base_fund_id"
+        else "#{category}_id"
+      callback null, (each.cell[cell] for each in body.rows)
+
+
 module.exports = JisiluData
 ###
-new JisiluData().get('funda')
+(new JisiluData()).getSymbols 'fundb', (symbols)->
+  console.log symbols
 ###


little beautification

little beautification

--- src/js/app.coffee
+++ src/js/app.coffee
@@ -67,15 +67,11 @@
       requiresPacificTimezoneCorrection(userTimezone)
     ) for showID in showIDList
   )
-
   MyTimeline.updateSubscriptions topics

-subscribeToShowsWhenDataAvailable = (
-  @showIDList=@showIDList,
-  @userTimezone=@userTimezone) ->
+subscribeToShowsWhenDataAvailable = (@showIDList=@showIDList, @userTimezone=@userTimezone) ->
   if @showIDList and @userTimezone
     subscribeToShows(@showIDList, @userTimezone)
-

 setupEvents = (toWatchMenu, upcomingMenu, popularMenu, myShowsMenu, signInWindow) ->
   Trakttv.on 'authorizationRequired', (event) ->
@@ -134,7 +130,7 @@
         cb(err, userSettings)
     ]
     (err, result) =>
-      log.error("fetchData error: #{err.message}") if err
+      log.error("fetchData error: #{err}, #{err.message}") if err
       callback err, null
   )


all whats needed to create a tag from design mask

--- src/linker.coffee
+++ src/linker.coffee
@@ -44,16 +44,9 @@
 new_tag = (parent, el, callback) ->
     attrs = deep_merge el.attrs # copy data
     parent.tag el.name, attrs, ->
-        for child in el.children.slice() ? []
-            if typeof child is 'string' or typeof child is 'number'
-                @text "#{child}", append:on
-            else
-                new_tag this, child, ->
-                    callback?()
-                    callback = null
+        @once 'end', ->
+            callback?()
         @end()
-        # call back some delayed work
-        callback?()

 ##
 # apply possible additions from the data structure on the tag


Add helper methods linkBindingGyp() and its counterpart

--- test/node_gyp.coffee
+++ test/node_gyp.coffee
@@ -1,5 +1,6 @@
 should = require('chai').should()
 proxyquire = require 'proxyquire'
+fs = require 'fs'

 gruntError = null

@@ -24,6 +25,14 @@
 	grunt.tasks 'gyp:' + task, gruntOptions, ->
 		callback(gruntError)
 		gruntError = null
+
+linkBindingGyp = ->
+	if !fs.existsSync __dirname + '/support/binding.gyp'
+		fs.symlinkSync __dirname + '/support/binding.gyp.original', __dirname + '/support/binding.gyp'
+
+unlinkBindingGyp = ->
+	if fs.existsSync __dirname + '/support/binding.gyp'
+		fs.unlinkSync __dirname + '/support/binding.gyp'

 describe 'grunt-node-gyp', ->
 	describe 'configure', ->


new version of the process function. now permits the use of process.nextTick without corrupting the flow

--- tools/objects.coffee
+++ tools/objects.coffee
@@ -22,28 +22,36 @@
     ##
     process: (obj, {each, done})->
         done ?= (err)-> console.error(err) if err
-
-        return done() if !obj
-
-        waiting = 0
-        next = (err)->
-            if --waiting <= 0 || err
-                return done(err)
-
+
+        _array = false
+
+        _iter = []
+
+        ##
+        next = (err)->
+            done(err) if err
+
+            return done() if !_iter.length
+
+            if _array
+                each _iter.shift(), next
+
+            else
+                each (key=_iter.shift()), obj[key], next
+
+
+        ##
         if floyd.tools.objects.isArray obj
-            return done() if !obj.length
-
-            waiting = obj.length
-
-            for item in obj
-                each item, next
-
-        else
-            return done() if !( waiting = floyd.tools.objects.keys(obj).length )
-
-            for key, item of obj
-                each key, item, next
-
+            _array = true
+
+            _iter.push item for item in obj
+
+        else
+            _iter.push key for key, val of obj
+
+        ##
+        next()
+

     ##


test bind/fix against inheritance via protostate and superstate

--- test/methods.test.coffee
+++ test/methods.test.coffee
@@ -1,4 +1,4 @@
-{ env, State, RootState } = state = require '../state'
+{ env, bind, fix, State, RootState } = state = require '../state'
 { expect } = require 'chai'

@@ -67,6 +67,45 @@
       expect( f ).to.equal o.f

+  describe "Context: state-binding and state-fixing", ->
+
+    methods =
+      normal: -> this
+      bound: bind -> this
+      fixed: fix ( autostate, protostate ) -> -> this
+      both: fix ( autostate, protostate ) -> bind -> this
+
+    test = (o) ->
+      it "works for normal functions", ->
+        expect( o.normal() ).to.equal o
+      it "works for bound functions", ->
+        expect( o.bound() ).to.equal o.state 'A'
+      it "works for fixed functions", ->
+        expect( o.fixed() ).to.equal o
+      it "works for functions that are both bound and fixed", ->
+        expect( o.both() ).to.equal o.state 'A'
+
+    describe "from the autostate", ->
+      state o = {}, A: state 'initial', methods
+      test o
+
+    describe "from a substate", ->
+      state o = {}, A: state { methods, AA: state 'initial' }
+      test o, yes
+
+    describe "from an epistate", ->
+      test new class
+        state @::, A: state 'initial', methods
+
+    describe "from an episubstate", ->
+      test new class
+        state @::, A: state { methods, AA: state 'initial' }
+
+
+
+
+
+
   # This will fail; `unless this is root` in `State::addMethod` prevents
   # expando `original`
   0 and


Updated tag autocomplete to make use of angular scope bi-directional connection.

--- src/directives/tag_autocomplete.coffee
+++ src/directives/tag_autocomplete.coffee
@@ -21,19 +21,19 @@
   "keys",
   ($parse, $http, key) ->
     restrict:    "E"
-    scope:       {}
+    scope:
+      autocompleteUrl: "=macTagAutocompleteUrl"
+
     templateUrl: "template/tag_autocomplete.html"
     replace:     true

     compile: (element, attr) ->
-      urlExp      = attr.macTagAutocompleteUrl
       valueKey    = attr.macTagAutocompleteValue      or "id"
       labelKey    = attr.macTagAutocompleteLabel      or "name"
       selectedExp = attr.macTagAutocompleteSelected
       queryKey    = attr.macTagAutocompleteQuery      or "q"
       delay       = attr.macTagAutocompleteDelay      or 800

-      getUrl      = $parse urlExp
       getSelected = $parse selectedExp

       textInput = $(".text-input", element)
@@ -44,10 +44,6 @@

       ($scope, element, attrs) ->
         # Getting autocomplete url from parent scope
-        Object.defineProperty $scope, "autocompleteUrl",
-          get:       -> getUrl $scope.$parent
-          set: (url) -> getUrl.assign $scope.$parent, url
-
         Object.defineProperty $scope, "tags",
           get:         -> getSelected $scope.$parent
           set: (_tags) ->


Radio: Fixed extends jsDoc.

Radio: Fixed extends jsDoc.

--- src/lib/components/inputs/Radio.coffee
+++ src/lib/components/inputs/Radio.coffee
@@ -12,7 +12,7 @@
     @constructor
     @param   {Object=} options Class options.
     @param   {*=} data Class data
-    @extends {spark.core.spark.components.Checkbox}
+    @extends {spark.components.Checkbox}
   ###
   constructor: (options = {}, data) ->


working implementation of drag and drop across multiple panels

--- src/packages/tabs/src/tabs-view.coffee
+++ src/packages/tabs/src/tabs-view.coffee
@@ -45,15 +45,39 @@
   removeTabAtIndex: (index) ->
     @find(".tab:eq(#{index})").remove()

+  onDragStart: (event) =>
+    super
+    pane = $(event.target).closest('.pane')
+    event.originalEvent.dataTransfer.setData 'from-pane-index', pane.index()
+
   onDrop: (event) =>
     super
-    sessions = @editor.editSessions
-    el = @sortableElement(event)
-    previousIndex = event.originalEvent.dataTransfer.getData('index')
-    currentIndex  = el.index() - 1
+    transfer = event.originalEvent.dataTransfer
+    previousDraggedTabIndex = transfer.getData 'sortable-index'

-    sessions.splice(currentIndex, 0, sessions.splice(previousIndex, 1)[0])
+    fromPaneIndex = ~~transfer.getData 'from-pane-index'
+    toPaneIndex   = ~~$(event.target).closest('.pane').index()
+    fromPane      = rootView.find ".pane:nth-child(#{fromPaneIndex + 1})"
+    fromEditor    = fromPane.find('.editor').view()

-    @setActiveTab(currentIndex)
-    @editor.setActiveEditSessionIndex(currentIndex)
-    @editor.focus()
+    if fromPaneIndex == toPaneIndex
+      toPane   = fromPane
+      toEditor = fromEditor
+    else
+      toPane = rootView.find ".pane:nth-child(#{toPaneIndex + 1})"
+      toEditor = toPane.find('.editor').view()
+
+    droppedNearTab = @getSortableElement(event)
+    draggedTab     = fromPane.find(".#{Tabs.viewClass()} .sortable:eq(#{previousDraggedTabIndex})")
+
+    draggedTab.remove()
+    draggedTab.insertBefore(droppedNearTab)
+
+    currentDraggedTabIndex = draggedTab.index()
+
+    toEditor.editSessions.splice(currentDraggedTabIndex, 0, fromEditor.editSessions.splice(previousDraggedTabIndex, 1)[0])
+
+    @setActiveTab(currentDraggedTabIndex)
+    fromEditor.setActiveEditSessionIndex(0)
+    toEditor.setActiveEditSessionIndex(currentDraggedTabIndex)
+    toEditor.focus()


fix https://github.com/sagemathinc/smc/issues/1932 -- jupyter2: problem with too much output

--- src/smc-project/jupyter/jupyter.coffee
+++ src/smc-project/jupyter/jupyter.coffee
@@ -166,7 +166,7 @@
             err = "#{err}"
             for cb in @_spawn_cbs
                 cb?(err)
-        opts = {detached: true}
+        opts = {detached: true, stdio:'ignore'}
         if @_directory != ''
             opts.cwd = @_directory
         require('spawnteract').launch(@name, opts).then(success, fail)


Deeply assert output as list of prices can return in a random order

--- src/spec/integration/impex.spec.coffee
+++ src/spec/integration/impex.spec.coffee
@@ -62,10 +62,29 @@
         console.log "export", result
         expect(result).toBe 'Export done.'
         fs.readFileAsync file, {encoding: 'utf8'}
-      .then (content) ->
+      .then (content) =>
         console.log "export file content", content
+        # special check for p1 (because of list of prices)
+        p1Elements = p1.split(',')
+        expect(p1Elements[0]).toBe @productType.name
+        expect(p1Elements[1]).toBe 'myProduct1'
+        expect(p1Elements[2]).toBe 'my-slug1'
+        expect(p1Elements[3]).toBe '1'
+        expect(p1Elements[4]).toBe 'sku1'
+        # dirty check since prices can return in a different order
+        expect(_.difference(p1Elements[5].split(';'), ['FR-EUR 999', 'CHF 1099'])).toEqual []
+        expect(p1Elements[6]).toBe 'some Text'
+        expect(p1Elements[7]).toEqual 'foo\n'
+        expect(p1Elements[8]).toBe ''
+        expect(p1Elements[9]).toBe ''
+        expect(p1Elements[10]).toBe '2'
+        expect(p1Elements[11]).toBe 'sku2'
+        expect(p1Elements[12]).toBe 'EUR 799'
+        expect(p1Elements[13]).toBe 'some other Text'
+        expect(p1Elements[14]).toBe 'foo'
+        expect(p1Elements[15]).toBe '"t1;t2;t3;Üß""Let\'s see if we support multi\nline value"""'
+
         expect(content).toMatch header
-        expect(content).toMatch p1
         expect(content).toMatch p2
         done()
     .catch (err) -> done _.prettify(err)


Typo in event_binding.coffee

Typo in event_binding.coffee

--- src/view/bindings/event_binding.coffee
+++ src/view/bindings/event_binding.coffee
@@ -1,7 +1,7 @@
 #= require ./abstract_attribute_binding

 class Batman.DOM.EventBinding extends Batman.DOM.AbstractAttributeBinding
-  onlyObserve: onlyObserve: Batman.BindingDefinitionOnlyObserve.None
+  onlyObserve: Batman.BindingDefinitionOnlyObserve.None

   constructor: ->
     super


:bug: Don't get too fancy with the regex

--- src/markov.coffee
+++ src/markov.coffee
@@ -92,7 +92,7 @@

     # Chance to randomly respond un-prompted
     if pct > 0 and Math.random() < pct
-      words = msg.message.text.match /(?=\s*)\w+(?=\s*)/g
+      words = msg.message.text.match /\w+/g
       randword = Math.floor(Math.random() * words.length)
       seed = words[randword]
       model.generate seed[0] or '', max, (text) =>


Defautl to POSTing to Metaphysics

Defautl to POSTing to Metaphysics

--- desktop/lib/metaphysics.coffee
+++ desktop/lib/metaphysics.coffee
@@ -5,7 +5,7 @@
 { METAPHYSICS_ENDPOINT, API_REQUEST_TIMEOUT } = require('sharify').data

 metaphysics = ({ method, query, variables, req } = {}) ->
-  method ?= 'get'
+  method ?= 'post'

   Q.promise (resolve, reject) ->
     r = request[method] METAPHYSICS_ENDPOINT


Remove debug logging statements.

Remove debug logging statements.

--- src/module.coffee
+++ src/module.coffee
@@ -59,10 +59,8 @@
       throw err if err?

       if @mtime? and @mtime <= stat.mtime
-        console.log 'not compiling'
         return callback()

-      console.log 'compiling', @absolutePath
       @mtime = stat.mtime
       extension = (path.extname @absolutePath).substr 1

@@ -234,7 +232,7 @@
         for node in mod.wrapped().body
           toplevel.body.push node
       else
-        console.log 'warning: ast missing', mod.requireAs
+        console.error 'warning: ast missing', mod.requireAs

     for node in @wrapped().body
       toplevel.body.push node


add showdown

add showdown

--- src/player.coffee
+++ src/player.coffee
@@ -10,3 +10,5 @@
     bet = gameState.current_buy_in
     bet = minBet unless bet > minBet
     next null, bet
+  showdown: (gameState, next) ->
+    next()


all in okay on 1

all in okay on 1

--- src/player.coffee
+++ src/player.coffee
@@ -41,7 +41,8 @@
         800
       else
         300
-      bet = maxBet unless bet < maxBet
+      if value < 1
+        bet = maxBet unless bet < maxBet
       bet = minBet unless bet > minBet
       return sendBet maxBet


missing require

missing require

--- src/player.coffee
+++ src/player.coffee
@@ -1,3 +1,5 @@
+_ = require 'lodash'
+
 pkg = require '../package.json'

 decodeRank = require './decodeRank'


Remove testing leftovers.

Remove testing leftovers.

--- src/plugin.coffee
+++ src/plugin.coffee
@@ -8,11 +8,11 @@
     constructor: (@_filepath, @_text, @data) ->

     getFilename: ->
-      (@data && @data["filename"]) ? @_filepath.relative
+      @_filepath.relative

     getView: ->
       (env, locals, contents, templates, callback) ->
-        callback null, new Buffer((@data && @data["template"]) ? @_text)
+        callback null, new Buffer(@_text)

     SandboxPlugin.fromFile = (filepath, callback) ->
       fs.readFile filepath.full, (error, buffer) ->


fix reference

fix reference

--- src/plugin.coffee
+++ src/plugin.coffee
@@ -89,7 +89,7 @@
     options ?= {}
     _.assign options, {
       allowedStartRules: [startRule]
-      plugins: [overrideAction]
+      plugins: [exports]
       overrideActionPlugin: {
         initializer
         rules


Add update functions on both Rivets.View and Rivets.Binding used for updating bindings with a new set of models. [Closes #131]

--- src/rivets.coffee
+++ src/rivets.coffee
@@ -122,6 +122,13 @@
           keypath = dependency.join '.'

         @view.config.adapter.unsubscribe model, keypath, @sync
+
+  # Updates the binding's model from what is currently set on the view. Unbinds
+  # the old model first and then re-binds with the new model.
+  update: =>
+    @unbind()
+    @model = @view.models[@key]
+    @bind()

 # A collection of bindings built from a set of parent elements.
 class Rivets.View
@@ -222,6 +229,12 @@
   publish: =>
     binding.publish() for binding in @select (b) -> b.binder.publishes

+  # Updates the view's models along with any affected bindings.
+  update: (models = {}) =>
+    for key, model of models
+      @models[key] = model
+      binding.update() for binding in @select (b) -> b.key is key
+
 # Cross-browser event binding.
 bindEvent = (el, event, handler, context) ->
   fn = (e) -> handler.call context, e


[fix] styleノードの中身も書き換えてしまうバグを修正

[fix] styleノードの中身も書き換えてしまうバグを修正

refs #2
これで対象ページのレイアウトを崩さずにテキスト置換できるようになった

--- src/w-cart.coffee
+++ src/w-cart.coffee
@@ -53,8 +53,13 @@
 ###
 replaceAllChars = ->
   replaceTextNode = (node)->
-    if node.nodeType is Node.TEXT_NODE
+    nodeType = node.nodeType
+    nodeName = node.nodeName.toLowerCase()
+
+    if nodeType is Node.TEXT_NODE
       node.nodeValue = node.nodeValue.replace /\S/g, '〼'
+      return null
+    else if nodeName is 'script' or nodeName is 'style'
       return null
     else
       for child in node.childNodes


Remove whitespace lines

Remove whitespace lines

--- src/xml2js.coffee
+++ src/xml2js.coffee
@@ -40,7 +40,7 @@
       trim: false,
       normalize: false
     }
-
+
     # emit one error event if the sax parser fails. this is mostly a hack, but
     # the sax parser isn't state of the art either.
     err = false
@@ -48,7 +48,7 @@
       if ! err
         err = true
         @emit "error", error
-
+
     # always use the '#' key, even if there are no subkeys
     # setting this property by and is deprecated, yet still supported.
     # better pass it as explicitCharkey option to the constructor
@@ -74,7 +74,7 @@
       # need a place to store the node name
       obj["#name"] = node.name
       stack.push obj
-
+
     @saxParser.onclosetag = =>
       obj = stack.pop()
       nodeName = obj["#name"]


Add more tests to test suite

Add more tests to test suite

--- _includes/test.coffee
+++ _includes/test.coffee
@@ -8,3 +8,32 @@
   assert.equal(user_repo('https://github.com/wd15/pymks/tree/master/doc'),
                          'wd15/pymks')
 )
+
+it('test to_date', ->
+  assert.equal(to_date('Tue Jan 31 21:01:55 EST 2017'),
+               'Jan 31, 2017')
+)
+
+it('test get_software', ->
+  assert.equal(get_software('moose',
+                            [{name: 'MOOSE', value: 0},
+                             {name: 'fipy', value: 1}]).value,
+               0)
+)
+
+it('test get_data', ->
+  assert.equal(get_software('name1',
+                            [{name: 'name0', value: 0},
+                             {name: 'name1', value: 1}]).value,
+               1)
+)
+
+it('test memory_usage', ->
+  assert.equal(
+    memory_usage(
+      {data: [{name: 'memory_usage', values: [{value: '1000', unit: 'MB'}]},
+              {name: 'other', value: 1}]}
+    ),
+   '1000.0 MB')
+
+)


Properly parses nested objects in arrays

Fixes https://github.com/groupon/cson-safe/issues/5

--- test/parse.coffee
+++ test/parse.coffee
@@ -127,6 +127,26 @@
       { a: { b: { c: false }, d: 44, 3: 't' }, e: 'str' }
     )

+  it 'parses nested objects in arrays', ->
+    compilesTo(
+      """
+      o:
+        [
+                  a: 'x'
+                  b: 'y'
+                  c:
+                      d: 'z'
+            ,
+                  a: 'x'
+                  b: 'y'
+        ]
+      """
+      o: [
+        { a: 'x', b: 'y', c: { d: 'z' } }
+        { a: 'x', b: 'y' }
+      ]
+    )
+
   describe 'reviver functions', ->
     calls = expected = source = reviver = null
     beforeEach ->


Don't assume we have no plugins by default

--- test/tests.coffee
+++ test/tests.coffee
@@ -21,8 +21,10 @@

   describe 'use', ->
     it 'adds a plugin', ->
-      assert.equal request.use({}).plugins.length, 1
+      startCount = request.plugins.length
+      assert.equal request.use({}).plugins.length, startCount + 1

     it "doesn't mutate the request function", ->
+      startCount = request.plugins.length
       request.use {}
-      assert.equal request.plugins.length, 0
+      assert.equal request.plugins.length, startCount


LoginRejected test.

LoginRejected test.

--- test/tests.coffee
+++ test/tests.coffee
@@ -188,6 +188,17 @@
           socket1 = ioClient.connect url1, makeParams()
           socket1.on 'error', (e) ->
             expect(e).deep.equal(reason)
+            done()
+
+        it 'should reject login if onConnect hook passes error', (done) ->
+          err = { someField : 'some reason' }
+          onConnect = (server, socket, cb) ->
+            cb err
+          chatServer = new ChatService { port : port }
+            , { onConnect : onConnect }
+          socket1 = ioClient.connect url1, makeParams(user1)
+          socket1.on 'loginRejected', (e) ->
+            expect(e).deep.equal(err)
             done()

         it 'should support multiple sockets per user', (done) ->


Only parse package.json when it is a file

Closes #3784

--- build/Gruntfile.coffee
+++ build/Gruntfile.coffee
@@ -120,7 +120,10 @@

   for child in fs.readdirSync('node_modules') when child isnt '.bin'
     directory = path.join('node_modules', child)
-    {engines, theme} = grunt.file.readJSON(path.join(directory, 'package.json'))
+    metadataPath = path.join(directory, 'package.json')
+    continue unless grunt.file.isFile(metadataPath)
+
+    {engines, theme} = grunt.file.readJSON(metadataPath)
     if engines?.atom?
       coffeeConfig.glob_to_multiple.src.push("#{directory}/**/*.coffee")
       lessConfig.glob_to_multiple.src.push("#{directory}/**/*.less")