detect and update align status in toolbar

--- src/modules/toolbar.coffee
+++ src/modules/toolbar.coffee
@@ -87,12 +87,28 @@
     )

   _getActive: (range) ->
+    leafFormats = this._getLeafActive(range)
+    lineFormats = this._getLineActive(range)
+    return _.defaults(leafFormats, lineFormats)
+
+  _getLeafActive: (range) ->
     if range.isCollapsed()
       start = Math.max(0, range.start - 1)
       contents = @quill.getContents(start, range.end)
     else
       contents = @quill.getContents(range)
     formatsArr = _.map(contents.ops, 'attributes')
+    return this._intersectFormats(formatsArr)
+
+  _getLineActive: (range) ->
+    formatsArr = []
+    [firstLine, offset] = @quill.editor.doc.findLineAt(range.start)
+    [lastLine, offset] = @quill.editor.doc.findLineAt(range.end)
+    lastLine = lastLine.next if lastLine? and lastLine == firstLine
+    while firstLine? and firstLine != lastLine
+      formats = { 'align': firstLine.formats['align'] }    # TODO fix when we have more line attributes
+      formatsArr.push(firstLine.formats)
+      firstLine = firstLine.next
     return this._intersectFormats(formatsArr)

   _intersectFormats: (formatsArr) ->


use event delegation for avatar name tooltips

Former-commit-id: 7c2553bc77dd6424cb329374d681d1730615e742 [formerly 1cc5809636499a211ff7d27add3f6894614dd6df] [formerly 2def5dcc7338806e00923101c580d85f6e568324 [formerly 72f73f04b4263c45a149483dde249434b6298e04]] [formerly 5d1b3f55343ad4e84366f76dab44aab2cc96d515 [formerly 9121077a51646ec90098490882e90aa1a8615ca5] [formerly 0d5b2c0dd7b9ce6bad595b04f98577b9e2ae5499 [formerly 0d5b2c0dd7b9ce6bad595b04f98577b9e2ae5499 [formerly 4aa7b48232f3ce446271512377223cd08c7670cf]]]]
Former-commit-id: 1ebd5cfc14e1dae2eba440257f57b2ca84f6f8cf [formerly 04141fcdacbdbad2a3eb507acba533e99dc7ccf9] [formerly 4e9ad365df19a3fded6a12a44a0ad9a5c6dab105 [formerly 4a5d09411cc5ea527a70d19b2b21a4af1b48f481]]
Former-commit-id: 847b25ba749e32c2e558d44984354a59951be5fd [formerly d9c821bf783190997db1704e4f836f7564c5dc84]
Former-commit-id: cc495192f028db94f766a9e839376faebf4730f8
Former-commit-id: 7765f3a6bd45c2223ef4624d3a3c3db5714defca

--- @client/avatar.coffee
+++ @client/avatar.coffee
@@ -9,6 +9,31 @@
         "/system/avatars/" + \
         "#{user.key.split('/')[2]}/#{img_size}/#{user.avatar_file_name}"

+
+
+##########
+# Performance hack.
+# Was seeing major slowdown on pages with lots of avatars simply because we
+# were attaching a mouseover and mouseout event on each and every Avatar for
+# the purpose of showing a tooltip name. So we use event delegation instead.
+document.addEventListener "mouseover", (e) ->
+  if e.target.getAttribute('data-user') && e.target.getAttribute('data-showtooltip') == 'true'
+    user = fetch(e.target.getAttribute('data-user'))
+    anon = e.target.getAttribute('data-anonymous') == 'true'
+    name = if anon || user.name?.length == 0
+             'Anonymous'
+           else
+             user.name
+    tooltip = fetch 'tooltip'
+    tooltip.coords = $(e.target).offset()
+    tooltip.tip = name
+    save tooltip
+
+document.addEventListener "mouseout", (e) ->
+  if e.target.getAttribute('data-user') && e.target.getAttribute('data-showtooltip') == 'true'
+    tooltip = fetch 'tooltip'
+    tooltip.coords = null
+    save tooltip

 ##
 # Avatar
@@ -37,6 +62,7 @@
 #      Suppress the tooltip on hover.
 #   anonymous (default = false)
 #      Don't show a real picture and show "anonymous" in the tooltip.
+

 window.Avatar = ReactiveComponent
   displayName: 'Avatar'
@@ -90,22 +116,11 @@
     attrs =
       className: "avatar #{@props.className or ''}"
       id: id
+      'data-user': user.key
+      'data-showtooltip': !@props.hide_tooltip
+      'data-anon': @props.anonymous
       style: style
-      onMouseEnter: =>
-        if !@props.hide_tooltip
-          name = if @props.anonymous || user.name?.length == 0
-                   'Anonymous'
-                 else
-                   user.name
-          tooltip = fetch 'tooltip'
-          tooltip.coords = $(@getDOMNode()).offset()
-          tooltip.tip = name
-          save tooltip
-      onMouseLeave: =>
-        if !@props.hide_tooltip
-          tooltip = fetch 'tooltip'
-          tooltip.coords = null
-          save tooltip
+

     # IE9 gets confused if there is an image without a src
     tag = if !thumbnail? && browser.is_ie9 && img_size == 'thumb' || add_initials then SPAN else IMG


fix relative date (again, geez)

fix relative date (again, geez)

--- @client/shared.coffee
+++ @client/shared.coffee
@@ -109,7 +109,7 @@
                               day_diff == 1 && "Yesterday" ||
                               day_diff < 7 && day_diff + " days ago" ||
                               day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago" ||
-                              "#{date.getMonth() + 1}/#{date.getDay()}/#{date.getFullYear()}"
+                              "#{date.getMonth() + 1}/#{date.getDay() + 1}/#{date.getFullYear()}"

   r = r.replace('1 days ago', '1 day ago').replace('1 weeks ago', '1 week ago').replace('1 years ago', '1 year ago')
   r


add patches in the data model

add patches in the data model

--- src/spec.coffee
+++ src/spec.coffee
@@ -378,6 +378,8 @@
             size: 0
           }

+      patches: -> @genval.patches
+
       power_state: ->
         if @data.metrics?.live
           'Running'
@@ -801,3 +803,31 @@

       status: -> @genval.status
     }
+
+  @rule host_patch: ->
+    @val = {
+      applied: -> @genval.applied
+
+      $host: -> @genval.host
+
+      time: -> $toTimestamp @genval.timestamp_applied
+
+      pool_patch: -> @genval.pool_patch
+
+    }
+
+  @rule pool_patch: ->
+    @val = {
+      name_label: -> @genval.name_label
+
+      name_description: -> @genval.name_description
+
+      applied: -> @genval.pool_applied
+
+      version: -> @genval.version
+
+      $host_patches: -> @genval.host_patches
+
+      size: -> @genval.size
+
+    }


prepare backend for snapshots, as requested in https://github.com/vatesfr/xo-web/issues/95 and https://github.com/vatesfr/xo-web/issues/96

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -475,6 +475,27 @@

   return true

+exports.snapshot = ->
+  {
+    id
+    name
+  } = @getParams {
+    id: { type: 'string' }
+    name: { type: 'string' }
+  }
+
+  @checkPermission 'admin'
+
+  try
+    VM = @getObject id
+  catch
+    @throw 'NO_SUCH_OBJECT'
+
+  xapi = @getXAPI VM
+
+  $wait xapi.call 'VM.snapshot', VM.ref, name
+
+  return true

 exports.start = ->
   {id} = @getParams {


Fix prelude path on Windows.

Fix prelude path on Windows.

--- src/bundle.coffee
+++ src/bundle.coffee
@@ -183,8 +183,7 @@

   # Returns necessary prelude file.
   prelude = (opts, cb) ->
-    path = __dirname
-    path += if opts.minify then '/prelude-minify' else '/prelude'
+    path = join __dirname, if opts.minify then 'prelude-minify' else 'prelude'

     resolve path, (err, filename) ->
       fs.readFile filename, 'utf8', (err, data) ->


:memo: Fix PackageManager::onDidLoadAll description

--- src/package-manager.coffee
+++ src/package-manager.coffee
@@ -48,7 +48,7 @@
   Section: Event Subscription
   ###

-  # Public: Invoke the given callback when all packages have been activated.
+  # Public: Invoke the given callback when all packages have been loaded.
   #
   # * `callback` {Function}
   #


Fixing handler for new created files, in order to watch and compile them.

--- src/polvo/core/tree.coffee
+++ src/polvo/core/tree.coffee
@@ -111,8 +111,8 @@
         log "[#{now}] #{msg} #{relative_path}".cyan

         # initiate file and adds it to the array
-        @files.push script = new Script @, dir, location
-        script.compile_to_disk @config
+        file = new File @polvo, @cli, @config, @tentacle, @, dir, location
+        do file.compile_to_disk

       # when a file is deleted
       when "delete"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -36,7 +36,7 @@
       height: 2 * deadzone.y

     if objectCenter.x > centerRect.right
-      I.scroll.x = I.scr
+      I.scroll.x = I.scroll.x.app
     else if objectCenter.x < centerRect.left


$ -> jQuery for consistency.

$ -> jQuery for consistency.

--- src/cartjs.coffee
+++ src/cartjs.coffee
@@ -45,8 +45,8 @@
   # Set up toggling of CSS class on body during requests if provided.
   if CartJS.settings.requestBodyClass
     CartJS.Utils.log('"requestBodyClass" set, adding event listeners.')
-    $(document).on 'cart.requestStarted', () -> $('body').addClass(CartJS.settings.requestBodyClass)
-    $(document).on 'cart.requestComplete', () -> $('body').removeClass(CartJS.settings.requestBodyClass)
+    jQuery(document).on 'cart.requestStarted', () -> jQuery('body').addClass(CartJS.settings.requestBodyClass)
+    jQuery(document).on 'cart.requestComplete', () -> jQuery('body').removeClass(CartJS.settings.requestBodyClass)

   # Initialise DOM Binding through Rivets module.
   # Performs a no-op if Rivets.js isn't present.


Removed unnecessary require in processes/index.coffee

--- src/processes/index.coffee
+++ src/processes/index.coffee
@@ -30,7 +30,6 @@
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ###

-{spawn} = require 'child_process'
 http = require 'http'

 async = require 'async'


Disable persistent storage from tour

Disable persistent storage from tour

--- src/tour.coffee
+++ src/tour.coffee
@@ -157,6 +157,7 @@
                 if step.last
                     step.examples = getExamples()
                 jade.template 'tour', step
+            storage : false
             container: '#tour-region'
             onEnd: (tour) ->
                 p13n.set 'skip_tour', true


add moewbot option

add moewbot option

--- src/scripts/meowziq.coffee
+++ src/scripts/meowziq.coffee
@@ -2,14 +2,15 @@
 #   A Hubot script for meowziq
 #
 # Configuration:
+#   HUBOT_MEOWZIQ_MEOWBOT
+#   HUBOT_MEOWZIQ_ROOM
 #   HUBOT_MEOWZIQ_URL
-#   HUBOT_MEOWZIQ_ROOM
 #
 # Commands:
-#   hubot meowziq play - play meowziq
-#   hubot meowziq skip - skip meowziq
-#   hubot meowziq status - show meowziq status
-#   hubot meowziq stop - stop meowziq
+#   hubot [meowziq] play - play meowziq
+#   hubot [meowziq] skip - skip meowziq
+#   hubot [meowziq] status - show meowziq status
+#   hubot [meowziq] stop - stop meowziq
 #
 # Author:
 #   bouzuya <m@bouzuya.net>
@@ -18,6 +19,7 @@
 request = require 'request-b'

 config = parseConfig 'meowziq',
+  meowbot: null
   url: null
   room: null
   interval: '5000'
@@ -44,7 +46,8 @@
       .then (-> watch robot), (-> watch robot)
     , INTERVAL

-  robot.respond /meowziq play/, (res) ->
+  pattern = new RegExp (if config.meowbot then '' else 'meowziq ') + 'play'
+  robot.respond pattern, (res) ->
     message = null
     request
       method: 'PATCH'
@@ -55,7 +58,8 @@
       result = if r.statusCode is 200 then 'OK' else 'ERROR'
       res.send result

-  robot.respond /meowziq skip/, (res) ->
+  pattern = new RegExp (if config.meowbot then '' else 'meowziq ') + 'skip'
+  robot.respond pattern, (res) ->
     message = null
     request
       method: 'PATCH'
@@ -66,7 +70,8 @@
       result = if r.statusCode is 200 then 'OK' else 'ERROR'
       res.send result

-  robot.respond /meowziq status/, (res) ->
+  pattern = new RegExp (if config.meowbot then '' else 'meowziq ') + 'status'
+  robot.respond pattern, (res) ->
     message = null
     request config.url + '/status'
     .then (r) ->
@@ -83,7 +88,8 @@
     .then ->
       res.send message

-  robot.respond /meowziq stop/, (res) ->
+  pattern = new RegExp (if config.meowbot then '' else 'meowziq ') + 'stop'
+  robot.respond pattern, (res) ->
     message = null
     request
       method: 'PATCH'


Support callback bindings.

Support callback bindings.

--- src/view.coffee
+++ src/view.coffee
@@ -66,10 +66,12 @@

       # For each target cache based on selector
       for target in targets
-        [selector, attr] = @_splitTarget target
-
-        unless @_targets[selector]?
-          @_targets[selector] = @$el.find selector
+        # only cache string-based selector targets
+        if typeof target is 'string'
+          [selector, attr] = @_splitTarget target
+
+          unless @_targets[selector]?
+            @_targets[selector] = @$el.find selector

   _computeComputed: (name) ->
     args = []
@@ -99,19 +101,32 @@
     unless Array.isArray targets
       targets = [targets]

+    # find formatter
+    formatter = @formatters[name]
+
     # Update each target
     for target in targets
-      [selector, attr] = @_splitTarget target
-
-      # Format value and mutate DOM
-      if (formatter = @formatters[name])?
-        _value = formatter.call @, value, "#{selector} @#{attr}"
+      if typeof target is 'string'
+        @_renderSelector target, value, formatter
       else
-        _value = value
-
-      @_mutateDom selector, attr, _value
-
+        @_renderCallback target, value, name, formatter
     return
+
+  # render a string selector binding
+  _renderSelector: (target, value, formatter) ->
+    [selector, attr] = @_splitTarget target
+
+    # Format value and mutate DOM
+    if formatter?
+      value = formatter.call @, value, "#{selector} @#{attr}"
+
+    @_mutateDom selector, attr, value
+
+  # render a callback binding
+  _renderCallback: (target, value, name, formatter) ->
+    if formatter?
+      value = formatter.call @, value, 'callback'
+    target.call @, value, name

   # Split event name / selector
   _splitEvent: (e) ->


close driver after all screenshots have taken

--- src/viff.coffee
+++ src/viff.coffee
@@ -6,19 +6,22 @@
 class Viff
   constructor: (seleniumHost) ->
     @builder = new webdriver.Builder().usingServer(seleniumHost)
+    @drivers = {}

   takeScreenshot: (browserName, envHost, url, callback) ->
+    that = @
     defer = mr.Deferred()
     defer.done(callback)

-    @builder = @builder.withCapabilities { browserName: browserName }
-    driver = @builder.build()
+    unless driver = @drivers[browserName]
+      @builder = @builder.withCapabilities { browserName: browserName }
+      driver = @builder.build()
+      @drivers[browserName] = driver

     envName = _.first(envName for envName of envHost)
     driver.get envHost[envName] + url

     driver.takeScreenshot().then (base64Img) ->
-      driver.close()
       defer.resolve base64Img

     defer.promise()
@@ -51,6 +54,7 @@
               returned++

             if returned == total
+              driver.close() for browserName, driver of that.drivers
               defer.resolve compares

     defer.promise()


Add row count docs

Add row count docs

--- src/editor.coffee
+++ src/editor.coffee
@@ -1948,12 +1948,16 @@
   # Essential: Move the cursor of each selection one character upward while
   # preserving the selection's tail position.
   #
+  # * `rowCount` {Number} of rows to select up
+  #
   # This method may merge selections that end up intesecting.
   selectUp: (rowCount) ->
     @expandSelectionsBackward (selection) -> selection.selectUp(rowCount)

   # Essential: Move the cursor of each selection one character downward while
   # preserving the selection's tail position.
+  #
+  # * `rowCount` {Number} of rows to select down
   #
   # This method may merge selections that end up intesecting.
   selectDown: (rowCount) ->


fix bug where deleting last character is not registered

--- src/editor.coffee
+++ src/editor.coffee
@@ -1,10 +1,10 @@
 #= require underscore
-#= require rangy-core
+#= require rangy/rangy-core
 #= require diff_match_patch
 #= require eventemitter2
 #= require jetsync
 #= require tandem/document
-#= require tandem/selection
+#= require tandem/range

 class TandemEditor extends EventEmitter2
   @editors: []
@@ -44,6 +44,7 @@
       body {
         font-family: 'Helvetica', 'Arial', san-serif;
         font-size: 13px;
+        line-height: 15px;
         margin: 0px;
         padding: 0px;
       }
@@ -66,8 +67,7 @@
   initContentListeners: ->
     onEdit = _.debounce( =>
       delta = this.update()
-      if delta.deltas.length > 1 || !JetRetain.isRetain(delta.deltas[0])
-        this.emit(this.events.USER_TEXT_CHANGE, delta)
+      this.emit(this.events.USER_TEXT_CHANGE, delta) if !delta.isIdentity()
     , 100)

     @iframeDoc.body.addEventListener('DOMSubtreeModified', =>


Novo trecho que inclui o javascript do servi?o de estat?sticas do Serpro

--- assets/barra-brasil.coffee
+++ assets/barra-brasil.coffee
@@ -29,3 +29,12 @@
         style.appendChild conteudo
         head.appendChild style

+  #Inserindo tag javascript do Serpro Analytics
+  novoScript = document.createElement("script")
+  tipo = document.createAttribute("type")
+  tipo.nodeValue = "text/javascript"
+  src = document.createAttribute("src")
+  src.nodeValue = "http://coletajavascript.serpro.gov.br/estatistica.js"
+  novoScript.setAttributeNode tipo
+  novoScript.setAttributeNode src
+  head.appendChild novoScript


don't return mutable array from deps

don't return mutable array from deps

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -604,16 +604,17 @@
 Observable :: inspect = Observable :: toString

 flatMap_ = (root, f, firstOnly, limit) ->
-  deps = [root]
+  rootDep = [root]
+  childDeps = []
   result = new EventStream describe(root, "flatMap" + (if firstOnly then "First" else ""), f), (sink) ->
     composite = new CompositeUnsubscribe()
     queue = []
     spawn = (event) ->
       child = makeObservable(f event.value())
-      deps.push(child)
+      childDeps.push(child)
       composite.add (unsubAll, unsubMe) -> child.subscribeInternal (event) ->
         if event.isEnd()
-          _.remove(child, deps)
+          _.remove(child, childDeps)
           checkQueue()
           checkEnd(unsubMe)
           Bacon.noMore
@@ -644,7 +645,7 @@
         else
           spawn event
     composite.unsubscribe
-  result.internalDeps = -> deps
+  result.internalDeps = -> if (childDeps.length) then rootDep.concat(childDeps) else rootDep
   result

 class EventStream extends Observable


follow docs

follow docs

--- src/follow.coffee
+++ src/follow.coffee
@@ -12,7 +12,7 @@

 enemy = GameObject
   x: 100
-  y:
+  y: 50

 player.update()
 </pre></code>


delete before calling callbacks

delete before calling callbacks

--- src/smc-hub/rethink.coffee
+++ src/smc-hub/rethink.coffee
@@ -468,9 +468,10 @@
         @table(opts.table).wait(waitFor: "ready_for_writes", timeout:30).run (err) =>
             if not err and opts.cache
                 last[opts.table] = new Date()
-            for cb in d[opts.table]
+            v = d[opts.table]
+            delete d[opts.table]
+            for cb in v
                 cb(err)
-            delete d[opts.table]

     # Wait until the query results in at least one result obj, and
     # calls cb(undefined, obj).


Simplify hint-string generation; fix tests.

--- tests/dom_tests/dom_tests.coffee
+++ tests/dom_tests/dom_tests.coffee
@@ -149,10 +149,8 @@
     document.getElementById("test-div").innerHTML = ""

   should "label the hints correctly", ->
-    # TODO(philc): This test verifies the current behavior, but the current behavior is incorrect.
-    # The output here should be something like aa, ab, b.
     hintMarkers = getHintMarkers()
-    expectedHints = ["aa", "ba", "ab"]
+    expectedHints = ["aa", "b", "ab"]
     for hint, i in expectedHints
       assert.equal hint, hintMarkers[i].hintString


Fixed bug that prevented all open prs from showing Fixed up github lookup logic

--- src/github.coffee
+++ src/github.coffee
@@ -51,6 +51,7 @@
       users = _(users).keys().map (id) ->
         u = users[id]
         id: u.id
+        name: u.name
         real_name: u.real_name

       f = new Fuse users,
@@ -59,13 +60,8 @@
         verbose: no
       results = f.search github.login
       result = if results? and results.length >=1 then results[0] else null
-
-      if result
-        return "<@#{result.id}>"
-      else
-        return github.login
-    else
-      return "Unassigned"
+      return result if result
+    return null

   notificationShouldFire = (notification) ->
     now = new Date
@@ -129,21 +125,26 @@
     repo = octo.repos(githubOrg, repo)
     repo.pulls.fetch(state: "open").then (prs) ->
       return Promise.all prs.map (pr) ->
-        if not user? or pr.assignee?.login.toLowerCase() is user.toLowerCase()
-          return repo.pulls(pr.number).fetch()
-        return
+        if user?
+          return if not pr.assignee?
+          assignee = lookupUserWithGithub pr.assignee
+          return if user.toLowerCase() isnt assignee.name.toLowerCase()
+
+        return repo.pulls(pr.number).fetch()
     .then ( prs ) ->
       message = ""
       for pr in prs when pr
-          message+= """
-            *[#{pr.title}]* +#{pr.additions} -#{pr.deletions}
-            #{pr.htmlUrl}
-            Updated: *#{moment(pr.updatedAt).fromNow()}*
-            Status: #{if pr.mergeable then "Mergeable" else "Unresolved Conflicts"}
-            Author: #{lookupUserWithGithub pr.user}
-            Assignee: #{lookupUserWithGithub pr.assignee}
-            \n
-          """
+        author = lookupUserWithGithub pr.user
+        assignee = lookupUserWithGithub pr.assignee
+        message+= """
+          *[#{pr.title}]* +#{pr.additions} -#{pr.deletions}
+          #{pr.htmlUrl}
+          Updated: *#{moment(pr.updatedAt).fromNow()}*
+          Status: #{if pr.mergeable then "Mergeable" else "Unresolved Conflicts"}
+          Author: #{if author then "<@#{author.id}>" else "Unknown"}
+          Assignee: #{if assignee then "<@#{assignee.id}>" else "Unassigned"}
+          \n
+        """
       if message.length is 0
         message = "No matching pull requests found"

@@ -209,7 +210,9 @@

     if who?
       who = robot.brain.userForName who
-      listOpenPullRequestsForRoom msg.message.room, who.name
+      who = who.name
+
+    listOpenPullRequestsForRoom msg.message.room, who

   robot.brain.once 'loaded', ->
     # Run a cron job that runs every minute, Monday-Friday


fix conquest

fix conquest

--- src/inject.coffee
+++ src/inject.coffee
@@ -8,26 +8,24 @@
   }
   chrome.notifications.create opt
 alarmIt = (name, finished_at)->
-  console.log chrome, chrome.alarms
   chrome.alarms.get "#{name}|#{finished_at}", (alarm)->
     if !alarm
+      return if (Date.parse(finished_at) - 120000) < Date.now()
       chrome.alarms.create "#{name}|#{finished_at}", { when: Date.parse(finished_at) - 120000 }
       notify("#{name}远征开始！", "归还时间：#{finished_at}", "将在远征结束两分钟前提醒")
 chrome.alarms.onAlarm.addListener (alarm)->
   data = alarm.name.split('|')
   name = data[0]
-  time = data[1]
+  finished_at = data[1]
   notify("#{name}远征即将结束！", "归还时间：#{finished_at}", "请注意查收远征结果")
 chrome.runtime.onMessage.addListener (message)->
   #notify("Get", message)
-  console.log message
   return if !message.type
   switch message.type
     when 'conquest'
       _.forEach message.msg, (n, key)->
         return if n.finished_at == null
         alarmIt n.party_name, n.finished_at
-        # chrome.alarms.create("#{n.party_name}#{n.finished_at}", Date.parse(n.finished_at))
     when 'notify'
       msg = message.msg
       notify msg.title, msg.message, msg.contextMessage


Output only document html instead of whole layout

--- src/inkpad.coffee
+++ src/inkpad.coffee
@@ -3,7 +3,10 @@

 module.exports = (id) ->

-  url = "https://www.inkpad.io/#{id}"
+  options =
+    url: "https://www.inkpad.io/#{id}"
+    headers:
+      "Accept": "text/html;vanilla"

-  request(url)
+  request options


Temporary LoS effect

Temporary LoS effect

--- src/io/tty.coffee
+++ src/io/tty.coffee
@@ -123,7 +123,11 @@

 			# to only get the part that's on-screen
 			# we slice from left to right edge of viewport
-			row = row[c.x ... c.x+c.viewport.w]
+			# row = row[c.x ... c.x+c.viewport.w]
+			row = for t, tx in row[c.x ... c.x+c.viewport.w]
+				if c.target.canSee {x: (c.x + tx), y: (c.y + cy)}
+					t
+				else ' '

 			program.write row.join ''

@@ -140,7 +144,7 @@
 	renderEntities: (x, y, entities) ->
 		c = @game.camera

-		for e in entities
+		for e in entities when c.target.canSee e
 			if (c.x <= e.x < c.x+c.viewport.w) and (c.y <= e.y < c.y+c.viewport.h)
 				program.pos (e.y - c.y + y), (e.x - c.x + x)
 				program.write _.result e, 'symbol'


Tests: Disable search test intentionally, I need to test it for other test steps

I will revert this after first test passes.

--- tests/src/activity/others.coffee
+++ tests/src/activity/others.coffee
@@ -7,20 +7,22 @@

 module.exports =

-
-  searchActivity: (browser) ->
-
-    post     = helpers.postActivity(browser)
-    selector = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
-    word     = post.split(' ')[0]
-
-    browser
-      .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
-      .waitForElementVisible    '.kdtabpaneview.search', 25000
-      .waitForElementVisible    selector, 25000
-      .pause                    25000
-      .assert.containsText      selector, word # Assertion
-      .end()
+  # Disable search test intentionally, I need to test it for other test steps
+  # I will revert this after first test passes ~ GG
+  #
+  # searchActivity: (browser) ->
+  #
+  #   post     = helpers.postActivity(browser)
+  #   selector = '[testpath=activity-list] [testpath=ActivityListItemView]:first-child'
+  #   word     = post.split(' ')[0]
+  #
+  #   browser
+  #     .setValue                 '.kdtabhandlecontainer .search-input', word + '\n'
+  #     .waitForElementVisible    '.kdtabpaneview.search', 25000
+  #     .waitForElementVisible    selector, 25000
+  #     .pause                    25000
+  #     .assert.containsText      selector, word # Assertion
+  #     .end()

   showMoreCommentLink: (browser) ->


js state machine

js state machine

--- src/State.coffee
+++ src/State.coffee
@@ -142,7 +142,7 @@
   self =
     add: (name, object, options) ->
       guard = Guard(name, object, options)
-      guards.push guard
+      guards.push(guard)
       return guard

     all: ->


add z

add z

--- src/Controller.coffee
+++ src/Controller.coffee
@@ -46,6 +46,7 @@
     @kb.addKey(Phaser.Keyboard.W).onDown.add(@type, @, 0, 'w')
     @kb.addKey(Phaser.Keyboard.X).onDown.add(@type, @, 0, 'x')
     @kb.addKey(Phaser.Keyboard.Y).onDown.add(@type, @, 0, 'y')
+    @kb.addKey(Phaser.Keyboard.Z).onDown.add(@type, @, 0, 'z')
     @kb.addKey(Phaser.Keyboard.ZERO).onDown.add(@type, @, 0, '0', ')')
     @kb.addKey(Phaser.Keyboard.ONE).onDown.add(@type, @, 0, '1', '!')
     @kb.addKey(Phaser.Keyboard.TWO).onDown.add(@type, @, 0, '2', '@')


Fix Object.keys shim by iterating over obj

--- src/LibroIpsum.coffee
+++ src/LibroIpsum.coffee
@@ -217,7 +217,7 @@

     # Object.keys polyfill (ES5)
     Object.keys ?= (obj) ->
-        key for key of keys when obj.hasOwnProperty(key)
+        key for key of obj when obj.hasOwnProperty(key)

     # ## Expose LibroIpsum


fix pang

fix pang

--- src/js/sse.coffee
+++ src/js/sse.coffee
@@ -1,5 +1,5 @@
 jQuery(document).ready ->

   # 有内容页面，对内容页面添加空格
-  if jQuery('.main-content').length > 0
-    pangu.element_spacing('.typo')
+  if jQuery('.format--pangu').length > 0
+    pangu.element_spacing('.format--pangu')


make account an optional parameter on getPassword()

--- src/keytar.coffee
+++ src/keytar.coffee
@@ -1,9 +1,8 @@
 keytar = require('../build/Release/keytar.node')

 module.exports =
-  getPassword: (service, account) ->
+  getPassword: (service, account = "") ->
     throw new Error("Service is required.") unless service?.length > 0
-    throw new Error("Account is required.") unless account?.length > 0

     keytar.getPassword(service, account)


set-outer-width

set-outer-width

--- src/layout.coffee
+++ src/layout.coffee
@@ -32,9 +32,11 @@
     margin: my.margin
     outer_width: (world) -> world.get('width') + 2 * world.get('padding')
     inner_width: (world) -> world.get('width') - 2 * world.get('margin')
-    available_width: (world) -> world.up.get('inner_width') - 2 * world.get('padding')
+    available_width: (world) ->
+      world.up.get('inner_width') - 2 * world.get('padding')
+    set_outer_width: (world, outer_width) ->
+      world.put 'width', (outer_width - 2 * world.get('padding'))
   }
-

 set_font_size = (dict, size) -> dict.name_style = {font_size: size}


Rename _build_errors(expectation) to build_errors()

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -5,8 +5,15 @@
   all_expectations.length = 0

 verify_all_expectations = ->
-  errors = _build_errors(@)
+  errors = build_errors()
   throw new Error(errors) unless errors == ""
+
+build_errors = ->
+  # TODO: use a mapping function?
+  errors = ""
+  for expectation in all_expectations when expectation.called == false
+    errors += "'#{expectation.method_name}(#{expectation._args})' was never called\n"
+  errors

 class Expectation
@@ -124,13 +131,6 @@
     for inner in [outer+1..all_expectations.length-1]
       if all_expectations[outer].equals( all_expectations[inner] )
         _throw_duplicate_expectation("#{all_expectations[outer].method_name}(#{all_expectations[outer]._args})")
-
-_build_errors = (expectation) ->
-  # TODO: use a mapping function?
-  errors = ""
-  for expectation in all_expectations when expectation.called == false
-    errors += "'#{expectation.method_name}(#{expectation._args})' was never called\n"
-  errors

 _throw_args_usage = ->
   throw "you need to supply at least one argument to args(), e.g. my_mock.expects('my_method').args(42)"


Create class Expects and move related functions into it.

--- src/TinyMockJS.coffee
+++ src/TinyMockJS.coffee
@@ -16,7 +16,7 @@
     AllExpectations.unregister_all_expectations()

 install_expects_method = ->
-  Object.prototype.expects = expects
+  Object.prototype.expects = Expects.expects

 uninstall_expects_method = ->
   delete Object.prototype.expects
@@ -29,44 +29,42 @@

 #
-# expects
-#
-expects = (method_name) ->
-  check_expects_usage(@, method_name)
-  create_expectation(@, method_name)
-
-check_expects_usage = (object, method_name) ->
-  throw_expects_usage() unless method_name?
-  throw_reserved_word(method_name) if is_reserved_word(method_name)
-  throw_pre_existing_property(method_name) if is_pre_existing_property(object, method_name)
-  throw_not_an_existing_method(method_name) if is_class(object) and not prototype_has_method(object, method_name)
-
-is_reserved_word = (word) ->
-  word in [ "expects", "args", "returns", "check" ]
-
-is_pre_existing_property = (object, method_name) ->
-  object[ method_name ]? and (typeof object[ method_name ]) != 'function'
-
-is_class = (object) ->
-   typeof object == 'function'
-
-prototype_has_method = (object, method_name) ->
-   object.prototype[ method_name ]?
-
-create_expectation = (object, method_name) ->
-  new Expectation(object, method_name)
-
-throw_expects_usage = ->
-  throw new Error( "you need to supply a method name to expects(), e.g. my_mock.expects('my_method')" )
-
-throw_reserved_word = (reserved_word) ->
-  throw new Error( "you cannot use my_mock.expects('#{reserved_word}'); '#{reserved_word}' is a reserved method name" )
-
-throw_pre_existing_property = (property_name) ->
-  throw new Error( "'#{property_name}' is an existing property; you can only mock functions" )
-
-throw_not_an_existing_method = (method_name) ->
-  throw new Error( "'#{method_name}' is not an existing method; you can only mock existing methods on classes" )
+# Expects
+#
+class Expects
+
+  @expects: (method_name) ->
+    _check_expects_usage(@, method_name)
+    _create_expectation(@, method_name)
+
+  # private
+
+  _check_expects_usage = (object, method_name) ->
+    _throw_expects_usage() unless method_name?
+    _throw_reserved_word(method_name) if _is_reserved_word(method_name)
+    _throw_pre_existing_property(method_name) if _is_pre_existing_property(object, method_name)
+    _throw_not_an_existing_method(method_name) if is_class(object) and not prototype_has_method(object, method_name)
+
+  _is_reserved_word = (word) ->
+    word in [ "expects", "args", "returns", "check" ]
+
+  _is_pre_existing_property = (object, method_name) ->
+    object[ method_name ]? and (typeof object[ method_name ]) != 'function'
+
+  _create_expectation = (object, method_name) ->
+    new Expectation(object, method_name)
+
+  _throw_expects_usage = ->
+    throw new Error( "you need to supply a method name to expects(), e.g. my_mock.expects('my_method')" )
+
+  _throw_reserved_word = (reserved_word) ->
+    throw new Error( "you cannot use my_mock.expects('#{reserved_word}'); '#{reserved_word}' is a reserved method name" )
+
+  _throw_pre_existing_property = (property_name) ->
+    throw new Error( "'#{property_name}' is an existing property; you can only mock functions" )
+
+  _throw_not_an_existing_method = (method_name) ->
+    throw new Error( "'#{method_name}' is not an existing method; you can only mock existing methods on classes" )

 #
@@ -75,43 +73,43 @@
 # TODO: note about there not being that many expectations (i.e. typically fewer than 10?)
 #
 class AllExpectations
-
-	@register_expectation: (expectation) ->
-		_expectations.push(expectation)
-
-	@find_expectation: (object, method_name, args...) ->
-	  for expectation in _expectations when expectation.matches(object, method_name, args...)
-	    return expectation
-	  undefined
-
-	@check_for_duplicate_expectations: ->
-	  # TODO: use each with index and slice to avoid last element
-	  return if _expectations.length < 2
-	  for outer in [0.._expectations.length-2]
-	    for inner in [outer+1.._expectations.length-1]
-	      if _expectations[outer].equals( _expectations[inner] )
-	        throw_duplicate_expectation("#{_expectations[outer]._method_name}(#{_expectations[outer]._args})")
-
-	@verify_all_expectations: ->
-		errors = _find_all_errors()
-		throw new Error(errors) unless errors == ""
-
-	# TODO: write comment about uninstalling in reverse
-	# TODO: does this belong in unregister_all_expectsions?
-	@uninstall_all_mocked_methods: ->
-	  expectation.uninstall_mocked_method() for expectation in _expectations by -1
-
-	# TODO: should this be called remove_all_expectations?  What about register_expectations?
-	#       How about install_expectation() and uninstall_all_expectations()?
-	@unregister_all_expectations: ->
-		_expectations.length = 0
-
-	# private
-
-	_expectations = []
-
-	_find_all_errors = ->
-  	  ( expectation.find_errors() for expectation in _expectations ).join("")
+
+  @register_expectation: (expectation) ->
+    _expectations.push(expectation)
+
+  @find_expectation: (object, method_name, args...) ->
+    for expectation in _expectations when expectation.matches(object, method_name, args...)
+      return expectation
+    undefined
+
+  @check_for_duplicate_expectations: ->
+    # TODO: use each with index and slice to avoid last element
+    return if _expectations.length < 2
+    for outer in [0.._expectations.length-2]
+      for inner in [outer+1.._expectations.length-1]
+        if _expectations[outer].equals( _expectations[inner] )
+          throw_duplicate_expectation("#{_expectations[outer]._method_name}(#{_expectations[outer]._args})")
+
+  @verify_all_expectations: ->
+    errors = _find_all_errors()
+    throw new Error(errors) unless errors == ""
+
+  # TODO: write comment about uninstalling in reverse
+  # TODO: does this belong in unregister_all_expectsions?
+  @uninstall_all_mocked_methods: ->
+    expectation.uninstall_mocked_method() for expectation in _expectations by -1
+
+  # TODO: should this be called remove_all_expectations?  What about register_expectations?
+  #       How about install_expectation() and uninstall_all_expectations()?
+  @unregister_all_expectations: ->
+    _expectations.length = 0
+
+  # private
+
+  _expectations = []
+
+  _find_all_errors = ->
+      ( expectation.find_errors() for expectation in _expectations ).join("")

 #
@@ -252,3 +250,13 @@

   _throw_returns_and_throws_both_used: ->
     throw new Error( "you specified both returns() and throws() on the same expectation; use one or the other on an expectation" )
+
+
+#
+# common
+#
+is_class = (object) ->
+   typeof object == 'function'
+
+prototype_has_method = (object, method_name) ->
+   object.prototype[ method_name ]?


http call was giving a 301 redirect and the script did not have the logic for that. Updated url to location of redirect, https, and the script works again

--- src/cheer.coffee
+++ src/cheer.coffee
@@ -47,7 +47,7 @@

   aww = (msg, lead = false) ->
     msg
-      .http('http://www.reddit.com/r/aww.json')
+      .http('https://www.reddit.com/r/aww.json')
         .get() (err, res, body) ->
           response = JSON.parse(body).data.children
           raw_url  = msg.random(response).data.url


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -1,6 +1,6 @@
 lookup = {}

-names.each (i, element) ->
+names.each (element, i) ->
   lookup[element[1].toLowerCase().replace(/ /g, "")] = Color(element[0])

 ###


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -799,6 +799,14 @@

     ###*
     returns an array of the hue, saturation, lightness, and alpha values of the color.
+
+

+    magenta = Color(255, 0, 255)
+
+    magenta.toHsl()
+    # => [300, 1, 0.5, 1]
+

+

     @name toHsl
     @methodOf Color#


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -448,23 +448,22 @@
     ###*
     A getter / setter for the hue value of the color. Passing no argument returns the
     current hue value. Passing a value will set the hue to that value and return the color.
-
-

-    magenta = Color(255, 0, 255)
-
-    magenta.hue()
-    # => 300
-
-    # modifies the color to be yellow
-    magenta.hue(60)
-
-    # to see what it looks like
-    canvas.drawRect
-      color: magenta
-      x: 50
-      y: 30
-      width: 80
-      height: 80
+
+        magenta = Color(255, 0, 255)
+
+        magenta.hue()
+        # => 300
+
+        # modifies the color to be yellow
+        magenta.hue(60)
+
+        # to see what it looks like
+        canvas.drawRect
+          color: magenta
+          x: 50
+          y: 30
+          width: 80
+          height: 80

     @name hue
     @methodOf Color#


Extract upload

Extract upload

--- scripts/ayp.coffee
+++ scripts/ayp.coffee
@@ -456,6 +456,25 @@
       dim..., dim... # No size change
     return dst

+  # Upload a strip S3 and updates @info.image_url
+  #
+  # cb invoked as `cb(error, url)`
+  upload: (cb=(->)) =>
+    perform = =>
+      name = "ayp-#{@info.when}.jpg"
+      info =
+        headers: {'Content-Type': 'image/jpeg'}
+        body: @info.image_jpeg
+      s3.put name, info, (err) ->
+              return cb(new Error("Woooops! Failed to upload: #{err}")) if err
+              return cb(false, @info.image_url = "http://s3.amazonaws.com/#{AYP_AWS_BUCKET}/#{name}")
+
+    # Either upload existing JPEG data, or compile some and upload that
+    return perform() if @info.image_jpeg
+    @buildJPEG (err) ->
+      return cb(err) if err
+      do perform
+
   # Build a JPEG version of the image and invoke the callback
   # with the data. The resulting data is also stored in
   # @info.image_jpeg


Remove bab.

Remove bab.

--- scripts/bab.coffee
+++ scripts/bab.coffee
@@ -1,60 +0,0 @@
-# Description:
-#   Show bab as image.
-#
-# Dependencies:
-#   aws-sdk
-#   moment
-#   pageres
-#
-# Configuration:
-#   None
-#
-# Commands:
-#   hubot bab
-
-AWS = require 'aws-sdk'
-fs = require 'fs'
-moment = require 'moment'
-Pageres = require 'pageres'
-
-module.exports = (robot) ->
-
-  fileName = () -> moment().format('YYYY-MM-DD')
-  fullPath = () -> __dirname + '/' + fileName() + '.png'
-
-  upload = (res) ->
-    s3 = new AWS.S3()
-    fs.stat fullPath(), (err, fileInfo) ->
-      if (err)
-        return res.reply 'failed : ' + err + ', ' + err.message
-      bodyStream = fs.createReadStream fullPath()
-
-      s3.putObject {
-        Bucket: 'slack-menu',
-        Key: fileName() + '.png',
-        Body: bodyStream,
-        ACL: 'public-read',
-        Expires: moment().add(1, 'months').toDate()
-      }, (err) ->
-        if (err)
-          res.reply 'failed : ' + err + ',' + err.message
-        else
-          remove res
-          res.reply 'https://s3-ap-northeast-1.amazonaws.com/slack-menu/' + fileName() + '.png'
-
-  remove = (res) ->
-    fs.unlink fullPath(), (err) ->
-      res.reply 'Error on unlinking temporary image file. ' + err if err
-
-  robot.respond /bab/i, (res) ->
-    pageres = new Pageres({delay: 2, filename: fileName()})
-      # .src('yeoman.io', ['480x320', '1024x768', 'iphone 5s'], {crop: true})
-      .src('mini.snu.kr/cafe/today/', ['1280x1024'])
-      .dest(__dirname)
-
-    pageres.run (err) ->
-      if (err)
-        res.reply 'done'
-      else
-        res.reply 'captured'
-        upload res


Lower color hex values

Lower color hex values

--- src/placement.coffee
+++ src/placement.coffee
@@ -26,7 +26,7 @@
   display: inline-block;
   padding: 5px 10px;
   margin: 0;
-  background: #FFA60D;
+  background: #ffa60d;
 }

 .infeedl--creative .infeedl--title {
@@ -61,7 +61,7 @@
 /* HORIZONTAL */
 .infeedl--appearance--horizontal {
   padding: 10px 15px;
-  background: #FFF;
+  background: #fff;
   border: 1px solid #FFA60D;
   border-radius: 5px;
 }


Make sure we call back after a preroll timeout

--- src/podroller.coffee
+++ src/podroller.coffee
@@ -336,7 +336,7 @@
                 res.end()
                 rstream?.destroy() if rstream?.readable

-
+    #----------

     loadPreroll: (key, req, cb) ->
         count = req.count
@@ -354,6 +354,8 @@
         # Pass along any query string to Preroller
         query = qs.stringify(req.query)

+        aborted = false
+
         opts =
             host: @options.preroll.server
             path: [
@@ -368,7 +370,8 @@
         req_t = setTimeout =>
             debug "#{count}: Preroll timeout reached."
             conn_pre_abort()
-        , 250
+            cb()
+        , 750

         debug "firing preroll request", count
         req = http.get opts, (rres) =>
@@ -385,9 +388,10 @@

                 clearTimeout req_t

-                rres.on "data", (chunk) =>
-                    buffers.push chunk
-                    buf_len += chunk.length
+                rres.on "readable", =>
+                    while chunk = rres.read()
+                        buffers.push chunk
+                        buf_len += chunk.length

                 # when preroll is done, call the output's callback
                 rres.on "end", =>
@@ -396,13 +400,13 @@

                     pre_data = Buffer.concat buffers, buf_len

-                    cb?(pre_data)
+                    cb(pre_data)
                     return true

             else
                 conn.removeListener "close", conn_pre_abort
                 conn.removeListener "end", conn_pre_abort
-                cb?()
+                cb()
                 return true

         req.on "socket", (sock) =>
@@ -412,7 +416,7 @@
             debug "#{count}: got a request error.", err
             conn.removeListener "close", conn_pre_abort
             conn.removeListener "end", conn_pre_abort
-            cb?()
+            cb()
             return true

         # attach a close listener to the response, to be fired if it gets
@@ -421,12 +425,14 @@
         conn_pre_abort = =>
             debug "#{count}: conn_pre_abort called. Destroyed? ", conn.destroyed

-            if conn.destroyed
-                debug "aborting preroll ", count
+            if !aborted
+                debug "#{count}: Aborting preroll"
                 req.abort()
+                aborted = true

             clearTimeout req_t

+        # we don't need to fire the callback after these
         conn.once "close", conn_pre_abort
         conn.once "end", conn_pre_abort


video/helper: add fake subscriber methods

--- client/app/lib/videocollaboration/helper.coffee
+++ client/app/lib/videocollaboration/helper.coffee
@@ -25,6 +25,30 @@
  * @return {boolean}
 ###
 isDefaultPublisher = (participant) -> _.isEqual participant, defaultPublisher()
+
+###*
+ * Helper utility to be able to pass a fake subscriber to the events. Events
+ * mostly don't care about OpenTok specific videoData, so it being `null`
+ * shouldn't affect anything, but be careful when you are passing
+ * `ParticipantType.Participant` instances around.
+ *
+ * @param {string} nickname
+ * @return {object} publisher - a fake object mimics `ParticipantType.Subscriber`
+###
+defaultSubscriber = (nickname) ->
+  nick      : nickname
+  type      : 'subscriber'
+  videoData : 'null'
+
+
+###*
+ * @param {ParticipantType.Participant} participant
+ * @return {boolean}
+###
+isDefaultSubscriber = (participant) ->
+  { type, videoData } = participant
+
+  return type is 'subscriber' and videoData is null

 ###*
@@ -342,7 +366,10 @@

 module.exports = {
+  defaultPublisher
   isDefaultPublisher
+  defaultSubscriber
+  isDefaultSubscriber
   generateSession
   generateToken
   toNickKeyedMap


Delete sass.test.coffee

Delete sass.test.coffee

no need for this anymore

--- src/sass.test.coffee
+++ src/sass.test.coffee
@@ -1,5 +0,0 @@
-# Test our plugin using DocPad's Testers
-require('docpad').require('testers').test({
-  pluginPath: __dirname+'/..'
-  testerClass: 'RendererTester'
-})


new blueprints

new blueprints

--- src/blueprints.coffee
+++ src/blueprints.coffee
@@ -165,4 +165,14 @@
   url:    (x) -> "/order/#{x.id ? x}/payments"
   expects:  statusOk

+blueprints.organization =
+  get:
+    url:     (x) -> "/c/organization/#{x.id ? x}"
+    method:  'GET'
+    expects: statusOk
+  update:
+    url:     (x) -> "/c/organization/#{x.id ? x}"
+    method:  'PATCH'
+    expects: statusOk
+
 export default blueprints


fix typo

fix typo

--- scripts/gh-book/toc-node.coffee
+++ scripts/gh-book/toc-node.coffee
@@ -7,8 +7,8 @@
   'cs!gh-book/uuid'
   'cs!models/content/inherits/saveable'
   'cs!mixins/tree'
+  'models/path'
 ], (Backbone, _, $, allContent, XhtmlFile, uuid, SaveableModel, treeMixin, Path) ->
-  'models/path'

   mediaType = 'application/vnd.org.cnx.section'


List.js search and sort reset working

List.js search and sort reset working

--- app/assets/javascripts/categories.js.coffee
+++ app/assets/javascripts/categories.js.coffee
@@ -5,4 +5,5 @@
   tag_list = new List('js_tag_list', options)

   $(".reset").click  ->
-    tag_list.filter()+    tag_list.search()
+    tag_list.sort('watcher_count', {asc: false})


LOL YOU CAN NAVIGATE CLOUD!??!

LOL YOU CAN NAVIGATE CLOUD!??!

--- app/assets/javascripts/views/root.js.coffee
+++ app/assets/javascripts/views/root.js.coffee
@@ -52,7 +52,31 @@

     session.get('user').bind 'change', (user) =>
       @refreshGfx()
-
+
+    $(document).bind 'keydown', (e) =>
+
+      if e.target.tagName == "BODY"
+
+        activeToggle = @.$('.cloud-toggle.active')
+
+        if ((e.keyCode == 38) or (e.keyCode == 40)) and e.shiftKey
+
+          if e.keyCode == 40
+            next = activeToggle.next()
+            if next.length > 0
+              id = next.attr('data-cloud-id')
+              Backbone.history.navigate("/clouds/#{id}",true)
+
+          if e.keyCode == 38
+            prev = activeToggle.prev()
+            if prev.length > 0
+              id = prev.attr('data-cloud-id')
+              Backbone.history.navigate("/clouds/#{id}",true)
+
+
+
+
+
   refreshGfx: ->
     if session.isLoggedIn()
       $(@el).addClass('with-active-session')


Code cleaning on common/lightboxes.coffee

--- app/coffee/modules/common/lightboxes.coffee
+++ app/coffee/modules/common/lightboxes.coffee
@@ -16,99 +16,109 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 #
-# File: modules/lightboxes.coffee
+# File: modules/common/lightboxes.coffee
 ###

 module = angular.module("taigaCommon")

 bindOnce = @.taiga.bindOnce
+timeout = @.taiga.timeout
+
+#############################################################################
+## Common Lightbox Services
+#############################################################################

 class LightboxService extends taiga.Service
-    open: (lightbox) ->
-        lightbox.css('display', 'flex')
-
-        setTimeout ( ->
-            lightbox.addClass('open')
-        ), 70
-
-        $(document)
-            .on 'keydown.lightbox', (e) =>
-                code = if e.keyCode then e.keyCode else e.which
-
-                if code == 27
-                    @close(lightbox)
-
-    close: (lightbox) ->
-        $(document).off('.lightbox')
-        lightbox
-            .one "transitionend", () ->
-                lightbox.css('display', 'none')
-            .removeClass('open')
+    open: ($el) ->
+        $el.css('display', 'flex')
+        timeout(70, -> $el.addClass("open"))
+
+        docEl = angular.element(document)
+        docEl.on "keydown.lightbox", (e) =>
+            code = if e.keyCode then e.keyCode else e.which
+            @.close($el) if code == 27
+
+    close: ($el) ->
+        docEl = angular.element(document)
+        docEl.off(".lightbox")
+
+        $el.one "transitionend", =>
+            $el.css('display', 'none')
+
+        $el.removeClass("open")

 module.service("lightboxService", LightboxService)

+
+class LightboxKeyboardNavigationService extends taiga.Service
+    stop: ->
+        docEl = angular.element(document)
+        docEl.off(".keyboard-navigation")
+
+    dispatch: ($el, code) ->
+        activeElement = $el.find(".active")
+
+        # Key: enter
+        if code == 13
+            activeElement.trigger("click")
+
+        # Key: down
+        else if code == 40
+            if not activeElement.length
+                $el.find('.watcher-single:first').addClass('active')
+            else
+                next = activeElement.next('.watcher-single')
+                if next.length
+                    activeElement.removeClass('active')
+                    next.addClass('active')
+        # Key: up
+        else if code == 38
+            if not activeElement.length
+                $el.find('.watcher-single:last').addClass('active')
+            else
+                prev = activeElement.prev('.watcher-single')
+
+                if prev.length
+                    activeElement.removeClass('active')
+                    prev.addClass('active')
+
+    init: ($el) ->
+        docEl = angular.element(document)
+        docEl.on "keydown.keyboard-navigation", (event) =>
+            code = if event.keyCode then event.keyCode else event.which
+            if code == 40 || code == 38 || code == 13
+                event.preventDefault()
+                @.dispatch($el, code)
+
+module.service("lightboxKeyboardNavigationService", LightboxKeyboardNavigationService)
+
+#############################################################################
+## Generic Lighthbox Directive
+#############################################################################
+
+# This adds generic behavior to all blocks with lightbox class like
+# close button event handlers.

 LightboxDirective = (lightboxService) ->
     link = ($scope, $el, $attrs) ->
         $el.on "click", ".close", (event) ->
             event.preventDefault()
-
             lightboxService.close($el)

-    return {
-        restrict: "C",
-        link: link
-    }
+    return {restrict: "C", link: link}

 module.directive("lightbox", ["lightboxService", LightboxDirective])

-class LightboxListNavigationService
-    stop: () ->
-        $(document).off "keydown.list-navigation"
-
-    init: ($el) ->
-        $(document).on "keydown.list-navigation", (e) =>
-            code = if e.keyCode then e.keyCode else e.which
-
-            if code == 40 || code == 38 || code == 13
-                e.preventDefault()
-
-                active = $el.find('.active')
-
-                if code == 13
-                    active.trigger('click')
-
-                if code == 40
-                    if active.length
-                        next = active.next('.watcher-single')
-
-                        if next.length
-                            active.removeClass('active')
-                            next.addClass('active')
-                    else
-                        $el.find('.watcher-single:first').addClass('active')
-
-                if code == 38
-                    if active.length
-                        prev = active.prev('.watcher-single')
-
-                        if prev.length
-                            active.removeClass('active')
-                            prev.addClass('active')
-                    else
-                        $el.find('.watcher-single:last').addClass('active')
-
-module.service("lightboxListNavigationService", LightboxListNavigationService)
-
-
 #############################################################################
 ## Block Lightbox Directive
 #############################################################################
+
+# Issue/Userstory blocking message lightbox directive.

 BlockLightboxDirective = (lightboxService) ->
     link = ($scope, $el, $attrs, $model) ->
-        title = $attrs.title
-        $el.find("h2.title").text(title)
+        $el.find("h2.title").text($attrs.title)
+
         $scope.$on "block", ->
             lightboxService.open($el)

@@ -121,7 +131,6 @@

         $el.on "click", ".button-green", (event) ->
             event.preventDefault()
-            target = angular.element(event.currentTarget)

             $scope.$apply ->
                 $model.$modelValue.is_blocked = true
@@ -136,7 +145,6 @@
     }

 module.directive("tgLbBlock", ["lightboxService", BlockLightboxDirective])
-

 #############################################################################
 ## Create/Edit Userstory Lightbox Directive
@@ -347,7 +355,7 @@
 <% } %>
 """)

-AssignedToLightboxDirective = (lightboxService, lightboxListNavigationService) ->
+AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationService) ->
     link = ($scope, $el, $attrs) ->
         selectedUser = null
         selectedItem = null
@@ -383,10 +391,10 @@

             html = usersTemplate(ctx)
             $el.find("div.watchers").html(html)
-            lightboxListNavigationService.init($el)
+            lightboxKeyboardNavigationService.init($el)

         closeLightbox = () ->
-            lightboxListNavigationService.stop()
+            lightboxKeyboardNavigationService.stop()
             lightboxService.close($el)

         $scope.$on "assigned-to:add", (ctx, item) ->
@@ -437,14 +445,14 @@
     }

-module.directive("tgLbAssignedto", ["lightboxService", "lightboxListNavigationService", AssignedToLightboxDirective])
+module.directive("tgLbAssignedto", ["lightboxService", "lightboxKeyboardNavigationService", AssignedToLightboxDirective])

 #############################################################################
 ## Watchers Lightbox directive
 #############################################################################

-WatchersLightboxDirective = ($repo, lightboxService, lightboxListNavigationService) ->
+WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationService) ->
     link = ($scope, $el, $attrs) ->
         selectedItem = null

@@ -476,7 +484,7 @@
             $el.find("div.watchers").html(html)

         closeLightbox = () ->
-            lightboxListNavigationService.stop()
+            lightboxKeyboardNavigationService.stop()
             lightboxService.close($el)

         $scope.$on "watcher:add", (ctx, item) ->
@@ -486,7 +494,7 @@
             render(users)

             lightboxService.open($el)
-            lightboxListNavigationService.init($el)
+            lightboxKeyboardNavigationService.init($el)

         $scope.$watch "usersSearch", (searchingText) ->
             if not searchingText?
@@ -521,7 +529,7 @@
         link:link
     }

-module.directive("tgLbWatchers", ["$tgRepo", "lightboxService", "lightboxListNavigationService", WatchersLightboxDirective])
+module.directive("tgLbWatchers", ["$tgRepo", "lightboxService", "lightboxKeyboardNavigationService", WatchersLightboxDirective])

 #############################################################################
 ## Notion Lightbox Directive


Remove return values from method signature

--- src/class-page.coffee
+++ src/class-page.coffee
@@ -50,7 +50,7 @@

   signature: (method) ->
     parameters = if method.arguments then @parameters(method) else ''
-    "#{method.name}(#{parameters})#{returnValues}"
+    "#{method.name}(#{parameters})"

   parameterBlock: (method) ->
     rows = (@parameterRow(parameter) for parameter in method.arguments)
@@ -71,10 +71,3 @@
   parameters: (method) ->
     names = (name for {name} in method.arguments)
     names.join(', ')
-
-  returnValues: (method) ->
-    types = (type ? 'null' for {type} in method.returnValues)
-    if types.length is 1
-      " ⇒ #{types[0]}"
-    else
-      " ⇒ #{types[0...-1].join(', ')} or #{types[-1..]}"


Update pivotal-listener.coffee

Update pivotal-listener.coffee

--- scripts/pivotal-listener.coffee
+++ scripts/pivotal-listener.coffee
@@ -44,7 +44,10 @@
         "Salesforce": "SFDC-",
         "JAM": "JAM-",
         "Business As Usual": "BAU-",
-        "State of the States 2019": "SOTS19-"
+        "State of the States 2019": "SOTS19-",
+        "Kleena": "FFL-K-",
+        "digiBridgeAnalysis": "DBA-",
+        "DigiBridgeEng": "DBE-"

       project =
         projectId: reqBody["project"]["id"]


Agent Cooper +1

Agent Cooper +1

--- scripts/seal-of-approval.coffee
+++ scripts/seal-of-approval.coffee
@@ -17,7 +17,8 @@
  "http://i.imgur.com/3YRs6.gif",
  "http://i.imgur.com/eyo3k.jpg",
  "http://i.imgur.com/xpGee.gif",
- "http://i.imgur.com/PtlSV.gif"
+ "http://i.imgur.com/PtlSV.gif",
+ "http://mlkshk.com/r/AHDT.gif"
 ]

 module.exports = (robot) ->


Update tortoise.coffee

Update tortoise.coffee

--- app/lib/field-guide-content/tortoise.coffee
+++ app/lib/field-guide-content/tortoise.coffee
@@ -4,7 +4,7 @@
     The Bell’s hinged tortoise is a medium-sized tortoise with an elongated carapace and a movable rear hinge. This species is one of only four tortoises in the world to possess this unusual structure. They have tails with a clawlike tip and a small head with a nonprojecting snout. Their color and pattern varies, but they typically bear a pattern of yellow or reddish-brown scutes (thick, horny or bony plates) with dark brown or black edges. Males tend to be more faded in coloration and also possess a larger tail.
   '''

-  scientificName: '(Kinixys belliana)'
+  scientificName: 'Kinixys belliana'
   mainImage: 'assets/fieldguide-content/reptiles/tortoise/bells-tortoise-feature.jpg'

   information: [{
@@ -12,7 +12,7 @@
     value: ': 15-22 cm'
   }, {
     label: 'Weight'
-    value: '1 - 2 kg'
+    value: '1-2 kg'
   }, {
     label: 'Lifespan'
     value: 'Up to 22 years'


Don't abuse integers for boolean logic unnecessarily

--- core/app/assets/javascripts/intermediate.coffee
+++ core/app/assets/javascripts/intermediate.coffee
@@ -42,11 +42,12 @@
       return # don't return anything unless you have a callback on the other site of easyXdm

 showUrl = (url, successFn) ->
-  successCalled = 0
+  successCalled = false
   onLoadSuccess = ->
-    unless successCalled
-      successCalled++
-      successFn()  if $.isFunction(successFn)
+    if !successCalled
+      successCalled = true
+      if $.isFunction(successFn)
+        successFn()

   showFrame.onload = onLoadSuccess
   # Somehow only lower case letters seem to work for those events --mark


Pass options to validator.

Pass options to validator.

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -15,14 +15,14 @@
     client_secret: argv.clientSecret
   timeout: timeout

-validator = new Validator()
+validator = new Validator options

 fs.readFile argv.csv, 'utf8', (err, content) ->
   if err
     console.error "Problems on reading file '#{argv.csv}': " + err
     process.exit 2
   validator.parse content, (data, count) ->
-    errors = validator.validateOffline data
-    process.exit 0 if validator.errors.length is 0
-    console.log validator.errors
-    process.exit 1+    errors = validator.validate data, (then) ->
+      process.exit 0 if validator.errors.length is 0
+      console.log validator.errors
+      process.exit 1


Remove unused import

Remove unused import

--- src/coffee/run.coffee
+++ src/coffee/run.coffee
@@ -5,7 +5,6 @@
 tmp = require 'tmp'
 {Logger, ProjectCredentialsConfig, Qutils} = require 'sphere-node-utils'
 package_json = require '../package.json'
-Logger = require './logger'
 StockImport = require './stockimport'
 SftpHelper = require './sftp'


much more efficient toArray implementation

--- src/collection.coffee
+++ src/collection.coffee
@@ -55,9 +55,7 @@
     new Collection(@toArray().concat(args...))

   toArray: ->
-    array = []
-    array[index] = val for index, val of @ when isArrayIndex(index)
-    array
+    Array::slice.call(this)

   clone: ->
     new Collection(@toArray())


Don't run portNumbers test on arm64

Don't run portNumbers test on arm64

--- test/usb.coffee
+++ test/usb.coffee
@@ -45,7 +45,8 @@
 	it 'should have sane properties', ->
 		assert.ok((device.busNumber > 0), "busNumber must be larger than 0")
 		assert.ok((device.deviceAddress > 0), "deviceAddress must be larger than 0")
-		assert.ok((util.isArray(device.portNumbers)), "portNumbers must be an array")
+		if process.platform != 'darwin' || process.arch != 'arm64'
+			assert.ok((util.isArray(device.portNumbers)), "portNumbers must be an array")

 	it 'should have a deviceDescriptor property', ->
 		assert.ok(((deviceDesc = device.deviceDescriptor) != undefined))


fix authentication in replication

fix authentication in replication

--- server/middlewares/utils.coffee
+++ server/middlewares/utils.coffee
@@ -55,7 +55,7 @@

 # Check the permission for a post request in replication protocol
 module.exports.checkPermissionsPostReplication = (req, res, next) ->
-    if req.url is '/replication/_revs_diff'
+    if req.url.indexOf('/replication/_revs_diff') is 0
         # Use to retrieve difference in documents revisions
         next()
     else if req.url is '/replication/_ensure_full_commit'


fixed webgl error

fixed webgl error

--- src/ubret/sw_viewer.coffee
+++ src/ubret/sw_viewer.coffee
@@ -55,6 +55,7 @@
     # Set parameters
     @stretch = 'linear'
     @collection = new Layers()
+    @ready = false

     # Set various deferred objects to handle asynchronous requests.
     @dfs =
@@ -63,10 +64,7 @@
       r: new $.Deferred()
       i: new $.Deferred()
       z: new $.Deferred()
-
-
     @dfsWebfits = new $.Deferred()
-
     @getApi()

   # Request the appropriate WebFITS API (WebGL or Canvas)
@@ -103,6 +101,8 @@

   # Request FITS files for each channel
   requestChannels: ->
+    @ready = false
+
     @dfsWebfits.then =>
       @initWebFITS()

@@ -149,9 +149,7 @@
   # Initialize a WebFITS object
   initWebFITS: =>
     @wfits?.teardown()
-
     @wfits = new astro.WebFITS(@el, @dimension)
-
     unless @wfits.ctx?
       alert 'Something went wrong initializing the context'

@@ -162,6 +160,7 @@

   # Call when all FITS received and WebFITS library is received
   allChannelsReceived: (e) =>
+    @ready = true

     # Get extent for each layer and add to settings
     mins = @collection.map( (d) -> return d.get('minimum') )
@@ -225,20 +224,20 @@
         @wfits.setStretch(@opts.stretch)

   updateAlpha: =>
-    @wfits?.setAlpha(@opts.alpha)
+    @wfits?.setAlpha(@opts.alpha) if @ready

   updateQ: =>
-    @wfits?.setQ(@opts.q)
+    @wfits?.setQ(@opts.q) if @ready

   updateScale: =>
-    @wfits?.setScales.apply(@wfits, @opts.scales)
+    @wfits?.setScales.apply(@wfits, @opts.scales) if @ready

   updateStretch: =>
     @stretch = @opts.stretch
-    @wfits?.setStretch(@stretch)
+    @wfits?.setStretch(@stretch) if @ready

   updateExtent: =>
-    @wfits?.setExtent(@opts.extent.min, @opts.extent.max)
+    @wfits?.setExtent(@opts.extent.min, @opts.extent.max) if @ready

 window.Ubret.SpacewarpViewer = SpacewarpViewer


Add language-pip to Atom package list

Add language-pip to Atom package list

--- atom/packages.cson
+++ atom/packages.cson
@@ -23,6 +23,7 @@
   "language-liquid"
   "language-lisp"
   "language-pegjs"
+  "language-pip"
   "language-prolog"
   "language-sca"
   "language-svg"


:art:

:art:

--- menus/welcome.cson
+++ menus/welcome.cson
@@ -1,6 +1,6 @@
 'menu': [
   'label': 'Help'
   'submenu': [
-    { 'label': 'Welcome Guide', 'command': 'welcome:show'}
+    {'label': 'Welcome Guide', 'command': 'welcome:show'}
   ]
 ]


fixes specs syntax

fixes specs syntax

--- spec/index.coffee
+++ spec/index.coffee
@@ -52,7 +52,7 @@
         beforeSpy.should.have.been.calledWith {}, true, "123"
       it 'should pass the parameters to the original function', ->
         @maypop {}, true, "123"
-        @original.should.have.beenCalledWith {}, true, "123"
+        @original.should.have.been.calledWith {}, true, "123"
       it 'should receive the returned value of the original function on "after"', ->
         afterSpy = sinon.spy()
         @maypop.after(afterSpy)


Remove spaces around parens in PHP function snippet

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -144,7 +144,7 @@

   'function':
     'prefix': 'f'
-    'body': "function ${1:name}( $2 ) {\n\t$3\n}"
+    'body': "function ${1:name}($2) {\n\t$3\n}"

   'if':
     'prefix': 'if'


Simplify require snippet to the require call only

The old require snippet mostly consisted of tab stops that the user
would have to type over anyway.

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -235,7 +235,7 @@

   'require':
     'prefix': 're'
-    'body': '${1:var} ${2:vname} = require(\'${3:mname}\');$4'
+    'body': 'require(\'${1:mname}\');$4'

   'module.exports':
     'prefix': 'moduleexports'


Changes on grunt file (core, organisms & templates builds)

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -57,7 +57,10 @@

     jasmine:
         pivotal:
-          src: '<%=meta.build%>/<%=pkg.name%>.debug.js'
+          src: [
+            '<%=meta.build%>/<%=pkg.name%>.debug.js',
+            '<%=meta.build%>/<%=pkg.name%>.organisms.js',
+            '<%=meta.build%>/<%=pkg.name%>.templates.js']
           options:
             vendor: 'spec/components/jquery/jquery.js'
             specs: '<%=meta.build%>/<%=pkg.name%>.spec.js',


Change the API host

Change the API host

--- app/api/config.coffee
+++ app/api/config.coffee
@@ -1,7 +1,7 @@
 DEFAULT_ENV = 'staging'

 API_HOSTS =
-  production: 'https://panoptes.zooniverse.org'
+  production: 'https://www.zooniverse.org'
   staging: 'https://panoptes-staging.zooniverse.org'
   cam: 'http://172.17.2.87:3000'


Added mochaTest task

Added mochaTest task

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -14,6 +14,11 @@
           src: ['test/*.coffee']
           ext: '.js'
         }]
+    mochaTest:
+      options:
+        reporter: 'spec'
+      test:
+        src: ['test/**/*.js']
     uglify:
       options:
         banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("dd-mm-yyyy") %> */\n'
@@ -25,5 +30,5 @@

   require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks)

-  grunt.registerTask 'test', 'Lints and unit tests', ['coffeelint']
-  grunt.registerTask 'default', 'Default task', ['test', 'coffee', 'uglify']+  grunt.registerTask 'test', 'Lints and unit tests', ['coffeelint', 'mochaTest']
+  grunt.registerTask 'default', 'Default task', ['coffee', 'test', 'uglify']


Reorder grunt.tasks

Reorder grunt.tasks

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -4,216 +4,219 @@
     component   : grunt.file.readJSON 'bower/component.json'

     meta:
-      build     : 'build',
-      bower     : 'bower',
-      extensions: 'extensions',
       version   : '',
       banner    : '/* <%= pkg.name %> v<%= grunt.template.today("0.mm.dd") %>\n' +
                 '   <%= pkg.homepage %>\n' +
                 '   Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>' +
                 ' - Licensed <%= _.pluck(pkg.license, "type").join(", ") %> */\n'
-    source:
-      # CoffeeScript
-      core: [
-        'components/quojs/source/quo.coffee'
-        'components/quojs/source/quo.ajax.coffee'
-        'components/quojs/source/quo.css.coffee'
-        'components/quojs/source/quo.element.coffee'
-        'components/quojs/source/quo.environment.coffee'
-        'components/quojs/source/quo.events.coffee'
-        'components/quojs/source/quo.gestures.coffee'
-        'components/quojs/source/quo.gestures.*.coffee'
-        'components/quojs/source/quo.output.coffee'
-        'components/quojs/source/quo.query.coffee'
+
+    folder:
+      build : 'build/'
+      bower : 'bower/'
+      app   : 'extensions/app/'
+      icons : 'extensions/icons/'
+      test  : 'extensions/test/source/'
+      quo   : 'components/quojs/source/'
+
+    core:
+      coffee: [
+        '<%=folder.quo%>quo.coffee'
+        '<%=folder.quo%>quo.ajax.coffee'
+        '<%=folder.quo%>quo.css.coffee'
+        '<%=folder.quo%>quo.element.coffee'
+        '<%=folder.quo%>quo.environment.coffee'
+        '<%=folder.quo%>quo.events.coffee'
+        '<%=folder.quo%>quo.gestures.coffee'
+        '<%=folder.quo%>quo.gestures.*.coffee'
+        '<%=folder.quo%>quo.output.coffee'
+        '<%=folder.quo%>quo.query.coffee'
         'source/*.coffee'
         'source/core/*.coffee'
         'source/class/*.coffee']
-      app: [
-        'extensions/app/*.coffee'
-        'extensions/app/atom/*.coffee'
-        'extensions/app/molecule/*.coffee'
-        'extensions/app/organism/*.coffee']
-
-      spec  : [
+      spec: [
         'spec/*.coffee']
-      example:
-          app: [
-            'extensions/test/source/entities/*.coffee'
-            'extensions/test/source/atoms/*.coffee'
-            'extensions/test/source/molecules/*.coffee'
-            'extensions/test/source/organisms/*.coffee'
-            'extensions/test/source/*.coffee']
-
-      extensions:
-        app     : []
-        appnima : ['extensions/appnima/**/*.coffee']
-        carousel: ['extensions/carousel/**/*.coffee']
-        gmaps   : ['extensions/gmaps/**/*.coffee']
-
-      # Stylesheets
-      stylus:
-        app: [
-          'extensions/app/style/reset.styl'
-          'extensions/app/style/atom.*.styl'
-          'extensions/app/style/molecule.*.styl'
-          'extensions/app/style/organism.*.styl'
-          'extensions/app/style/app.styl']
-        theme: [
-          'extensions/app/style/theme/reset.styl'
-          'extensions/app/style/theme/atom.*.styl'
-          'extensions/app/style/theme/molecule.*.styl'
-          'extensions/app/style/theme/organism.*.styl'
-          'extensions/app/style/theme/app.styl'
-        ]
-        icons: [
-          'extensions/icons/*.styl']
-        app_appnima: [
-          'extensions/appnima/style/*.styl']
-        app_carousel: [
-          'extensions/carousel/style/*.styl']
-        app_gmaps: [
-          'extensions/gmaps/style/*.styl']
+      test: [
+        '<%=folder.test%>entities/*.coffee'
+        '<%=folder.test%>atoms/*.coffee'
+        '<%=folder.test%>molecules/*.coffee'
+        '<%=folder.test%>organisms/*.coffee'
+        '<%=folder.test%>*.coffee']
+
+    app:
+      coffee: [
+        '<%=folder.app%>*.coffee'
+        '<%=folder.app%>atom/*.coffee'
+        '<%=folder.app%>molecule/*.coffee'
+        '<%=folder.app%>organism/*.coffee']
+      stylus: [
+        '<%=folder.app%>style/reset.styl'
+        '<%=folder.app%>style/atom.*.styl'
+        '<%=folder.app%>style/molecule.*.styl'
+        '<%=folder.app%>style/organism.*.styl'
+        '<%=folder.app%>style/app.styl']
+      theme: [
+        '<%=folder.app%>style/theme/reset.styl'
+        '<%=folder.app%>style/theme/atom.*.styl'
+        '<%=folder.app%>style/theme/molecule.*.styl'
+        '<%=folder.app%>style/theme/organism.*.styl'
+        '<%=folder.app%>style/theme/app.styl']
+
+      extension:
+        appnima:
+          coffee: '<%=folder.app%>extension/appnima/**/*.coffee'
+          stylus: '<%=folder.app%>extension/appnima/style/*.styl'
+        carousel:
+          coffee: '<%=folder.app%>extension/carousel/**/*.coffee'
+          stylus: '<%=folder.app%>extension/carousel/style/*.styl'
+        gmaps:
+          coffee: '<%=folder.app%>extension/gmaps/**/*.coffee'
+          stylus: '<%=folder.app%>extension/gmaps/style/*.styl'
+
+    icons:
+      stylus: 'extensions/icons/*.styl'

     doc:
-      es: ['extensions/app/docs/ES/*.md']
-
+      es: 'extensions/app/docs/ES/*.md'
+
+    # ==========================================================================
+    # TASKS
+    # ==========================================================================
     concat:
-      core        : files: '<%=meta.build%>/<%=pkg.name%>.debug.coffee'         : '<%= source.core %>'
-      # Extension
-      app         : files: '<%=meta.build%>/<%=pkg.name%>.app.coffee'           : '<%= source.app %>'
-      app_appnima : files: '<%=meta.build%>/<%=pkg.name%>.app.appnima.coffee'   : '<%= source.extensions.appnima %>'
-      app_carousel: files: '<%=meta.build%>/<%=pkg.name%>.app.carousel.coffee'  : '<%= source.extensions.carousel %>'
-      app_gmaps   : files: '<%=meta.build%>/<%=pkg.name%>.app.gmaps.coffee'     : '<%= source.extensions.gmaps %>'
-      # Example
-      example_app : files: '<%=meta.build%>/<%=pkg.name%>.example.app.coffee'   : '<%= source.example.app %>'
-
+      core        : files: '<%=folder.build%>core.coffee'                       : '<%= core.coffee %>'
+      # App
+      app         : files: '<%=folder.build%>app.coffee'                        : '<%= app.coffee %>'
+      app_appnima : files: '<%=folder.build%>app.appnima.coffee'                : '<%= app.extension.appnima.coffee %>'
+      app_carousel: files: '<%=folder.build%>app.carousel.coffee'               : '<%= app.extension.carousel.coffee %>'
+      app_gmaps   : files: '<%=folder.build%>app.gmaps.coffee'                  : '<%= app.extension.gmaps.coffee %>'
+      # Test
+      test        :   files: '<%=folder.build%>test.coffee'                     : '<%= core.test %>'

     coffee:
-      core        : files: '<%=meta.build%>/<%=pkg.name%>.debug.js'             : '<%=meta.build%>/<%=pkg.name%>.debug.coffee'
-      spec        : files: '<%=meta.build%>/<%=pkg.name%>.spec.js'              : '<%= source.spec %>'
-      # Extension
-      app         : files: '<%=meta.build%>/<%=pkg.name%>.app.debug.js'         : '<%=meta.build%>/<%=pkg.name%>.app.coffee'
-      app_appnima : files: '<%=meta.build%>/<%=pkg.name%>.app.appnima.js'       : '<%=meta.build%>/<%=pkg.name%>.app.appnima.coffee'
-      app_carousel: files: '<%=meta.build%>/<%=pkg.name%>.app.carousel.js'      : '<%=meta.build%>/<%=pkg.name%>.app.carousel.coffee'
-      app_gmaps   : files: '<%=meta.build%>/<%=pkg.name%>.app.gmaps.js'         : '<%=meta.build%>/<%=pkg.name%>.app.gmaps.coffee'
-      # Example
-      example_app : files: '<%=meta.build%>/<%=pkg.name%>.example.app.js'       : '<%=meta.build%>/<%=pkg.name%>.example.app.coffee'
-
+      core        : files: '<%=folder.build%>core.js'                           : '<%=folder.build%>core.coffee'
+      spec        : files: '<%=folder.build%>spec.js'                           : '<%= core.spec %>'
+      # App
+      app         : files: '<%=folder.build%>app.js'                            : '<%=folder.build%>app.coffee'
+      app_appnima : files: '<%=folder.build%>app.appnima.js'                    : '<%=folder.build%>app.appnima.coffee'
+      app_carousel: files: '<%=folder.build%>app.carousel.js'                   : '<%=folder.build%>app.carousel.coffee'
+      app_gmaps   : files: '<%=folder.build%>app.gmaps.js'                      : '<%=folder.build%>app.gmaps.coffee'
+      # Test
+      test        : files: '<%=folder.build%>test.js'                           : '<%=folder.build%>test.coffee'

     uglify:
       options:  banner: "<%= meta.banner %>"#, report: "gzip"
       core:
         options: mangle: true
-        files: '<%=meta.bower%>/<%=pkg.name%>.js'                               : '<%=meta.build%>/<%=pkg.name%>.debug.js'
-      # Extensions
+        files: '<%=folder.bower%><%=pkg.name%>.js'                              : '<%=folder.build%>core.js'
+      # App
       app:
         options: mangle: false
-        files: '<%=meta.bower%>/<%=pkg.name%>.app.js'                           : '<%=meta.build%>/<%=pkg.name%>.app.debug.js'
+        files: '<%=folder.bower%><%=pkg.name%>.app.js'                          : '<%=folder.build%>app.js'
       app_appnima:
         options: mangle: false
-        files: '<%=meta.extensions%>/appnima/<%=pkg.name%>.app.appnima.js'      : '<%=meta.build%>/<%=pkg.name%>.app.appnima.js'
+        files: '<%=folder.app%>extension/appnima/<%=pkg.name%>.app.appnima.js'  : '<%=folder.build%>app.appnima.js'
       app_carousel:
         options: mangle: false
-        files: '<%=meta.extensions%>/carousel/<%=pkg.name%>.app.carousel.js'    : '<%=meta.build%>/<%=pkg.name%>.app.carousel.js'
+        files: '<%=folder.app%>extension/carousel/<%=pkg.name%>.app.carousel.js': '<%=folder.build%>app.carousel.js'
       app_gmaps:
         options: mangle: false
-        files: '<%=meta.extensions%>/gmaps/<%=pkg.name%>.app.gmaps.js'          : '<%=meta.build%>/<%=pkg.name%>.app.gmaps.js'
-
+        files: '<%=folder.app%>extension/gmaps/<%=pkg.name%>.app.gmaps.js'      : '<%=folder.build%>app.gmaps.js'

     copy:
       doc_es:
         expand  : true
         flatten : true
         src     : '<%= doc.es %>'
-        dest    : '<%= meta.bower %>/docs/ES/'
-
+        dest    : '<%= folder.bower %>/docs/ES/'

     jasmine:
       pivotal:
-        src: [
-          '<%=meta.build%>/<%=pkg.name%>.debug.js']
+        src: '<%=folder.build%>core.js'
         options:
           vendor: 'spec/components/jquery/jquery.min.js'
-          specs: '<%=meta.build%>/<%=pkg.name%>.spec.js',
-
+          specs: '<%=folder.build%>spec.js',

     stylus:
-      app:
+      # App
+      app_stylus:
         options: compress: true, import: [ '__init']
-        files: '<%=meta.bower%>/<%=pkg.name%>.app.css'                          : '<%=source.stylus.app%>'
-      theme:
+        files: '<%=folder.bower%><%=pkg.name%>.app.css'                         : '<%=app.stylus%>'
+      app_theme:
         options: compress: false, import: [ '__init']
-        files: '<%=meta.bower%>/<%=pkg.name%>.app.theme.css'                    : '<%=source.stylus.theme%>'
+        files: '<%=folder.bower%><%=pkg.name%>.app.theme.css'                   : '<%=app.theme%>'
+      app_appnima:
+        options: compress: true
+        files: '<%=folder.app%>extension/appnima/<%=pkg.name%>.app.appnima.css' : '<%=app.extension.appnima.stylus%>'
+      app_carousel:
+        options: compress: true
+        files: '<%=folder.app%>extension/carousel/<%=pkg.name%>.app.carousel.css': '<%=app.extension.carousel.stylus%>'
+      app_gmaps:
+        options: compress: true
+        files: '<%=folder.app%>extension/gmaps/<%=pkg.name%>.app.gmaps.css'     : '<%=app.extension.gmaps.stylus%>'
+      # Icons
       icons:
         options: compress: true
-        files: '<%=meta.extensions%>/icons/<%=pkg.name%>.icons.css'             : '<%=source.stylus.icons%>'
-      app_appnima:
-        options: compress: true
-        files: '<%=meta.extensions%>/appnima/<%=pkg.name%>.app.appnima.css'     : '<%=source.stylus.app_appnima%>'
-      app_carousel:
-        options: compress: true
-        files: '<%=meta.extensions%>/carousel/<%=pkg.name%>.app.carousel.css'   : '<%=source.stylus.app_carousel%>'
-      app_gmaps:
-        options: compress: true
-        files: '<%=meta.extensions%>/gmaps/<%=pkg.name%>.app.gmaps.css'         : '<%=source.stylus.app_gmaps%>'
-
+        files: '<%=folder.icons%>icons/<%=pkg.name%>.icons.css'                 : '<%=icons.stylus%>'

     notify:
       core:
         options: title: 'atoms.js', message: 'grunt:uglify:core'
+      spec:
+        options: title: 'Atoms Spec', message: 'grunt:jasmine'
       app:
         options: title: 'atoms.app.js', message: 'grunt:uglify:app'
-      stylus_app:
+      app_stylus:
         options: title: 'atoms.app.css', message: 'grunt:stylus:app'
-      stylus_theme:
+      app_theme:
         options: title: 'atoms.app.theme.css', message: 'grunt:stylus:theme'
-      spec:
-        options: title: 'Atoms Spec', message: 'grunt:jasmine'
-

     watch:
       core:
-        files: ['<%= source.core %>']
-        tasks: ['concat:core', 'coffee:core', 'uglify:core']#, 'jasmine', 'notify:core']
+        files: ['<%= core.coffee %>']
+        tasks: ['concat:core', 'coffee:core', 'uglify:core', 'jasmine', 'notify:core']
       spec:
-        files: ['<%= source.spec %>']
+        files: ['<%= core.spec %>']
         tasks: ['coffee:spec', 'jasmine', 'notify:spec']
-      app:
-        files: ['<%= source.app %>']
+      test:
+        files: ['<%= core.test %>']
+        tasks: ['concat:test', 'coffee:test']
+      # App
+      app_coffee:
+        files: ['<%= app.coffee %>']
         tasks: ['concat:app', 'coffee:app', 'uglify:app', 'notify:app']
+      app_stylys:
+        files: ['<%= app.stylus %>']
+        tasks: ['stylus:app_stylus', 'notify:app_stylus']
+      app_theme:
+        files: ['<%= app.theme %>']
+        tasks: ['stylus:app_theme', 'notify:app_theme']
+      # App.Extension
       app_appnima:
-        files: ['<%= source.extensions.appnima %>']
+        files: ['<%= app.extension.appnima.coffee %>']
         tasks: ['concat:app_appnima', 'coffee:app_appnima', 'uglify:app_appnima']
       app_carousel:
-        files: ['<%= source.extensions.carousel %>']
+        files: ['<%= app.extension.carousel.coffee %>']
         tasks: ['concat:app_carousel', 'coffee:app_carousel', 'uglify:app_carousel']
       app_gmaps:
-        files: ['<%= source.extensions.gmaps %>']
+        files: ['<%= app.extension.gmaps.coffee %>']
         tasks: ['concat:app_gmaps', 'coffee:app_gmaps', 'uglify:app_gmaps']
-      stylus_app:
-        files: ['<%= source.stylus.app %>']
-        tasks: ['stylus:app', 'notify:stylus_app']
-      stylus_theme:
-        files: ['<%= source.stylus.theme %>']
-        tasks: ['stylus:theme', 'notify:stylus_theme']
-      stylus_icons:
-        files: ['<%= source.stylus.icons %>']
+      app_appnima_stylus:
+        files: ['<%= app.extension.appnima.stylus %>']
+        tasks: ['stylus:app_appnima']
+      app_carousel_stylus:
+        files: ['<%= app.extension.carousel.stylus %>']
+        tasks: ['stylus:app_carousel']
+      app_gmaps_stylus:
+        files: ['<%= app.extension.gmaps.stylus %>']
+        tasks: ['stylus:app_gmaps']
+      # Icons
+      icons:
+        files: ['<%= icons.stylus %>']
         tasks: ['stylus:icons']
-      stylus_app_appnima:
-        files: ['<%= source.stylus.app_appnima %>']
-        tasks: ['stylus:app_appnima']
-      stylus_app_carousel:
-        files: ['<%= source.stylus.app_carousel %>']
-        tasks: ['stylus:app_carousel']
-      stylus_app_gmaps:
-        files: ['<%= source.stylus.app_gmaps %>']
-        tasks: ['stylus:app_gmaps']
+      # Docs
       doc_es:
         files: ['<%= doc.es %>']
         tasks: ['copy:doc_es']
-      example_app:
-        files: ['<%= source.example.app %>']
-        tasks: ['concat:example_app', 'coffee:example_app']
+

   grunt.loadNpmTasks 'grunt-contrib-concat'
   grunt.loadNpmTasks 'grunt-contrib-coffee'


Include the auditor gui in the build

Include the auditor gui in the build

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -20,8 +20,28 @@
             'Standards/**/*.js'
             'HTMLCS.js'
             'PhantomJS/runner.js'
+            'Auditor/HTMLCSAuditor.js'
           ]

+    copy:
+      dist:
+        files: [
+          {
+            expand: true
+            flatten: true,
+            src: 'Auditor/HTMLCSAuditor.css'
+            rename: (dest, src) -> dest + '/HTMLCS.css'
+            dest: 'dist'
+            filter: 'isFile'
+          },
+          {
+            expand: true
+            flatten: true,
+            src: 'Auditor/Images/*'
+            dest: 'dist/Images'
+            filter: 'isFile'
+          }
+        ]
     watch:
       jade:
         files: ['<%= jshint.all %>']
@@ -30,4 +50,4 @@
   require('load-grunt-tasks') grunt

   grunt.registerTask 'default', ['jshint']
-  grunt.registerTask 'build',   ['uglify:dist']+  grunt.registerTask 'build',   ['uglify:dist', 'copy:dist']


Attribute data type returned as number

Attribute data type returned as number

--- src/demo-model.coffee
+++ src/demo-model.coffee
@@ -115,7 +115,7 @@
                               max_warning: '50'
                               max_alarm: '70'
                             }),
-                            tangojs.tango.AttributeDataType.ATT_DOUBLE)
+                            tangojs.tango.AttributeDataType.ATT_DOUBLE.value)
     string: createAttribute(undefined,
                             'string'
                             undefined,
@@ -126,7 +126,7 @@
                             undefined,
                             undefined,
                             null,
-                            tangojs.tango.AttributeDataType.ATT_STRING)
+                            tangojs.tango.AttributeDataType.ATT_STRING.value)
     sine_trend: (->
       name = 'sine_trend'
       format = 'scientific,setprecision(3)'
@@ -140,7 +140,7 @@
                              undefined,
                              undefined,
                              null,
-                             tangojs.tango.AttributeDataType.ATT_DOUBLE)
+                             tangojs.tango.AttributeDataType.ATT_DOUBLE.value)
       attr.get_value = ->
         value = Math.sin((new Date()).getTime()/1000.0)
         createDeviceAttributeStruct(name, format, value)
@@ -156,7 +156,7 @@
                              undefined,
                              undefined,
                              null,
-                             tangojs.tango.AttributeDataType.ATT_BOOL)
+                             tangojs.tango.AttributeDataType.ATT_BOOL.value)
     spectrum: createAttribute(([1..10].map (_i) -> Math.random()),
                               'spectrum'
                               undefined,
@@ -167,39 +167,39 @@
                               undefined,
                               undefined,
                               null,
-                              tangojs.tango.AttributeDataType.ATT_DOUBLE)
+                              tangojs.tango.AttributeDataType.ATT_DOUBLE.value)

   commands:
     double_arg: createCommand(((x) -> 2*x),
                               'double',
                               tangojs.tango.DispLevel.OPERATOR,
-                              tangojs.tango.AttributeDataType.ATT_DOUBLE,
-                              tangojs.tango.AttributeDataType.ATT_DOUBLE)
+                              tangojs.tango.AttributeDataType.ATT_DOUBLE.value,
+                              tangojs.tango.AttributeDataType.ATT_DOUBLE.value)
     to_upper: createCommand(((x) -> x.toUpperCase()),
                             'to_upper',
                             tangojs.tango.DispLevel.OPERATOR,
-                            tangojs.tango.AttributeDataType.ATT_NO_DATA,
-                            tangojs.tango.AttributeDataType.ATT_NO_DATA)
+                            tangojs.tango.AttributeDataType.ATT_NO_DATA.value,
+                            tangojs.tango.AttributeDataType.ATT_NO_DATA.value)
     goto_on: createCommand((-> _state = tangojs.tango.DevState.ON),
                            'goto_on',
                            tangojs.tango.DispLevel.OPERATOR,
-                           tangojs.tango.AttributeDataType.ATT_NO_DATA,
-                           tangojs.tango.AttributeDataType.ATT_NO_DATA)
+                           tangojs.tango.AttributeDataType.ATT_NO_DATA.value,
+                           tangojs.tango.AttributeDataType.ATT_NO_DATA.value)
     goto_off: createCommand((-> _state = tangojs.tango.DevState.OFF),
                             'goto_off',
                             tangojs.tango.DispLevel.OPERATOR,
-                            tangojs.tango.AttributeDataType.ATT_NO_DATA,
-                            tangojs.tango.AttributeDataType.ATT_NO_DATA)
+                            tangojs.tango.AttributeDataType.ATT_NO_DATA.value,
+                            tangojs.tango.AttributeDataType.ATT_NO_DATA.value)
     goto_fault: createCommand((-> _state = tangojs.tango.DevState.FAULT),
                               'goto_fault',
                               tangojs.tango.DispLevel.OPERATOR,
-                              tangojs.tango.AttributeDataType.ATT_NO_DATA,
-                              tangojs.tango.AttributeDataType.ATT_NO_DATA)
+                              tangojs.tango.AttributeDataType.ATT_NO_DATA.value,
+                              tangojs.tango.AttributeDataType.ATT_NO_DATA.value)
     goto_alarm: createCommand((-> _state = tangojs.tango.DevState.ALARM),
                               'goto_off',
                               tangojs.tango.DispLevel.OPERATOR,
-                              tangojs.tango.AttributeDataType.ATT_NO_DATA,
-                              tangojs.tango.AttributeDataType.ATT_NO_DATA)
+                              tangojs.tango.AttributeDataType.ATT_NO_DATA.value,
+                              tangojs.tango.AttributeDataType.ATT_NO_DATA.value)

 ###*
  * @private


Extract penetration updates into function

--- app/js/physics.coffee
+++ app/js/physics.coffee
@@ -540,23 +540,15 @@
     [linearMove, angularMove] = @calculateMove @from, moveRatio
     linearChange   = @from.changePosition @normal, linearMove
     rotationChange = @from.rotateByImpulse @position, @normal, angularMove
-
     if @related
-      rotationDistance = Vec.scale Vec.perpendicular(@from.relativePositionAt(@related.position)), rotationChange
-      deltaPosition = Vec.add linearChange, rotationDistance
-      relativeChange = Vec.dotProduct @related.normal, deltaPosition
-      @related.depth -= relativeChange
+      @related.updatePenetration linearChange, rotationChange, @from, -1

     if @to
       [linearMove, angularMove] = @calculateMove @to, moveRatio
       linearChange = @to.changePosition @normal, -linearMove
       rotationChange = @to.rotateByImpulse @position, @normal, -angularMove
-
       if @related
-        rotationDistance = Vec.scale Vec.perpendicular(@to.relativePositionAt(@related.position)), rotationChange
-        deltaPosition = Vec.add linearChange, rotationDistance
-        relativeChange = Vec.dotProduct @related.normal, deltaPosition
-        @related.depth += relativeChange
+        @related.updatePenetration linearChange, rotationChange, @to, 1

     @depth = 0

@@ -580,6 +572,13 @@

     [linearMove, angularMove]

+  updatePenetration: (linearChange, rotationChange, referenceBody, sign) ->
+    relativePosition = referenceBody.relativePositionAt(@position)
+    rotationDistance = Vec.scale Vec.perpendicular(relativePosition), rotationChange
+    deltaPosition = Vec.add linearChange, rotationDistance
+    relativeChange = Vec.dotProduct @normal, deltaPosition
+    @depth += relativeChange * sign
+
 window.Rotation = Rotation =
   fromAngle: (angle) -> [Math.cos(angle), Math.sin(angle)]
   add: ([a,b],[c,d]) -> [a*c - b*d, a*d + c*b]


Id updates

Id updates


Fixed missing back button in event details page by replacing url encoded colon with actual colon (:) in regular expression

--- src/models.coffee
+++ src/models.coffee
@@ -932,7 +932,7 @@
             data

         getUnit: () ->
-            unitId = @get('location')['@id'].match(/^.*tprek%3A(\d+)/)
+            unitId = @get('location')['@id'].match(/^.*tprek:(\d+)/)
             unless unitId?
                 return null
             return new models.Unit id: unitId[1]


Ensure a generated module method accepts an argument.

--- src/module.coffee
+++ src/module.coffee
@@ -12,7 +12,14 @@
     # Cache responses by default.
     @options.cache = true if typeof @options.cache is 'undefined'

-  run: (done) =>
+    # Build our own `run` instance-method to accurately reflect the fact that
+    # `run` is always asynchronous and requires an argument to declare itself
+    # as such to our API. This feels a bit hacky, but using CoffeeScript's `=>`
+    # in `_Method.prototype` creates a zero argument function when compiled.
+    @run = (done) =>
+      _Method::run.apply @, arguments
+
+  run: (done) ->
     return done null, @results if @results

     # If the method accepts an argument, it is asynchronous.


ghetto fabulous redition of the output optionally with line numbers, as a table, also added classes to the markup

--- src/highlights.coffee
+++ src/highlights.coffee
@@ -65,31 +65,74 @@
   # Returns a String of HTML. The HTML will contains one
 with one

   # per line and each line will contain one or more  elements for the
   # tokens in the line.
-  highlightSync: ({filePath, fileContents, scopeName}={}) ->
+  highlightSync: ({filePath,
+                   fileContents,
+                   scopeName,
+                   startingLineNum,
+                   idHandle}={}) ->
     @loadGrammarsSync()

     fileContents ?= fs.readFileSync(filePath, 'utf8') if filePath
     grammar = @registry.grammarForScopeName(scopeName)
     grammar ?= @registry.selectGrammar(filePath, fileContents)
     lineTokens = grammar.tokenizeLines(fileContents)
+    if startingLineNum
+      useLineNums = true
+      lineNum = startingLineNum
+      useNumAnchor = !!idHandle
+    else
+      useLineNums = false
+      lineNum = NaN

+    console.log('useline numes:', useLineNums, lineNum)
     # Remove trailing newline
     if lineTokens.length > 0
       lastLineTokens = lineTokens[lineTokens.length - 1]
       if lastLineTokens.length is 1 and lastLineTokens[0].value is ''
         lineTokens.pop()

-    html = '
'
+    html = '
'
+      html += '

'
+      trCssClasses = 'highlight-numbered-line'
+      if useNumAnchor
+        trCssClasses += ' code-is-anchored'
+      else
+    else
+      html += ' without-line-numbers">'
+
     for tokens in lineTokens
       scopeStack = []
-      html += '
'
+      if useLineNums
+        html += """
+

+            """
+        if useNumAnchor
+          html += """
+
+            """
+        html += """
+
+          """
+      else
+        html += '
'
       for {scopes, value} in tokens
         value = ' ' unless value
         html = @updateScopeStack(scopeStack, scopes, html)
         html += "#{@escapeString(value)}"
       html = @popScope(scopeStack, html) while scopeStack.length > 0
-      html += '
'
+      if useLineNums
+        html += '
'
+        lineNum++
+      else
+        html += '
'
+    if useLineNums
+      html += '

'
     html += '
'
+    # consoel.log('result:', html);
     html

   escapeString: (string) ->


Remove redundant block comment logic.

Remove redundant block comment logic.

--- src/parser.coffee
+++ src/parser.coffee
@@ -113,7 +113,7 @@

         if inComment
           comment.push commentLine[2]
-        else if commentLine[2].substring(0, 2) isnt '##'
+        else
           inComment = true
           indentComment =  commentLine[1].length - 1


Big fail

Big fail

--- src/puzzle.coffee
+++ src/puzzle.coffee
@@ -442,7 +442,7 @@
             swap.call(@squareList[0], @squareList[1].row, @squareList[1].col)

         once = runOnceAt(@squareList.length, =>
-            @status.shuffling -= 0
+            @status.shuffling -= 1
             callback?.apply(this)
             @trigger('puzzle.shuffle')
         )


Set stability level to 1

Set stability level to 1

--- build/tasks/docs-task.coffee
+++ build/tasks/docs-task.coffee
@@ -25,6 +25,7 @@
           '--title', 'Atom API Documentation'
           '-o', 'docs/output/api'
           '-r', 'docs/README.md'
+          '--stability', '1'
           'src/'
           includePaths...
         ]


Run main process specs first to shorten the feedback loop

--- build/tasks/spec-task.coffee
+++ build/tasks/spec-task.coffee
@@ -136,19 +136,19 @@
       else
         async.parallel

-    specs = [runRendererProcessSpecs, runMainProcessSpecs, runPackageSpecs]
+    specs = [runMainProcessSpecs, runRendererProcessSpecs, runPackageSpecs]

     method specs, (error, results) ->
       failedPackages = []
       coreSpecFailed = null

-      [rendererProcessSpecsFailed, mainProcessSpecsFailed, failedPackages] = results
+      [mainProcessSpecsFailed, rendererProcessSpecsFailed, failedPackages] = results

       elapsedTime = Math.round((Date.now() - startTime) / 100) / 10
       grunt.log.ok("Total spec time: #{elapsedTime}s using #{concurrency} cores")
       failures = failedPackages
+      failures.push "atom core (main process)" if mainProcessSpecsFailed
       failures.push "atom core (renderer process)" if rendererProcessSpecsFailed
-      failures.push "atom core (main process)" if mainProcessSpecsFailed

       grunt.log.error("[Error]".red + " #{failures.join(', ')} spec(s) failed") if failures.length > 0


Change signature in $.ajax's error callback

Error callback in $.ajax has different signature than success callback

--- app/utils/ajax.coffee
+++ app/utils/ajax.coffee
@@ -65,7 +65,7 @@
       success.apply(this, arguments)

     error = options.error || (->)
-    options.error = (data, status, xhr) =>
+    options.error = (xhr, status, data) =>
       Travis.lookup('controller:flash').pushObject(data.flash) if data?.flash
       delete data.flash if data?
       console.log "[ERROR] API responded with an error (#{status}): #{JSON.stringify(data)}"


Remove unused dependency

Remove unused dependency

--- src/scripts/modules/media/tabs/contents/tree/draggable.coffee
+++ src/scripts/modules/media/tabs/contents/tree/draggable.coffee
@@ -1,5 +1,4 @@
 define (require) ->
-  $ = require('jquery')
   BaseView = require('cs!helpers/backbone/views/base')

   return class TocDraggableView extends BaseView


removed an unnecessary console.log

removed an unnecessary console.log

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -131,9 +131,6 @@
 app.get "/-/google-api",(req, res)->
   ggl = require("googleapis")
   gsc = KONFIG.googleapiServiceAccount
-  console.log gsc
-
-
   eml = gsc.serviceAccountEmail
   key = gsc.serviceAccountKeyFile
   scp = ['https://www.googleapis.com/auth/drive']


stupid mistake

stupid mistake

--- scripts/create_previews.coffee
+++ scripts/create_previews.coffee
@@ -88,7 +88,7 @@

   albums.forEach (album) ->
     album.pictures.forEach (picture) ->
-     picture.sizes.forEach (size) ->
+     sizes.forEach (size) ->
         do (album, picture, size) ->
           magickSemaphore.push ->
             createPreview