Wtf is rate I don't even

Wtf is rate I don't even

--- resources/assets/coffee/_classes/beatmapset-filter.coffee
+++ resources/assets/coffee/_classes/beatmapset-filter.coffee
@@ -52,4 +52,4 @@
     query: ''

-  @expand: ['genre', 'language', 'extra', 'rate']
+  @expand: ['genre', 'language', 'extra', 'rank']


pjax: attempt to fix relative url

pjax: attempt to fix relative url

--- app/_src/pjaxnavigation.coffee
+++ app/_src/pjaxnavigation.coffee
@@ -65,7 +65,9 @@
     # prevent transition to same page
     unless @currentPageId is pageId
       # tell pjax to nav to page
-      $.pjax({url: "/#{pageId}", container: @contentSelector, fragment: @contentSelector})
+      # console.log "pageId ", pageId
+      $.pjax({url: url, container: @contentSelector, fragment: @contentSelector})
+      # $.pjax({url: "/#{pageId}", container: @contentSelector, fragment: @contentSelector})

   # handle history event for home page link


Support multiple instances (fix #75)

Support multiple instances (fix #75)

--- server/server.coffee
+++ server/server.coffee
@@ -76,6 +76,7 @@
             system.selfTest()
         await sleep(30 * 1000)  # wait for a bit to make sure previous deployment has been stopped
         logger.info("Starting jobs")
-        jobs.map((job) -> job.start())
+        if not (process.env["INSTANCE_NUMBER"]?) or (process.env["INSTANCE_NUMBER"] == 0)
+            jobs.map((job) -> job.start())

 start()


Max nickname length + 1

Max nickname length + 1

--- server/server.coffee
+++ server/server.coffee
@@ -364,7 +364,7 @@
       err.push("#{prefix}: #{pokemon.forme} forme is battle-only.")
       return err

-    unless 0 < pokemon.name.length < MAX_NICKNAME_LENGTH
+    unless 0 < pokemon.name.length <= MAX_NICKNAME_LENGTH
       err.push("#{prefix}: Nickname cannot be blank or be
                 #{MAX_NICKNAME_LENGTH} characters or higher.")
       return err


added logger for rewriter middleware

added logger for rewriter middleware

--- server/server.coffee
+++ server/server.coffee
@@ -17,6 +17,7 @@
 rewriter = express.Router()
 rewriter.use (req, res, next) ->
   req.url = '/bower' + req.url;
+  console.log req.url
   next()
   return

@@ -54,6 +55,7 @@
 app = express()

 # Only for prod env
+console.log process.env.NODE_ENV
 if process.env.NODE_ENV is 'prod'
   app.enable 'trust proxy' # tell express it's behind nginx reverse proxy & trust X-Forwarded-* headers
   app.use rewriter # serve requests on shan.io/bower


the prefix was stupid. now it's gone

the prefix was stupid. now it's gone

--- server/server.coffee
+++ server/server.coffee
@@ -12,8 +12,6 @@

 DEFAULT_PORT = 7000
 DEFAULT_HOST = "localhost"
-
-Q_PREFIX = '__q'

 class Server extends process.EventEmitter

@@ -49,7 +47,7 @@

         distributeJobs = (queues...) =>
             _.each queues, (q) =>
-                @redis.lpop Q_PREFIX + q, (err, jobId) =>
+                @redis.lpop q, (err, jobId) =>
                     if jobId
                         if workers[q] and workers[q].length
                             worker = workers[q].pop()
@@ -57,7 +55,7 @@
                                 pusher.send worker, "", q, jsonJob
                         else
                             # nobody's ready, back in the front of the line
-                            @redis.lpush Q_PREFIX + q, jobId
+                            @redis.lpush q, jobId

         routes = {}
         route = (regEx, actions) ->
@@ -81,7 +79,7 @@

         route "\/queue\/(.+?)\/?$", {
             GET: (match, response) =>
-                queue = Q_PREFIX + match[1]
+                queue = match[1]
                 @redis.lrange queue, 0, -1, (err, messages) ->
                     respond response, {
                         success: true,
@@ -89,7 +87,7 @@
                     }

             POST: (match, response, bag) =>
-                queue = Q_PREFIX + match[1]
+                queue = match[1]
                 id = uuidFactory.generate()
                 job = JSON.stringify {
                     uuid: id,
@@ -100,10 +98,10 @@
                     @redis.set id, job
                     @redis.rpush queue, id, (err, status) ->
                         respond response, { success: status, uuid: id }
-                        distributeJobs(match[1])
+                        distributeJobs(queue)

             DELETE: (match, response) =>
-                queue = Q_PREFIX + match[1]
+                queue = match[1]
                 @redis.del queue, (err, status) ->
                     respond response, {
                         success: status,


Add CORS headers to eventsource

Add CORS headers to eventsource

--- src/trans-eventsource.coffee
+++ src/trans-eventsource.coffee
@@ -20,7 +20,18 @@

 exports.app =
     eventsource: (req, res) ->
+        if !req.headers['origin'] or req.headers['origin'] is 'null'
+            origin = '*'
+        else
+            origin = req.headers['origin']
         res.setHeader('Content-Type', 'text/event-stream; charset=UTF-8')
+        res.setHeader('Access-Control-Allow-Origin', origin)
+        res.setHeader('Vary', 'Origin')
+        headers = req.headers['access-control-request-headers']
+        if headers
+            res.setHeader('Access-Control-Allow-Headers', headers)
+        res.setHeader('Access-Control-Allow-Credentials', 'true')
+
         res.writeHead(200)
         # Opera needs one more new line at the start.
         res.write('\r\n')


Add new ObjectID parsing and error hanling

--- coffee/document.coffee
+++ coffee/document.coffee
@@ -3,8 +3,8 @@
 ObjectID = require('mongodb').ObjectID

 exports.param = (req, res, next, id) ->
-  return res.send 400, 'invalid oid' if not /[a-f0-9]{24}/.test id
-  req.id = new ObjectID id
+  return res.json 400, error: 'Invalid ObjectID' if not /[a-f0-9]{24}/.test id
+  req.id = ObjectID.createFromHexString id
   next()

 exports.options = (req, res, next) ->


fix test

fix test

--- apps/show/test/routes.coffee
+++ apps/show/test/routes.coffee
@@ -34,4 +34,4 @@
       Backbone.sync.args[0][2].success fabricate 'show', fair: {
         organizer: { profile_id: 'artrio' }
       }
-      @res.locals.relatedContext.should.equal 'fair'
+      @res.locals.context.should.equal 'fair'


remove crufy code in sidebar.coffee

remove crufy code in sidebar.coffee

--- scripts/views/layouts/workspace/sidebar.coffee
+++ scripts/views/layouts/workspace/sidebar.coffee
@@ -34,10 +34,6 @@
       model = @model
       collection = @collection or model.getChildren?()

-      if model
-      else
-        @filteredMediaTypes.setFilter (type) -> return type.get('modelType')::toplevel
-
       # TODO: Make the collection a FilteredCollection that only shows @model.accepts
       @addContent.show(new AddView {context:model, collection:@filteredMediaTypes})
       @toc.show(new TocView {model:model, collection:collection})


Cakefile specified Stencils.

Cakefile specified Stencils.

--- src/lib/edify_.coffee
+++ src/lib/edify_.coffee
@@ -69,13 +69,15 @@
   constructor: ->
     @contents = []
     @languages = {}
+    @templates = []
   parse: (options...) -> @contents.push options
   language: (language, options) ->
     suffixes = options.suffix
     suffixes = [ suffixes ] if not Array.isArray(suffix)
     for suffix in suffixes
       @languages[suffix] = extend { language }, options
-  stencil: ->
+  stencil: (regex, stencil) ->
+    @templates.push { regex, stencil }
   _find: (from, to, include, exclude) ->
     find = (found, from, to, _) ->
       found ?= []
@@ -138,7 +140,10 @@
           file[0].source.push line
     file.pop()
     file.reverse()
-    output = engine.execute "stencil/markdown.stencil", { file }, _
+    for template in @templates
+      if template.regex.test from
+        break
+    output = engine.execute template.stencil, { file }, _
     fs.writeFile to, output, "utf8", _
   _edify: (_) ->
     for content in @contents


Format command and run count integers

Format command and run count integers

--- src/packages/command-logger/lib/command-logger-view.coffee
+++ src/packages/command-logger/lib/command-logger-view.coffee
@@ -1,6 +1,7 @@
 {$$$} = require 'space-pen'
 ScrollView = require 'scroll-view'
 _ = require 'underscore'
+humanize = require 'humanize-plus'

 module.exports =
 class CommandLoggerView extends ScrollView
@@ -77,7 +78,10 @@
       else
         previous + 1
     commandCount = node.children.reduce(reduceCommandCount, 0)
-    @categorySummary.text("#{_.pluralize(commandCount, 'command')}, #{_.pluralize(runCount, 'invocation')}")
+
+    commandText = "#{humanize.intcomma(commandCount)} #{humanize.pluralize(commandCount, 'command')}"
+    invocationText = "#{humanize.intcomma(runCount)} #{humanize.pluralize(runCount, 'invocation')}"
+    @categorySummary.text("#{commandText}, #{invocationText}")

   updateTreeMapSize: ->
     @treeMap.width(@width() - 20)


Random comments

Random comments

--- controllers/index.coffee
+++ controllers/index.coffee
@@ -27,12 +27,15 @@
                     location: []

                 if action?
+                    # Set history
                     res.locals.current.location.push
                         title: controller.title
                         slug: req.params.controller
                 else
+                    # Set index as the default action if undefined
                     req.params.action = 'index'

+                # Call controller if it exists
                 if @controllers[req.params.controller]?[req.params.action]?
                     @controllers[req.params.controller][req.params.action] req, res


add /winners route

add /winners route

--- controllers/index.coffee
+++ controllers/index.coffee
@@ -68,6 +68,19 @@
     recentDeploys: req.recentDeploys
     interestingTeams: req.interestingTeams
     featuredJudges: req.featuredJudges
+
+
+app.get '/winners', [loadCanRegister, loadFeaturedJudges], (req, res, next) ->
+
+  if app.enabled('winners')
+    res.render2 'index/winners',
+      team: req.team
+      stats: app.stats
+      featuredJudges: req.featuredJudges
+
+  else
+    res.redirect("/")
+

 app.get '/2013', [loadCanRegister, loadCurrentPersonWithTeam, loadRecentDeploys, loadInterestingTeams, loadFeaturedJudges], (req, res, next) ->
     res.render2 "index/index",


small fix; nested components with justified is still not working"

--- app/scripts/components/BsBtnContainer.coffee
+++ app/scripts/components/BsBtnContainer.coffee
@@ -1,10 +1,15 @@
 Bootstrap.BsBtnContainer = Ember.ContainerView.extend(
     classNames: ['btn-group'],
-    childViews: [Bootstrap.BsButtonItemView],
+    childViews: ['buttonItemView'],
+    buttonItemView: ->
+        Bootstrap.BsButtonItemView.create {content: @get('content')}
     init: ->
         @_super()
         @set('icon_active', @get('parentView.icon_active'))
         @set('icon_inactive', @get('parentView.icon_inactive'))
+        content = this.get('content')
+        @get('childViews').forEach (view) ->
+            view.set('content', content)
 )

 Ember.Handlebars.helper 'bs-btn-container', Bootstrap.BsBtnContainer


Add strict check for file type

Add strict check for file type

--- src/ls-archive.coffee
+++ src/ls-archive.coffee
@@ -32,8 +32,10 @@
       entryPath = entry.path
     if entry.type is 'Directory'
       entryType = 5
+    else if entry.type is 'File'
+      entryType = 0
     else
-      entryType = 0
+      entryType = -1
     paths.push(new ArchiveEntry(entryPath, entryType))
     entry.autodrain()


Workaround Chrome issue reseting scroll after focus

Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=75072

--- app/lib/markdown-insert.coffee
+++ app/lib/markdown-insert.coffee
@@ -83,7 +83,9 @@
     input.value = begInputValue + midInputValue + endInputValue

     # set cursor back to a meaningful location for continued typing
+    {scrollTop} = input
     input.focus()
+    input.scrollTop = scrollTop
     input.setSelectionRange?(newSelectionStart, newSelectionEnd)

   incrementedListItems: (previousText, text) -> # TODO: limit prev lines length


Pass bogus first parameter

Pass bogus first parameter

--- src/index.coffee
+++ src/index.coffee
@@ -27,7 +27,7 @@
           @emit 'update', {state, desiredState: {}}

   _computeState: (callback) =>
-    @Lync.getState (error, state) =>
+    @Lync.getState null, (error, state) =>
       return callback error if error?
       return callback null, state

@@ -42,7 +42,7 @@

     return @Lync.stopMeetings callback if _.isEmpty meetingUrl

-    @Lync.getState (error, state) =>
+    @Lync.getState null, (error, state) =>
       return callback error if error?
       return callback() if meetingUrl == _.get(state, 'meetingUrl')
       @Lync.joinMeeting meetingUrl, callback


Expose version on sake object as well

Expose version on sake object as well

--- src/index.coffee
+++ src/index.coffee
@@ -1,4 +1,8 @@
 import * as sake from './sake'
-export *         from './sake'
-export {version} from '../package.json'
+import {version} from '../package.json'
+
+sake.version = version
+
+export * from './sake'
+export {version}
 export default sake


Clarify help text for --plaintext

Clarify help text for --plaintext

--- src/index.coffee
+++ src/index.coffee
@@ -175,7 +175,7 @@
     .describe('ssl', 'Use an SSL encrypted connection to connect with the host')
     .boolean('ssl')
     .default('ssl', false)
-    .describe('plaintext', 'For accounts created on Meteor servers older than v0.8.2, fallback to sending the password as plaintext.')
+    .describe('plaintext', 'For Meteor servers older than v0.8.2, fallback to sending the password as plaintext.')
     .default('plaintext', false)
     .boolean('plaintext')
     .boolean('h')


fixes

fixes

--- src/index.coffee
+++ src/index.coffee
@@ -101,7 +101,7 @@
       G.repository[k] = make_pattern(v, macros)

   if print
-    if options.print == "CSON"
+    if print == "CSON"
       CSON = require "CSON"
       process.stdout.write CSON.stringify(G)
     else


Assign targetColor to color in case it's not assigned

--- src/index.coffee
+++ src/index.coffee
@@ -5,6 +5,9 @@
 isObject = require 'is-object'

 module.exports = (color, targetColor, options={}) ->
+  unless targetColor?
+    targetColor = color
+
   if isObject(targetColor)
     options = targetColor
     targetColor = color


test instance props

test instance props

--- src/index.coffee
+++ src/index.coffee
@@ -61,3 +61,13 @@
 setTimeout tick, 1000

 app.$mount '#app'
+
+# instance properties
+console.log app.$el
+console.log app.$data
+console.log app.$option
+console.log app.$parent
+console.log app.$root
+console.log app.$children
+console.log app.$
+console.log app.$$


Removed stray comment

Removed stray comment

--- src/index.coffee
+++ src/index.coffee
@@ -54,4 +54,3 @@
     console.log JSON.stringify(vouchers, null, 4)
   else if (program.readable)
     console.log humanOutput(vouchers)
-      # body...


remove `serve-index` usage in favor of default `serve-static` behavior

`connect.static` serves `index.html` to directory requests by default:
https://github.com/expressjs/serve-static/tree/aec36c897a33c6c2421fa41cc4947042d67332f6#index

https://github.com/senchalabs/connect/blob/5412f50bba39cc2e1f2448fd4ca125fdeeef1bf9/package.json#L47

--- src/index.coffee
+++ src/index.coffee
@@ -32,7 +32,6 @@

   run: ->
     @app = connect()
-    @app.use connect.directory(if typeof @root == "object" then @root[0] else @root)

     @handlers().forEach (middleware) =>
       if typeof (middleware) is "object"


Start on a drag-and-drop subject uploader

--- app/pages/lab/subject-set.cjsx
+++ app/pages/lab/subject-set.cjsx
@@ -3,6 +3,55 @@
 PromiseRenderer = require '../../components/promise-renderer'
 apiClient = require '../../api/client'
 ChangeListener = require '../../components/change-listener'
+
+UploadDropTarget = React.createClass
+  displayName: 'UploadDropTarget'
+
+  getDefaultProps: ->
+    accept: 'text/plain'
+    multiple: false
+    onSelect: Function.prototype
+
+  getInitialState: ->
+    dragEntered: false
+
+  eventsToMakeDropWork: ->
+    onDragEnter: @handleDrag.bind this, true
+    onDragExit: @handleDrag.bind this, false
+    onDragOver: @handleDrag.bind this, null
+
+  hiddenInputStyle:
+    height: 0
+    opacity: 0
+    position: 'absolute'
+    width: 0
+
+  render: ->
+    style =
+      position: 'relative'
+      outline: if @state.dragEntered
+        '1px solid green'
+      else
+        '1px dashed gray'
+
+
+      <input type="file" accept={@props.accept} multiple={@props.multiple} onChange={@handleFileSelection} style={@hiddenInputStyle} />
+      {@props.children}
+
+
+  handleDrag: (enter, e) ->
+    e.stopPropagation()
+    e.preventDefault()
+    if enter?
+      @setState dragEntered: enter
+
+  handleDrop: (e) ->
+    e.stopPropagation()
+    e.preventDefault()
+    @props.onSelect e.dataTransfer.files
+
+  handleFileSelection: (e) ->
+    @props.onSelect e.target.files

 EditSubjectSetPage = React.createClass
   displayName: 'EditSubjectSetPage'
@@ -10,20 +59,26 @@
   getDefaultProps: ->
     subjectSet: null

+  getInitialState: ->
+    {}
+
   render: ->

-
TODO

-

+

         Name

         <input type="text" name="display_name" value={@props.subjectSet.display_name} onChange={handleInputChange.bind @props.subjectSet} />
-

-

+

+
Subjects: {@props.subjectSet.set_member_subjects_count}

+

+        <UploadDropTarget onSelect={@handleFileSelection}>Add subjects and manifests</UploadDropTarget>
+

+

         (Retirement rules editor)
-

-

-        (Subject set editor)
-

+

+
+  handleFileSelection: (files) ->
+    console.log 'Selected files', files

 module.exports = React.createClass
   displayName: 'EditSubjectSetPageWrapper'


Lock to protect sensor

Lock to protect sensor

--- src/index.coffee
+++ src/index.coffee
@@ -1,6 +1,5 @@
 util = require 'util'
 {EventEmitter} = require 'events'
-schedule = require 'node-schedule'

 module.exports =
   Action : class Action extends EventEmitter
@@ -11,10 +10,12 @@

   Sensor : class Sensor extends EventEmitter
     constructor: (@name, @timeInterval, @fn) ->
+      @lock = false

     start: ->
       @intervalHandler = setInterval =>
-        @update()
+        if not @lock
+          @update()
       , @timeInterval
       @emit 'sensor-start', @


youtube & vimeo embed regexp

youtube & vimeo embed regexp

--- app/scripts/controllers.coffee
+++ app/scripts/controllers.coffee
@@ -182,7 +182,8 @@
     search = ""
     #return all artwork video and filtre with idFrezsnoy - TODO search idFresnoy in api
     # AmeRestangular.setDefaultHeaders({'Content-Type': 'charset=UTF-8'})
-    AmeRestangular.all("api_search/").get('',{"search": search, "flvfile": "true", "previewsize":"scr"}, {authorization: undefined} ).then((ame_artwork) ->
+    # AmeRestangular.all("api_search/").get('',{"search": search, "flvfile": "true", "previewsize":"scr"}, {authorization: undefined} ).then((ame_artwork) ->
+    AmeRestangular.all("api_search/").get('apiresult.htm',{}, {authorization: undefined}).then((ame_artwork) ->
       for archive in ame_artwork
         # valid reference id Fresnoy => id AME

@@ -394,7 +395,9 @@
       iframe: /(\.pdf|vimeo\.com|youtube\.com)/i.test(url)
       description: description
     # embed video youtube
-    url = url.replace("watch?v=","embed/").replace("&t=","#t=")
+    # url = url.replace("watch?v=","embed/").replace("&t=","#t=")
+    url = url.replace(/^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?/gm, 'http://www.youtube.com/embed/$5');
+    url = url.replace(/(?:http:\/\/)?(?:www\.)?(?:vimeo\.com)\/(.*?)\/(.*)/g, '//player.vimeo.com/video/$1')
     # when url is image set picture var, otherwise set medium_url
     if(/\.(jpe?g|png|gif|bmp)/i.test(url)) then image.picture= $sce.trustAsResourceUrl(url)
     else  image.medium_url= $sce.trustAsResourceUrl(url)


Properly reload datatable when region changes

--- app/scripts/dcplotsctrl.coffee
+++ app/scripts/dcplotsctrl.coffee
@@ -188,7 +188,8 @@

     $scope.initTable = () ->
       # needed to fix table alignment if drawn when not visible
-      $("#dc-data-table").dataTable().fnAdjustColumnSizing()
+      table = $("#dc-data-table").dataTable()
+      table.fnAdjustColumnSizing()

     setupCharts = (region) ->
       getData region, (data) ->
@@ -289,7 +290,6 @@
         pieChart managementChart, managements, managementsGroup, all

         dc.dataCount(".dc-data-count").dimension(xfilter).group(all)
-        $scope.columns = ["ward","region"]
         makeDataTable("#dc-data-table", wards)

         dc.renderAll()
@@ -435,31 +435,46 @@
           chart.rescale())
         .yAxis().ticks(4)

+    reloadTable = (datatable,dim) ->
+      alldata = dim.top(Infinity)
+      datatable.fnClearTable()
+      datatable.fnAddData(alldata)
+      datatable.fnDraw()
+
     makeDataTable = (selector, dim) ->
-      cols = $scope.fields.map((x) -> {mData: x, sDefaultContent: ""})
-
-      datatable = $(selector).dataTable
-        bPaginate: true,
-        pagingType: "full",
-        iDisplayLength: 25,
-        scrollX: true,
-        scrollY: 500,
-        scrollCollapse: true,
-        bSort: true,
-        bDeferRender: true,
-        aaData: dim.top(Infinity),
-        bDestroy: true,
-        aoColumns: cols
-
-      refreshTable = () ->
-        dc.events.trigger () ->
-          alldata = dim.top(Infinity)
-          datatable.fnClearTable()
-          datatable.fnAddData(alldata)
-          datatable.fnDraw()
+      exists = $.fn.DataTable.fnIsDataTable($(selector))
+
+      if exists
+        datatable = $(selector).dataTable()
+        reloadTable(datatable,dim)
+      else
+        cols = $scope.fields.map((x) ->
+          if x.endsWith("_year")
+            mData: x
+            sDefaultContent: ""
+            mRender: (obj) ->
+              y = obj.getFullYear()
+              if y == YEAR_ZERO then "unknown" else y
+          else
+            {mData: x, sDefaultContent: ""})
+
+        datatable = $(selector).dataTable
+          bPaginate: true,
+          pagingType: "full",
+          iDisplayLength: 25,
+          scrollX: true,
+          scrollY: 500,
+          scrollCollapse: true,
+          bSort: true,
+          bDeferRender: true,
+          aaData: dim.top(Infinity),
+          bDestroy: true,
+          aoColumns: cols

       dc.chartRegistry.list().forEach (chart) ->
-        chart.on "filtered", refreshTable
+        chart.on "filtered", () ->
+          dc.events.trigger () ->
+            reloadTable(datatable,dim)

     reduceStatus = (group) ->
       res = group.reduce(\
@@ -521,3 +536,5 @@
         (() -> count: 0, total: 0))
       res

+String.prototype.endsWith = (suffix) ->
+  this.indexOf(suffix, this.length - suffix.length) != -1


[fix] BaseModel: #touch

[fix] BaseModel: #touch

--- app/scripts/models/base.coffee
+++ app/scripts/models/base.coffee
@@ -57,3 +57,10 @@
         @sync method, @, options
       else
         super
+
+    touch: (attr, value = undefined) ->
+      return unless attr?
+      value ||= @get attr
+      @unset attr,
+        silent: true
+      @set attr, value


Readability

Readability

Signed-off-by: Ian Macalinao <08370e385f4778cad8fe504ec5445edd3d45bd9a@gmail.com>

--- src/items.coffee
+++ src/items.coffee
@@ -74,7 +74,10 @@
 ##
 # Makes a comparator to sort by.
 #
-lol.items.makeComparator = (property, asc = true) -> (a, b) -> if asc then (a[property] || 0) - (b[property] || 0) else (b[property] || 0) - (a[property] || 0)
+lol.items.makeComparator = (property, asc = true) ->
+  (a, b) ->
+    if asc then (a[property] || 0) - (b[property] || 0)
+    else (b[property] || 0) - (a[property] || 0)

 ##
 # Defines a new item.


Remove unused font.

Remove unused font.

--- app/server/js/react/app.coffee
+++ app/server/js/react/app.coffee
@@ -19,8 +19,6 @@
             title {}, this.props.title
             link href: '/app/client/img/favicon.ico?v=' + this.props.version, rel: 'shortcut icon'
             link href: '/app/client/build/app.css?v=' + this.props.version, rel: 'stylesheet'
-            # TODO: Use inline Base64.
-            # link href: 'http://fonts.googleapis.com/css?family=PT+Sans&subset=latin,latin-ext', rel: 'stylesheet'
           body dangerouslySetInnerHTML: __html: this.props.bodyHtml

       getHtmlClassName: ->


checkpoint

checkpoint

--- src/keyring.iced
+++ src/keyring.iced
@@ -53,7 +53,7 @@

   # These two functions are to fulfill to key manager interface
   get_pgp_key_id : () -> @key_id_64()
-  get_pgp_fingerprint : () -> @fingerprint()
+  get_pgp_fingerprint : () -> @fingerprint().toLowerCase()

   #-------------


introduce new error handling, distinguish (recoverable) 'fails' from (irrecoverable) 'exceptions'


feature(lorax): Fully support gfm for closing issues

--- src/lorax.coffee
+++ src/lorax.coffee
@@ -21,6 +21,7 @@
 url        = Config.get "url"
 issueTmpl  = Config.get "issue"
 commitTmpl = Config.get "commit"
+closeRegex = /(?:close(?:s|d)?|fix(?:es|ed)?|resolve(?:s|d)?)\s+#(\d+)/i

 ###
 @function
@@ -73,7 +74,7 @@
     issues:    []
     title:     lines.shift()

-  for line, i in lines when match = line.match /(?:Closes|Fixes)\s#(\d+)/
+  for line, i in lines when match = line.match closeRegex
     commitObj.issues.push parseInt(match[1])
     lines.splice i, 1


fix(model): converting container parameters in .create with export

--- src/model.coffee
+++ src/model.coffee
@@ -208,6 +208,7 @@
         callbackOrObservable(data)

     if params.length > 0 || typeof params == 'object'
+      params = model(params).export(false, true)
       connector.create(params).done callback
     else
       connector.create().done callback


fix conversation sorting

fix conversation sorting

--- src/model.coffee
+++ src/model.coffee
@@ -54,7 +54,10 @@
     data.conversation_state.forEach (conversation) =>
       conversation = conversation.conversation
       id = conversation.id.id
-      sort_timestamp = conversation.self_conversation_state.sort_timestamp
+      # sort_timestamp = conversation.self_conversation_state.sort_timestamp
+      # active_timestamp = conversation.self_conversation_state.active_timestamp
+      # invite_timestamp = conversation.self_conversation_state.invite_timestamp
+      latest_read_timestamp = conversation.read_state.latest_read_timestamp
       participants = []
       names = []
       conversation.participant_data.forEach (participant) =>
@@ -63,7 +66,7 @@
           participants.push participant.id.chat_id
           names.push participant.fallback_name
       name = conversation.name ? names.join(", ")
-      @conversationAdd id, name, participants, sort_timestamp
+      @conversationAdd id, name, participants, latest_read_timestamp
     # extract messages
     data.conversation_state.forEach (conversation) =>
       events = conversation.event


whitespace

whitespace

--- src/range.coffee
+++ src/range.coffee
@@ -8,6 +8,7 @@

 # https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
 TEXT_NODE = 3
+

 # Public interface.

@@ -140,7 +141,6 @@
     startOffset: start[1]
     endOffset: end[1]
   }
-

 splitBoundaries = (range) ->


parse help for external scripts

parse help for external scripts

scripts added via npm weren't getting their help parsed. this adds a
call to parse the help docs using node's `require.resolve` to figure out
the path.

--- src/robot.coffee
+++ src/robot.coffee
@@ -213,6 +213,7 @@
     for pkg in packages
       try
         require(pkg) @
+        @parseHelp require.resolve(pkg)
       catch error
         @logger.error "Error loading scripts from npm package - #{error}"
         process.exit(1)


Remove unused class variable

Remove unused class variable

--- src/robot.coffee
+++ src/robot.coffee
@@ -43,7 +43,6 @@
     @Response     = Response
     @commands     = []
     @listeners    = []
-    @loadPaths    = []
     @enableSlash  = false
     @logger       = new Log process.env.HUBOT_LOG_LEVEL or 'info'

@@ -152,7 +151,6 @@

     Fs.exists path, (exists) =>
       if exists
-        @loadPaths.push path
         for file in Fs.readdirSync(path)
           @loadFile path, file


add methods freeze, unfreeze, where

add methods freeze, unfreeze, where

--- lib/client/javascripts/nali/collection.js.coffee
+++ lib/client/javascripts/nali/collection.js.coffee
@@ -16,21 +16,21 @@
     @clone model: model, filters: filters

   onModelCreated: ( extModel, model ) ->
-    @add model if model.isCorrect @filters
+    @add model if not @freezed and model.isCorrect @filters
     @

   onModelUpdated: ( extModel, model ) ->
     if model in @
-      if model.isCorrect @filters
+      if @freezed or model.isCorrect @filters
         @reorder()
         @trigger 'update.model', model
       else @remove model
-    else if model.isCorrect @filters
+    else if not @freezed and model.isCorrect @filters
       @add model
     @

   onModelDestroyed: ( model ) ->
-    @remove model
+    @remove model unless @freezed
     @

   adaptCollection: ->
@@ -46,7 +46,7 @@
     @

   adaptation: ( apply, cancel ) ->
-    apply.call @, model for model in @
+    @each ( model ) -> apply.call @, model
     @adaptations.apply.push apply
     @adaptations.cancel.unshift cancel if cancel
     @
@@ -71,8 +71,12 @@
     @

   removeAll: ->
-    delete @[ index ] for model, index in @
+    @each ( model ) -> @remove model
     @length = 0
+    @
+
+  each: ( callback ) ->
+    callback.call @, model, index for model, index in @
     @

   pluck: ( property ) ->
@@ -87,6 +91,19 @@

   toArray: ->
     Array::slice.call @, 0
+
+  freeze: ->
+    @freezed = true
+    @
+
+  unfreeze: ->
+    @freezed = false
+    @
+
+  where: ( filters ) ->
+    result = []
+    result.push model for model in @ when model.isCorrect filters
+    result

   order: ( @ordering ) ->
     @reorder()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/state.coffee
+++ src/state.coffee
@@ -1,3 +1,4 @@
+###
 StateMachine = () ->
   currentState = null
   initialState = null
@@ -12,3 +13,4 @@
   self.attrAccessor('currentState')

   return self
+###


Use `_.contains()` rather than `indexOf()`

--- src/theme.coffee
+++ src/theme.coffee
@@ -60,7 +60,7 @@
   #
   # * stylesheetPath: A {String} to a stylesheet
   loadStylesheet: (stylesheetPath) ->
-    @stylesheets.push(stylesheetPath) if @stylesheets.indexOf(stylesheetPath) < 0
+    @stylesheets.push(stylesheetPath) unless _.contains(@stylesheets, stylesheetPath)
     content = window.loadStylesheet(stylesheetPath)
     window.applyStylesheet(stylesheetPath, content, 'userTheme')


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/tween.coffee
+++ src/tween.coffee
@@ -18,4 +18,4 @@

   tween: (duration, properties) ->
-    for prope+    for property, tar


properly reload package.json data

properly reload package.json data

fixes #536

--- src/watch.coffee
+++ src/watch.coffee
@@ -201,7 +201,9 @@
   rootPath = sysPath.resolve rootPath
   nodeModules = "#{rootPath}/node_modules"
   try
-    json = require sysPath.join rootPath, 'package.json'
+    packagePath = sysPath.join rootPath, 'package.json'
+    delete require.cache[require.resolve packagePath]
+    json = require packagePath
   catch err
     return callback "Current directory is not brunch application root path,
  as it does not contain package.json (#{err})"


Limit watchers.

Limit watchers.

--- src/watch.coffee
+++ src/watch.coffee
@@ -5,15 +5,17 @@

 module.exports = (options, cb) ->
+  watched = {}
+
   bundle options, (err, _bundle) ->
     return cb err if err?
     cb null, _bundle

     dir = path.dirname _bundle.absolutePath
-    watched = {}

     # rebuild bundle if module has changed
     rebuildBundle = (filename, stats) ->
+      console.log 'must rebuild all the things'
       requireAs = filename.replace /\.\w+$/, ''
       unless (mod = _bundle.find requireAs)? and mod.absolutePath == path.join dir, filename
         return
@@ -24,7 +26,7 @@

     watch = (dir) ->
       return if watched[dir]
-
+      watched[dir] = true
       vigil.watch dir, {recurse: true}, rebuildBundle

     watch dir


Type check custom startServer

Type check custom startServer

--- src/watch.coffee
+++ src/watch.coffee
@@ -70,7 +70,7 @@
       server = require sysPath.resolve config.server.path
     catch error
       logger.error "couldn't load server #{config.server.path}: #{error}"
-    unless server.startServer?
+    unless typeof server.startServer is 'function'
       throw new Error 'Brunch server file needs to have startServer function'
     opts = {port, path: publicPath}
     serverConfig = helpers.extend opts, serverOpts.config or {}


tweakable word spacing

tweakable word spacing

--- src/scene/font.coffee
+++ src/scene/font.coffee
@@ -27,8 +27,9 @@

     @invalid_char = @chars[String.fromCharCode(end)]

-    @linesize   = @size + (@size >> 2)
-    @tabsize    = @size << 2
+    @spaceSize  = @size
+    @lineSize   = @spaceSize + (@spaceSize >> 2)
+    @tabSize    = @spaceSize << 2

   # Public: Centers text inside the given rect.
   #
@@ -57,15 +58,15 @@
     for c in text
       switch c
         when ' '
-          w += @size
+          w += @spaceSize
           continue
         when '\n'
           maxWidth = w if w > maxWidth
           w = 0
-          h += @linesize
+          h += @lineSize
           continue
         when '\t'
-          w += @tabsize
+          w += @tabSize
           continue

       char = @chars[c] || @invalid_char
@@ -95,14 +96,14 @@
     for c in text
       switch c
         when ' '
-          xx += @size
+          xx += @spaceSize
           continue
         when '\n'
           xx = x
-          yy += @linesize
+          yy += @lineSize
           continue
         when '\t'
-          xx += @tabsize
+          xx += @tabSize
           continue

       char = @chars[c] || @invalid_char


DDPRateLimiter.addRule to updateUserUtcOffset

--- server/methods/updateUserUtcOffset.coffee
+++ server/methods/updateUserUtcOffset.coffee
@@ -6,3 +6,9 @@
 		@unblock()

 		RocketChat.models.Users.setUtcOffset @userId, utcOffset
+
+DDPRateLimiter.addRule
+	type: 'method'
+	name: 'updateUserUtcOffset'
+	userId: -> return true
+, 1, 60000


"fix" test by adding done function

"fix" test by adding done function

--- server/test/units/presenters/theme.coffee
+++ server/test/units/presenters/theme.coffee
@@ -43,17 +43,17 @@
     "Expected the outOfDateIndicator.isUpToDate to be fals"
 )

-test("#populateIndicators populates the indicators for the given array of themes", ->
+test("#populateIndicators populates the indicators for the given array of themes", (done) ->
   theme1 = new Theme()
   theme1Indicator = new Indicator()
   theme2 = new Theme()
   theme2Indicator = new Indicator()

-  getIndicatorsByThemeStub = sinon.stub(Theme, 'getIndicatorsByTheme',  (themeId, callback) ->
+  getIndicatorsByThemeStub = sinon.stub(Theme, 'getIndicatorsByTheme',  (themeId, filter, callback) ->
     if theme1.id is themeId
-      callback(null, theme1Indicator)
+      callback(null, [theme1Indicator])
     else
-      callback(null, theme2Indicator)
+      callback(null, [theme2Indicator])
   )

   ThemePresenter.populateIndicators([theme1, theme2]).then(->
@@ -78,7 +78,7 @@
       getIndicatorsByThemeStub.restore()
       done(err)

-  ).fail((err) ->
+  ).fail( (err) ->
     getIndicatorsByThemeStub.restore()
     done(err)
   )


fix copy-on-hide for events

fix copy-on-hide for events


add/remove subview

add/remove subview

--- src/views/view.coffee
+++ src/views/view.coffee
@@ -87,6 +87,16 @@
 		# Get this views absolute frame on the screen
 		utils.convertPoint @frame, @, null

+	contentFrame: ->
+		# Get the combined size of all subviews
+		frame =
+			x: utils.min _.pluck(@subViews, "minX")
+			y: utils.min _.pluck(@subViews, "minY")
+
+		frame.width  = utils.max(_.pluck(@subViews, "maxX")) - frame.x
+		frame.height = utils.max(_.pluck(@subViews, "maxY")) - frame.y
+
+		frame

 	#############################################################################
 	## Geometry
@@ -284,9 +294,6 @@
 	#############################################################################
 	## Hierarchy

-	removeFromSuperview: ->
-		@superView = null
-
 	@define "superView"
 		get: -> @_superView or null
 		set: (value) ->
@@ -299,12 +306,14 @@
 			# Remove from previous superview subviews
 			if @_superView
 				@_superView._element.removeChild @_element
-				utils.remove @_superView._subViews, @
+				@_superView._subViews = _.without @_superView._subViews, @
+				@_superView.emit "change:subViews"

 			# Either insert the element to the new superview or into dom
 			if value
 				value._element.appendChild @_element
 				value._subViews.push @
+				value.emit "change:subViews"
 			else
 				@__insertElement()

@@ -312,10 +321,20 @@
 			@emit "change:superView"

 	@define "subViews"
-		get: -> @_subViews
-
-	#############################################################################
-	## Indexes
+		get: -> _.compact @_subViews
+
+	addSubView: (view) ->
+		view.superView = @
+
+	removeSubView: (view) ->
+
+		if view not in @subViews
+			return
+
+		view.superView = null
+
+	#############################################################################
+	## Ordering

 	@define "index"
 		get: -> @style['z-index'] or 0


docs(build options): add src

docs(build options): add src

--- docs/src/client/scripts/constants/build-opts-constant.coffee
+++ docs/src/client/scripts/constants/build-opts-constant.coffee
@@ -731,6 +731,79 @@
 			}
 		"""

+	src:
+		opts: [
+			name: 'dir'
+			define: "@type string, @default 'src'"
+			description: [
+				"Provide to name the src/ directory differently."
+			]
+		,
+			name: 'client.dir'
+			define: "@type string, @default 'client'"
+			description: [
+				"Provide to name the src/client/ directory differently."
+			]
+		,
+			name: 'client.bower.dir'
+			define: "@type string, @default 'bower_components'"
+			description: [
+				"Provide to name the src/client/bower_components/
+				 directory differently."
+			]
+		,
+			name: 'client.libs.dir'
+			define: "@type string, @default 'libs'"
+			description: [
+				"Provide to name the src/client/libs/
+				 directory differently."
+				"Directory for 3rd party libraries
+				 that aren't bower components."
+			]
+		,
+			name: 'client[images|scripts|styles|test|views].dir'
+			define: "@type string, @default property name"
+			description: [
+				"Provide to name the src/client/property name/
+				 directory differently."
+				"Property name example, 'scripts'"
+			]
+		,
+			name: 'server.dir'
+			define: "@type string, @default 'server'"
+			description: [
+				"Provide to name the src/server/ directory differently."
+			]
+		,
+			name: 'server.test.dir'
+			define: "@type string, @default 'test'"
+			description: [
+				"Provide to name the src/server/test/
+				 directory differently."
+			]
+		]
+		example: """
+			var opts = {
+				dist: {
+					dir: 'source',
+					client: {
+						dir: 'frontend',
+						bower:   { dir: 'bower' },
+						libs:    { dir: 'libraries' },
+						images:  { dir: 'img' },
+						scripts: { dir: 'js' },
+						styles:  { dir: 'css' },
+						test:    { dir: 'tests' },
+						views:   { dir: 'html' }
+					},
+					server: {
+						dir: 'backend',
+						test: { dir: 'tests' }
+					}
+				}
+			}
+		"""
+
 	test:
 		opts: [
 			name: 'client.browsers'


no message

no message

--- shared/router.coffee
+++ shared/router.coffee
@@ -69,10 +69,11 @@
     path: '/sign-out'
     onBeforeAction: ()->
       Session.set('entryError', undefined)
-      if AccountsEntry.settings.homeRoute
+      if not AccountsEntry.settings.homeRoute
+        @next()
+      else
         Meteor.logout () ->
           Router.go AccountsEntry.settings.homeRoute
-      @next()

   @route 'entryResetPassword',
     path: 'reset-password/:resetToken'


add chromosomal dmg to mammalian gneotox

--- shared/shared.coffee
+++ shared/shared.coffee
@@ -359,6 +359,7 @@
             "Genotox":
                 "DNA damage": ["DNA adducts ", "DNA strand breaks", "DNA cross-links", "DNA oxidation", "Unscheduled DNA synthesis", "Other"]
                 "Mutation": ["tk", "hprt ", "ouabain resistance", "Other gene", "Chromosomal damage", "Chromosomal aberrations", "Micronuclei", "Sister Chromatid Exchange", "Aneuploidy", "Other"]
+                "Chromosomal damage": ["Chromosomal aberrations", "Micronuclei", "Sister Chromatid Exchange", "Aneuploidy", "Other"]
                 "DNA repair": ["Other"]
                 "Cell transformation": ["Other"]


:white_check_mark: For throttling max insertion count for i, a, o, O


support additional context in standalone

--- app/context.coffee
+++ app/context.coffee
@@ -337,9 +337,9 @@
   new_context

-create_standalone_context = ({imports, module_names}={}) ->
+create_standalone_context = ({imports, module_names, context}={}) ->
   base_context = create_base_context({imports: ['builtins'].concat(imports or []), module_names})
-  create_run_context [create_context base_context]
+  create_run_context [context ? {}, create_context base_context]

 scoped_eval = (ctx, string, var_names=[]) ->


Fix TypeError when running 'balena apps'

Change-type: patch
Signed-off-by: Paulo Castro <fd077434a7c3095bfe440741787d02f6a7bab07e@balena.io>

--- lib/actions/app.coffee
+++ lib/actions/app.coffee
@@ -82,6 +82,7 @@
 	permission: 'user'
 	primary: true
 	action: (params, options, done) ->
+		_ = require('lodash')
 		balena = require('balena-sdk').fromSharedOptions()
 		visuals = require('resin-cli-visuals')

@@ -94,8 +95,8 @@
 			$expand: owns__device: $select: 'is_online'
 		.then (applications) ->
 			applications.forEach (application) ->
-				application.device_count = application.owns__device.length
-				application.online_devices = application.owns__device.filter((d) -> d.is_online == true).length
+				application.device_count = _.size(application.owns__device)
+				application.online_devices = _.filter(application.owns__device, (d) -> d.is_online == true).length

 			console.log visuals.table.horizontal applications, [
 				'id'


rc script

rc script

--- editor.coffee
+++ editor.coffee
@@ -347,6 +347,9 @@

 window.init_editor = ->
   $output = $ '#output'
+  rc = localStorage.lead_rc
+  if rc?
+    run_in_available_context rc
   program = if location.search isnt ''
     atob decodeURIComponent location.search[1..]
   else


Add snippets for SuiteScript file functions


cleanup

cleanup

--- apps/articles/client/editorial_signup.coffee
+++ apps/articles/client/editorial_signup.coffee
@@ -6,7 +6,6 @@
 Cycle = require '../../../components/cycle/index.coffee'
 { resize } = require '../../../components/resizer/index.coffee'
 CTABarView = require '../../../components/cta_bar/view.coffee'
-mediator = require '../../../lib/mediator.coffee'
 cookies = require '../../../components/cookies/index.coffee'
 analyticsHooks = require '../../../lib/analytics_hooks.coffee'


Add more filterable bibliography types

Add more filterable bibliography types

--- apps/artist/client/views/bibliography.coffee
+++ apps/artist/client/views/bibliography.coffee
@@ -28,6 +28,8 @@
       group_by: 'published_date'
       filter_by: 'type'
       filters:
+        book: 'Books'
+        article: 'Articles'
         catalogue: 'Exhibition Catalogues'
         review: 'Exhibtion Reviews'
         interview: 'Interviews'


Fix in cache

Fix in cache

--- lib/cache.coffee
+++ lib/cache.coffee
@@ -23,8 +23,7 @@
       removed: 0

   add: (key, value, sticky = false) ->
-    return if @map[key] != undefined
-    return if @sticky[key] != undefined
+    return item.get() if item = (@sticky[key] || @map[key])
     item = new CacheItem key, value
     if sticky
       @stats.sticky_items++


Cleaner color functions

Cleaner color functions

--- lib/color.coffee
+++ lib/color.coffee
@@ -1,15 +1,18 @@
 'use strict'

-componentToHex = (c) ->
+
+rgbToHex = (r, g, b) ->
+  c2h = (c) ->
     hex = c.toString(16)
     return if (hex.length is 1) then "0#{hex}" else hex

-rgbToHex = (r, g, b) ->
-    return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b)
+  return "##{c2h(r)}#{c2h(g)}#{c2h(b)}"

-invert = (rgb) ->
-    rgb = [].slice.call(arguments).join(',').replace(/rgb\(|\)|rgba\(|\)|\s/gi, '').split(',')
+
+invert = (rgb...) ->
+    rgb = rgb.join(',').replace(/rgb\(|\)|rgba\(|\)|\s/gi, '').split(',')
     rgb[i] = (if i is 3 then 1 else 255) - c for c, i in rgb
     return rgbToHex(rgb[0], rgb[1], rgb[2])

+
 exports.invert = invert


give space modules better class names for debugging

--- source/module.coffee
+++ source/module.coffee
@@ -70,7 +70,7 @@

   @define: (moduleName, prototype) ->
     prototype.toString = -> moduleName # For better debugging
-    @publish Space.Module.extend(prototype), moduleName
+    @publish Space.Module.extend(moduleName, prototype), moduleName

   # All published modules register themselves here
   @published = {}


Rerender on language change.

Rerender on language change.

--- app/assets/javascripts/app/controllers/ticket_zoom.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom.coffee
@@ -60,7 +60,15 @@
     # rerender view, e. g. on langauge change
     @bind 'ui:rerender', =>
       return if !@authenticate(true)
-      @render(true)
+
+      # reset controllers state vars
+      @shown = false
+      @initDone = false
+      @activeState = false
+      @renderDone = false
+
+      # rerender view
+      @render()

   meta: =>


Fixed issue #2394 - Jump to bottom after article has been created to show that the article has been saved.

--- app/assets/javascripts/app/controllers/ticket_zoom.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom.coffee
@@ -239,6 +239,17 @@
     return if !@attributeBar
     @attributeBar.start()

+  # scroll to article if given
+  scrollToPosition: (position, delay, article_id) =>
+    scrollToDelay = =>
+      if position is 'article'
+        @scrollToArticle(article_id)
+        @positionPageHeaderUpdate()
+        return
+      @scrollToBottom()
+      @positionPageHeaderUpdate()
+    @delay(scrollToDelay, delay, 'scrollToPosition')
+
   pagePosition: (params = {}) =>

     # remember for later
@@ -251,34 +262,23 @@
       article_id = @pagePositionData
       @pagePositionData = undefined

-    # scroll to article if given
-    scrollToPosition = (position, delay) =>
-      scrollToDelay = =>
-        if position is 'article'
-          @scrollToArticle(article_id)
-          @positionPageHeaderUpdate()
-          return
-        @scrollToBottom()
-        @positionPageHeaderUpdate()
-      @delay(scrollToDelay, delay, 'scrollToPosition')
-
     # trigger shown to article
     if !@shown
       @shown = true
       App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
-      scrollToPosition('bottom', 50)
+      @scrollToPosition('bottom', 50, article_id)
       return

     # scroll to article if given
     if article_id && article_id isnt @last_article_id
       @last_article_id = article_id
-      scrollToPosition('article', 300)
+      @scrollToPosition('article', 300, article_id)
       return

     # scroll to end if new article has been added
     if !@last_ticket_article_ids || !_.isEqual(_.sortBy(@last_ticket_article_ids), _.sortBy(@ticket_article_ids))
       @last_ticket_article_ids = @ticket_article_ids
-      scrollToPosition('bottom', 100)
+      @scrollToPosition('bottom', 100, article_id)
       return

   setPosition: (position) =>
@@ -915,6 +915,7 @@
         @autosaveStart()
         @muteTask()
         @submitEnable(e)
+        @scrollToPosition('bottom', 50)

       error: (settings, details) =>
         error = undefined


Improve error message formatting

Improve error message formatting

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -571,7 +571,7 @@

     @fetchSocialChannel (err, channel) =>
       if err
-        console.warn "CollaborationController: #{err}"
+        throwError err
         return callMethod 'notStarted'

       @isRealtimeSessionActive channel.id, (isActive, file) =>
@@ -971,7 +971,7 @@

   throwError: throwError = (err, args...) ->

-    format = \
+    format = JSON.stringify \
       switch typeof err
         when 'string' then err
         when 'object' then err.message or err.description
@@ -980,7 +980,7 @@
     argIndex = 0
     console.error """
       IDE.CollaborationController:
-      #{ format.replace /%s/g, -> args[argIndex++] or '%s' }
+      #{ format.replace /%s/g, -> JSON.stringify(args[argIndex++]) or '%s' }
     """


remove unneeded attribute

remove unneeded attribute

--- app/assets/javascripts/models/journal_task_type.js.coffee
+++ app/assets/javascripts/models/journal_task_type.js.coffee
@@ -4,4 +4,3 @@
   role: a('string')
   journal: DS.belongsTo('journal')
   taskType: DS.belongsTo('taskType')
-  body: []


collaboration: controller minor

collaboration: controller minor

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -105,9 +105,7 @@

   startChatSession: (callback) ->

-    channelId = @channelId or @workspaceData.channelId
-
-    if channelId
+    if @getSocialChannelId()
     then @reactivateChatSession callback
     else @initPrivateMessage callback

@@ -130,7 +128,9 @@

   getRealtimeFileName: (id) ->

-    unless id = @getSocialChannelId()
+    id or= @getSocialChannelId()
+
+    unless id
       return showError 'social channel id is not provided'

     hostName = @getCollaborationHost()


Minor simplification

Minor simplification

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -522,9 +522,9 @@
     watchingHost = -1 < @myWatchMap.values().indexOf @collaborationHost
     return snapshot  unless watchingHost

-    hostSnapshot = @rtm.getFromModel("#{@collaborationHost}Snapshot")?.values()
-
-    if hostSnapshot
+    key = "#{@collaborationHost}Snapshot"
+
+    if hostSnapshot = @rtm.getFromModel(key)?.values()
       return snapshot.concat hostSnapshot

     return snapshot


fix scroll

fix scroll

--- app/assets/javascripts/uploadcare/widget/dialog.js.coffee
+++ app/assets/javascripts/uploadcare/widget/dialog.js.coffee
@@ -78,13 +78,13 @@
     # hide current opened dialog and open new one
     oldDialogPr = currentDialogPr
     currentDialogPr = null
-    oldDialogPr.dialogElement.addClass('uploadcare-inactive')

     settings = $.extend({}, settings, {
       multiple: false
       tabs: ''
     })
     dialog = uploadcare.openDialog(file, 'preview', settings)
+    oldDialogPr.dialogElement.addClass('uploadcare-inactive')

     dialog.always ->
       currentDialogPr = oldDialogPr


Add spec for issues: https://github.com/the-grid/Flowerflip/issues/22 https://github.com/the-grid/Flowerflip/issues/25

--- spec/Thenable.coffee
+++ spec/Thenable.coffee
@@ -787,3 +787,134 @@
       .finally 'enfin-fini',   (c, res) ->
         chai.expect(res).to.eql [15]
         done()
+
+  describe 'promise chain within branching', ->
+    it 'should execute the promise chain', (done) ->
+      multiply = (multiplier, c, data) ->
+        tree = c.tree 'a'
+        tree.deliver data
+        tree.then "#{multiplier}", (c, d) ->
+          c.branch 'doubled', (b, data) ->
+            data * 2
+          c.branch 'tripled', (b, data) ->
+            btree = b.continue
+            btree.deliver data
+            btree.then 'btreethen', (c, data) ->
+              data * 3
+      t = Root()
+      t.deliver 5
+      .contest "contest-multiply", [
+        multiply.bind @, 2
+        multiply.bind @, 3
+      ], (c, results) ->
+        paths = results.map (r) -> r.path
+        idx = paths.indexOf 'root-tripled-btreethen'
+        results[idx]
+      .finally 'end',   (c, res) ->
+        chai.expect(res).to.eql [15]
+        done()
+
+  describe 'promise chain after branching', ->
+    it 'should walk the promise chain of the branch', (done) ->
+      multiply = (multiplier, c, data) ->
+        tree = c.tree 'a'
+        tree.deliver data
+        tree.then "#{multiplier}", (c, d) ->
+          c.branch 'doubled', (b, data) ->
+            data * 2
+          c.branch 'tripled', (b, data) ->
+            data
+          .then 'bthen0', (c, data) ->
+            data
+          .then 'bthen1', (c, data) ->
+            data * 3
+      t = Root()
+      t.deliver 5
+      .contest "contest-multiply", [
+        multiply.bind @, 2
+        multiply.bind @, 3
+      ], (c, results) ->
+        paths = results.map (r) -> r.path
+        idx = paths.indexOf 'root-tripled-bthen0-bthen1'
+        results[idx]
+      .finally 'end',   (c, res) ->
+        chai.expect(res).to.eql [15]
+        done()
+
+  describe 'two consecutive negative results in the promise chain', ->
+    it 'finally should once be called once', (done) ->
+      multiply = (multiplier, orig, data) ->
+        tree = orig.tree 'a'
+        tree.deliver data
+        tree.then (c, d) ->
+          c.abort "I would've returned #{d*multiplier}, but chose not to"
+      t = Root()
+      t.deliver 5
+      .maybe [
+        multiply.bind @, 2
+        multiply.bind @, 3
+      ]
+      .else (c, res) ->
+        res * 2
+      .finally (c, res) ->
+        done()
+
+  describe 'using subtree with continue', ->
+    it 'should generate good path', (done) ->
+      treeComposition = (c, d) ->
+        sub = c.continue 'subtree_c'
+        sub.deliver d
+        sub.then 'subthen0', (c, d) ->
+          d
+        .then 'subthen1', (c, d) ->
+          d
+      t = Root()
+      t.deliver 10
+      .then 'then0', (c, d) ->
+        d
+      .all 'allin', [
+        treeComposition.bind @
+        treeComposition.bind @
+      ]
+      .then 'then1', (c, d) ->
+        d
+      .finally (c, d) ->
+        exp = {
+          path: [
+             'then0',
+             'allin',
+             'subtree_c',
+             'subthen0',
+             'subthen1',
+             'then1']
+          children: []
+        }
+        chai.expect(c.toSong()).to.eql exp
+        done()
+
+  describe 'when branching', ->
+    it 'the available items should be copied to the root choice of the branch', (done) ->
+      multiply = (multiplier, c, data) ->
+        tree = c.tree 'a'
+        tree.deliver data
+        tree.then "#{multiplier}", (c, d) ->
+          c.branch 'tripled', (b, data) ->
+            data is b.attributes.items.length
+      t = Root()
+      t.deliver
+        config:
+          name: 'test'
+          type: 'test'
+        items: [
+          'item1'
+          'item2'
+          ]
+      .then (c, d) ->
+        c.source.attributes.items.length
+      .contest "contest-multiply", [
+        multiply.bind @, 2
+      ], (c, results) ->
+        results[0]
+      .finally 'enfin-fini', (c, res) ->
+        chai.expect(res[0]).to.be.true
+        done()


.

Former-commit-id: 6a097b8363494f296abe79069550af50bd5b4336 [formerly edf7a01538e9aea10bdd255036df1cff67563291] [formerly 9753463fc4d7a1e70271b1a82cae7d1382393fcd [formerly 8d840b53b8b756bd51486c176ceecc3c56598f89]] [formerly 63559c2ce83275c2c52d234197218e7df0cd9a06 [formerly ae85eaf923ebeb3c49d512299e852898a6af407e] [formerly 8f11233c718e5ed3a01de1c3ecdcecac85ded6ce [formerly 8f11233c718e5ed3a01de1c3ecdcecac85ded6ce [formerly d63994648204fe58151c313c059dff55cc8f4ac6]]]]
Former-commit-id: a74880ebe7f138453053cabc6f00ec4a33ae6e37 [formerly 38168ae469d189d31b964f78ea22a595270a5613] [formerly 3b6125dd9fb38d2573daebc3ca98645ab63279fd [formerly 10af0cf0f605f55388bac815433aebc066af4434]]
Former-commit-id: 31c042601bd0db07212bd7577116a13f795ba627 [formerly a06101519ab3c716959b1ca5ce7e97d69cb3ffcf]
Former-commit-id: 002f6e43a576557b20e05bc651b642db826a19cd
Former-commit-id: 6a674c80879d7b7cc8746968c3f2120572f59cd9

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -681,14 +681,14 @@
           style:
             position: 'absolute'
             left: '50%'
-            width: 600
-            marginLeft: -300
+            width: 650
+            marginLeft: -325
             top: 25
             fontSize: 41
             textAlign: 'center'
             borderBottom: '1px solid black'

-          "The discussion will begin soon!"
+          "The Discussion will begin July 10!"

         IMG
@@ -790,12 +790,17 @@
                   marginBottom: 18
                 "Thanks for your time,"

-              IMG
-                src: asset('seattle2035/DPDLogo.svg')
+              A
+                href: 'http://www.seattle.gov/dpd/cityplanning/default.htm'
+                target: '_blank'
                 style:
-                  height: 50
                   display: 'block'
                   marginBottom: 8
+
+                IMG
+                  src: asset('seattle2035/DPDLogo.svg')
+                  style:
+                    height: 60

               DIV


fix supports, variable naming consistency

--- lib/index.coffee
+++ lib/index.coffee
@@ -8,14 +8,14 @@

 exports.supports = supports = (name) ->
   name = adapter_to_name(name)
-  !!glob.sync("#{path.join(__dirname, 'adapters', name)}.*").length
+  !!glob.sync("#{path.join(__dirname, 'adapters', name)}").length

-exports.load = (name, custom_path, engineName) ->
+exports.load = (name, custom_path, engine_name) ->
   name = adapter_to_name(name)
   engine_path = resolve_engine_path(name, custom_path)
   version = get_version(engine_path)
   adapter_name = match_version_to_adapter(name, version)
-  return new (require(adapter_name))(engineName, custom_path)
+  return new (require(adapter_name))(engine_name, custom_path)

 exports.all = ->
   indx(path.join(__dirname, 'adapters'))


document lib/index

document lib/index

--- lib/index.coffee
+++ lib/index.coffee
@@ -22,18 +22,46 @@
     @extensions = new Extensions(@)
     @config = new Config(@)

+  ###*
+   * Alternate constructor, creates a new roots project in a given folder and
+   * returns a roots instance for this project. Takes an object with these keys:
+   *
+   * path: path to the folder you'd like to create and initialize a project in
+   * template: name of the template you'd like to use (default: base)
+   * options: additional options to pass to sprout
+   *
+   * @param  {Object} opts - options object, described above
+   * @return {Function} Roots class instance
+  ###
+
   @new: (opts) ->
     n = new (require('./api/new'))(@)
     n.exec(opts).on('done', (root) => if opts.done then opts.done(new @(root)))
     return n

+  ###*
+   * Exposes an API to manage your roots project templates through sprout.
+   * See api/template for details.
+  ###
+
   @template: require('./api/template')
+
+  ###*
+   * Compiles a roots project. Wow.
+   * @return {Function} instance of itself for chaining
+  ###

   compile: ->
     # TODO: does this actually provide a speed boost?
     Compile = require('./api/compile')
     (new Compile(@)).exec()
     return @
+
+  ###*
+   * Watches a folder for changes and compiles whenever changes happen.
+   *
+   * @return {Function} instance of itself for chaining
+  ###

   watch: ->
     (new (require('./api/watch'))(@)).exec()
@@ -62,39 +90,3 @@
     process.exit(code)

 module.exports = Roots
-
-###
-
-What's Going On Here?
----------------------
-
-Welcome to the main entry point to roots! Through this very file, all the
-magic happens. Roots' code is somewhat of a work of art for me, something I
-strive to make as beautiful as functional, and consequently something I am
-hardly ever totally happy with because as soon as I learn or improve, I start
-seeing more details that could be smoothed out.
-
-Anyways, let's jump into it. This file exposes the main roots class and public
-API to roots. Everything within roots is loaded as lazily as possible, and
-uses dependency injection to share context between the different classes that
-make up roots. This allows a pretty significant speed boost, since for
-example, none of the deps for watch are loaded. The only code loaded is the
-code you need, which not only is good for performance, but also forces a very
-clean and separated API design. You can find all the individual method classes
-in the api folder.
-
-All roots' public API methods expose event emitters. Compile and watch expose
-the same emitter, while new exposes a slightly different one.
-
-The new class method is a bit of an anomaly. Since you do not technically have
-a roots project if you are running new, it is exposed as a class method and
-can optionally be an alternate constructor as well -- if you pass in a
-callback, it will not only initialize your project, but also pass you back a
-fully loaded roots instance configured to your new project.
-
-The compile and watch methods do more or less what you would expect - compile
-the project, and watch the project for changes then compile. The compile
-function runs once off, while the watch function will hang until you exit the
-process somehow.
-
-###


Made error messages have more consistant capitalization

--- lib/index.coffee
+++ lib/index.coffee
@@ -105,8 +105,8 @@
       return callback 'Missing opData' unless typeof opData is 'object'
       return callback 'Missing create type' if opData.create and typeof opData.create.type isnt 'string'

-      return callback 'invalid src' if opData.src? and typeof opData.src isnt 'string'
-      return callback 'invalid seq' if opData.seq? and typeof opData.seq isnt 'number'
+      return callback 'Invalid src' if opData.src? and typeof opData.src isnt 'string'
+      return callback 'Invalid seq' if opData.seq? and typeof opData.seq isnt 'number'
       return callback 'seq but not src' if !!opData.seq isnt !!opData.src

       ot.normalize opData


Logging; do not log the tab Id.

Logging; do not log the tab Id.

The frame Ids are sufficiently distinct.  And we do not always have
enough horizontal space to keep log messages on a single line.

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -384,7 +384,7 @@

 # For debugging only. This allows content scripts to log messages to the extension's logging page.
 bgLog = (request, sender) ->
-  BgUtils.log "#{sender.tab.id}/#{request.frameId} #{request.message}", sender
+  BgUtils.log "#{request.frameId} #{request.message}", sender

 # Port handler mapping
 portHandlers =


Fix indentation so that `openerTabId` takes effect

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -202,7 +202,7 @@
         index: tab.index + 1
         selected: true
         windowId: tab.windowId
-      openerTabId: tab.id
+        openerTabId: tab.id
       callback = (->) unless typeof callback == "function"
       chrome.tabs.create tabConfig, callback


added test __validateContentProvider (dummy)

--- test/main.coffee
+++ test/main.coffee
@@ -42,3 +42,17 @@
         expect(fn({encoding:'unknown', somekey:'somevalue'})).to.deep.equal { encoding: 'unknown' , somekey:'somevalue', prefix: '@', postfix: '', contentProvider:null }

+    describe '#__validateContentProvider()', ->
+
+      fn = metaEngine1.__validateContentProvider
+
+      it 'existance', ->
+
+        expect(metaEngine1).to.have.property('__validateContentProvider').that.is.a('function')
+
+      it.skip 'input-output sets', ->
+
+        # expect(fn()).to.deep.equal { encoding: 'utf8', prefix: '@', postfix: '', contentProvider:null }
+
+
+


Move instantiate() and Add Documentation

--- src/coffee/experimental-controller.coffee
+++ src/coffee/experimental-controller.coffee
@@ -1,8 +1,12 @@
 qbnApp = angular.module 'qbnApp', []

-class Quality
-  constructor: (@name, @defaultValue) ->
-
+# The immutable objects that make up the game itself serve as prototypes for the objects that make
+# up the mutable game state. This function takes a game definition object and makes a state
+# instance of it.
+#
+# By convention, any property on the prototype of the form "defaultThing" will be copied on the
+# instance as a property called "thing". This is to allow easy instantiation of default, starting
+# values.
 instantiate = (proto) ->
   instance = Object.create proto
   for key, value of proto when /^default\w{2}/.test(key)
@@ -10,6 +14,9 @@
     newName = first.toLowerCase() + rest
     instance[newName] = value
   return instance
+
+class Quality
+  constructor: (@name, @defaultValue) ->

 class Storylet
   constructor: (@title, @text, @choices) ->


add cleanliness checks

add cleanliness checks

--- test/sync.coffee
+++ test/sync.coffee
@@ -52,6 +52,11 @@
   .then ->
     utils.cmd "#{tmpWorkspace}/#{repo}", "git commit -m \"#{msg}\""

+isClean = (repo)->
+  nodegit.Repository.open("#{tmpWorkspace}/#{repo}").then (repo) ->
+    repo.getStatus().then (statuses)->
+      Promise.resolve statuses.length == 0
+
 getCommits = (repo)->
   commits = []
   nodegit.Repository.open("#{tmpWorkspace}/#{repo}")
@@ -116,6 +121,7 @@
             getCommits('server').should.eventually.have.property("length").equal(2)
             utils.readFile("./#{tmpWorkspace}/server/README.md").should.eventually.equal(readmeContents)
             getCommits('client').should.eventually.have.property("length").equal(2)
+            isClean("server").should.eventually.equal(true)
           ])

     it "should sync a save that is not committed", ->
@@ -132,6 +138,7 @@
                 getCommits('server').should.eventually.have.property("length").equal(2)
                 getCommits('client').should.eventually.have.property("length").equal(2)
                 utils.readFile("./#{tmpWorkspace}/server/README.md").should.eventually.equal(newReadme)
+                isClean('server').should.eventually.equal(false)
               ])

@@ -143,6 +150,7 @@
             getCommits('server').should.eventually.have.property("length").equal(2)
             getCommits('client').should.eventually.have.property("length").equal(2)
             utils.readFile("./#{tmpWorkspace}/server/README.md").should.eventually.equal(newReadme)
+            isClean('server').should.eventually.equal(false)
           ])

     it "remote repo should be clean after the user makes a commit"


clean task tests

clean task tests

--- test/task.coffee
+++ test/task.coffee
@@ -17,7 +17,8 @@
 initDb = (callback) ->
     async.series [
         helpers.createTodoListFunction "My Tasks", "/all/my-tasks"
-        helpers.createTodoListFunction "", "/all/recipe/dessert"
+        helpers.createTodoListFunction "Recipe", "/all/recipe"
+        helpers.createTodoListFunction "Dessert", "/all/recipe/dessert"
     ], ->
         callback()


Add tests about macro

Add tests about macro

--- test/test.coffee
+++ test/test.coffee
@@ -64,4 +64,18 @@
       expect(Lisp.eval("""
         (defun sum (x y) (+ x y))
         (sum 1 2)
-        """).body).to.equal('3')+        """).body).to.equal('3')
+
+    it 'should can assign value', ->
+      expect(Lisp.eval("""
+        (setq a 10)
+        a
+      """).body).to.equal('10')
+
+    it 'should can define and use macro', ->
+      expect(Lisp.eval("""
+        (defmacro nil! (var)
+          (list 'setq var nil))
+        (nil! a)
+        a
+        """).body).to.equal('nil')


adding another test case

adding another test case

--- test/util.coffee
+++ test/util.coffee
@@ -17,3 +17,6 @@

         it 'should resolve playhead, with percents', ->
             resolve("http://test.com/%%CONTENTPLAYHEAD%%", CONTENTPLAYHEAD: 120).should.equal "http://test.com/120"
+
+        it 'should resolve weird cases', ->
+            resolve("http://test.com/%%CONTENTPLAYHEAD%%&[CONTENTPLAYHEAD]", CONTENTPLAYHEAD: 120).should.equal "http://test.com/120&120"


Added ' =>' to the function name highlighting regex in grammar.

--- grammars/dart.cson
+++ grammars/dart.cson
@@ -165,7 +165,7 @@
         'name': 'support.class.dart'
       }
       {
-        'match': '(_?[a-z][a-zA-Z0-9]+)\\('
+        'match': '(_?[a-z][a-zA-Z0-9]+)(\\(|\\s+=>)'
         'captures':
           '1':
             'name': 'entity.name.function.dart'


Mark multiple leading apostrophes as comment sequences

Empty control-lines were sometimes prefixed with multiple apostrophes in
classical troff source (e.g., tests/fixtures/plan9-tmac.mcs.tr).

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -191,7 +191,7 @@

 			# Comments
 			name: "comment.line.roff"
-			begin: "(?:^([.'])\\s*)?(\\\\\")"
+			begin: "(?:^(.|'+)\\s*)?(\\\\\")"
 			end: "$"
 			beginCaptures:
 				1: {name: "punctuation.definition.comment.roff"}
@@ -200,7 +200,7 @@

 			# Empty control lines
 			name: "comment.empty.roff"
-			match: "^([.'])[ \t]*$"
+			match: "^(.|'+)[ \t]*$"
 			captures:
 				1: {name: "punctuation.definition.comment.roff"}
 		},


updating grammar

updating grammar

--- grammars/stan.cson
+++ grammars/stan.cson
@@ -1,233 +1,130 @@
-'name' "Stan"
+'name': "Stan"
 'scopeName': "source.stan"
-'fileTypes': "stan"
+'fileTypes': [ "stan" ]
 'patterns': [
-	{
-		include: "#double-slash"
-	}
-	{
-		include: "#pound-sign"
-	}
-	{
-		include: "#block-comment"
-	}
-	{
-		begin: "^\\s*(data|transformed data|parameters|transformed parameters|model|generated quantities|functions)\\s*{"
-		end: "}"
-		beginCaptures:
-			"1":
-				name: "keyword.control.block-names.stan"
-		contentName: "meta.block.major.stan"
-		patterns: [
-			{
-				include: "#double-slash"
-			}
-			{
-				include: "#pound-sign"
-			}
-			{
-				include: "#block-comment"
-			}
-			{
-				include: "#string"
-			}
-			{
-				include: "#type"
-			}
-			{
-				include: "#range"
-			}
-			{
-				include: "#control-flow"
-			}
-			{
-				include: "#cpp-conflict"
-			}
-			{
-				include: "#distributions"
-			}
-			{
-				include: "#cdfs"
-			}
-			{
-				include: "#spec-vals"
-			}
-			{
-				include: "#math-fns"
-			}
-			{
-				include: "#other-fns"
-			}
-			{
-				include: "#lp"
-			}
-			{
-				include: "#double-underscore"
-			}
-			{
-				include: "#vars"
-			}
-			{
-				include: "#real-a"
-			}
-			{
-				include: "#real-b"
-			}
-			{
-				include: "#real-c"
-			}
-			{
-				include: "#integer"
-			}
-			{
-				include: "#block"
-			}
-		]
-	}
-	{
-		match: "[^\\s]+(\\s*[^\\s]+)?"
-		name: "invalid.illegal.top-level"
-	}
+  {
+    include: "#comment-number-sign"
+  }
+  {
+    include: "#comment-block-comment"
+  }
+  {
+    include: "#comment-double-slash"
+  }
+  {
+    include: "#string"
+  }
+  {
+    include: "#block-declaration"
+  }
+  {
+    include: "#control-flow"
+  }
+  {
+    include: "#type"
+  }
+  {
+    include: "#range"
+  }
+  {
+    include: "cpp-reserved"
+  }
+  {
+    include: "#lp"
+  }
+  {
+    include: "#specia-functions"
+  }
+  {
+    include: "#vars"
+  }
+  {
+    include: "#illegal-variable-1"
+  }
+  {
+    include: "#illegal-variable-2"
+  }
+  {
+    include: "#real-a"
+  }
+  {
+    include: "#real-b"
+  }
+  {
+    include: "#real-c"
+  }
+  {
+    include: "#integer"
+  }
 ]
 repository:
-	"double-slash":
-		match: "//.*$"
-		name: "comment.line.double-slash.stan"
-	"pound-sign":
-		match: "#.*$"
-		name: "comment.line.number-sign.stan"
-	"block-comment":
-		begin: "/\\*"
-		end: "\\*/"
-		name: "comment.block.slashes"
-	string:
-		begin: "\""
-		end: "\""
-		name: "string.quoted.double.stan"
-		patterns: [
-			{
-				match: "(\\p{^ASCII}|\\p{Cntrl}|\\\\)+"
-				name: "invalid.illegal.quoted.bad-char.stan"
-			}
-		]
-	type:
-		match: "\\b(int|real|vector|simplex|ordered|positive_ordered|row_vector|matrix|corr_matrix|cov_matrix)\\b"
-		name: "storage.type.stan"
-	"cpp-conflict":
-		match: "\\b(alignas|alignof|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|false|float|friend|goto|if|inline|long|mutable|namespace|new|noexcept|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|true|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while|xor|xor_eq)\\b"
-		name: "invalid.illegal.cpp-conflict.stan"
-		comment: "reserved words in C++ that are invalid in Stan"
-	range:
-		match: "\\b(lower|upper)\\b"
-		name: "keyword.other.range.stan"
-	"control-flow":
-		match: "\\b(for|in|while|repeat|until|if|then|else|return)\\b"
-		name: "keyword.control.stan"
-	distributions:
-		match: "\\b(bernoulli|bernoulli_logit|binomial|binomial_logit|beta_binomial|hypergeometric|categorical|ordered_logistic|neg_binomial|poisson|poisson_log|multinomial|normal|student_t|cauchy|double_exponential|logistic|lognormal|chi_square|inv_chi_square|scaled_inv_chi_square|exponential|gamma|inv_gamma|weibull||pareto|beta|uniform|dirichlet|multi_normal|multi_normal_cholesky|multi_student_t|wishart|inv_wishart|lkj_cov|lkj_corr|lkj_corr_cholesky_log)(_log)?\\b"
-		name: "support.function.distribution.pdf.stan"
-	cdfs:
-		match: "\\b(normal|lognormal|exponential|weibull)_cdf\\b"
-		name: "support.function.distribution.cdf.stan"
-	"spec-vals":
-		match: "\\bnot_a_number|positive_infinity|negative_infinity|epsilon|negative_epsilon\\b"
-		name: "support.function.special-value.stan"
-	"math-fns":
-		match: "\\b(abs|int_step|fabs|fdim|min|max|pi|e|sqrt2|log2|log10|if_else|step|fmin|fmax|fmod|floor|ceil|round|trunc|sqrt|cbrt|square|exp|exp2|log|pow|hypot|cos|sin|tan|acos|asin|atan|atan2|cosh|sinh|tanh|acosh|asinh|atanh|logit|inv_logit|inv_cloglog|erf|erfc|Phi|Phi_approx|binary_log_loss|tgamma|lgamma|lmgamma|lbeta|binomial_coefficient_log|expm1|fma|multiply_log|log1p|log1m|log1p_exp|log_sum_exp|log_inv_logit|log1m_inv_logit|sum|prod|mean|variance|sd|rows|cols|cumulative_sum|dot_product|dot_self|tcrossprod|crossprod|multiply_lower_tri_self_transpose|diag_pre_multiply|diag_post_multiply|diagonal|diag_matrix|col|row|block|softmax|mdivide_right_tri_low|mdivide_left_tri_low|trace|determinant|inverse|eigenvalues_sym|eigenvectors_sym|cholesky_decompose|singular_values)\\b"
-		name: "support.function.math.stan"
-	"other-fns":
-		match: "\\bprint\\b"
-		name: "support.function.other.stan"
-	lp:
-		match: "\\blp__\\b"
-		name: "variable.language.logprob.stan"
-	"double-underscore":
-		match: "\\b[a-zA-Z][a-zA-Z0-9_]*__\\b"
-		name: "invalid.illegal.variable.double-underscore.stan"
-	vars:
-		match: "\\b[a-zA-Z][a-zA-Z0-9_]*\\b"
-		name: "variable.other.stan"
-	"real-a":
-		match: "-?(0|[1-9]\\d*)?\\.\\d+([eE]-?(0|[1-9]\\d*))?"
-		comment: "have a point with numbers after, maybe an exponent"
-		name: "constant.numeric.real.stan"
-	"real-b":
-		match: "-?(0|[1-9]\\d*)\\.\\d*([eE]-?(0|[1-9]\\d*))?"
-		comment: "have a point with numbers before, maybe an exponent"
-		name: "constant.numeric.real.stan"
-	"real-c":
-		match: "-?(0|[1-9]\\d*)[eE]-?(0|[1-9]\\d*)"
-		comment: "no point, have an exponent"
-		name: "constant.numeric.real.stan"
-	integer:
-		match: "-?(0|[1-9]\\d*)"
-		name: "constant.numeric.integer.stan"
-	block:
-		begin: "{"
-		end: "}"
-		contentName: "meta.block.minor.stan"
-		patterns: [
-			{
-				include: "#double-slash"
-			}
-			{
-				include: "#pound-sign"
-			}
-			{
-				include: "#block-comment"
-			}
-			{
-				include: "#string"
-			}
-			{
-				include: "#type"
-			}
-			{
-				include: "#range"
-			}
-			{
-				include: "#control-flow"
-			}
-			{
-				include: "#cpp-conflict"
-			}
-			{
-				include: "#distributions"
-			}
-			{
-				include: "#cdfs"
-			}
-			{
-				include: "#spec-vals"
-			}
-			{
-				include: "#math-fns"
-			}
-			{
-				include: "#other-fns"
-			}
-			{
-				include: "#lp"
-			}
-			{
-				include: "#double-underscore"
-			}
-			{
-				include: "#vars"
-			}
-			{
-				include: "#real-a"
-			}
-			{
-				include: "#real-b"
-			}
-			{
-				include: "#real-c"
-			}
-			{
-				include: "#integer"
-			}
-			{
-				include: "#block"
-			}
-		]
+  "comment-double-slash":
+    match: "//.*$"
+    name: "comment.line.double-slash.stan"
+  "comment-number-sign":
+    match: "#.*$"
+    name: "comment.line.number-sign.stan"
+  "comment-block-comment":
+    begin: "/\\*"
+    end: "\\*/"
+    name: "comment.block.slashes"
+  string:
+    begin: "\""
+    end: "\""
+    name: "string.quoted.double.stan"
+    patterns: [
+      {
+        match: "(\\p{^ASCII}|\\p{Cntrl}|\\\\)+"
+        name: "invalid.illegal.quoted.bad-char.stan"
+      }
+    ]
+  "block-declaration":
+    match: "\\b(data|transformed\\s+data|parameters|transformed\\s+parameters|model|generated\\s+quantities|functions)\\b"
+    name: "entity.name.type.stan'
+  type:
+    match: "\\b(int|real|vector|simplex|ordered|positive_ordered|row_vector|matrix|corr_matrix|cov_matrix|cholesky_factor_cov|cholesky_factor_corr|void)\\b"
+    name: "storage.type.stan"
+  "control-flow":
+    match: "\\b(for|in|while|repeat|until|if|then|else|return)\\b"
+    name: "keyword.control.stan"
+  "truncation-operator":
+    match: "\\bT\\s*\["
+    name: "keyword.other.truncation.stan"
+  "cpp-reserved":
+    match: "\\b(alignas|alignof|and|and_eq|asm|auto|bitand|bitor|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|false|float|friend|goto|if|inline|long|mutable|namespace|new|noexcept|not|not_eq|nullptr|operator|or|or_eq|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|true|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while|xor|xor_eq)\\b"
+    name: "invalid.illegal.cpp-conflict.stan"
+    comment: "reserved words in C++ that are invalid in Stan"
+  range:
+    match: "\\b(lower|upper)\\b"
+    name: "keyword.other.range.stan"
+  "special-functions":
+    match: "\\b(print|reject|integrate_ode|increment_log_prob)\\b"
+    name: "keyword.other.special-functions.stan"
+  lp:
+    match: "\\blp__\\b"
+    name: "invalid.deprecated.lp.stan"
+  vars:
+    match: "\\b[a-zA-Z][a-zA-Z0-9_]*\\b"
+    name: "variable.other.stan"
+  "illegal-variable-1":
+    match: "\\b[a-zA-Z][a-zA-Z0-9_]*__\\b"
+    name: "invalid.illegal.variable.double-underscore.stan"
+  "illegal-variable-2":
+    match: "\\b[0-9_]+[a-zA-Z_]+[a-zA-Z0-9_]*\\b"
+    name: "invalid.illegal.variable.nonalphafirst"
+  "real-a":
+    match: "-?(0|[1-9]\\d*)?\\.\\d+([eE]-?(0|[1-9]\\d*))?"
+    comment: "have a point with numbers after, maybe an exponent"
+    name: "constant.numeric.real.stan"
+  "real-b":
+    match: "-?(0|[1-9]\\d*)\\.\\d*([eE]-?(0|[1-9]\\d*))?"
+    comment: "have a point with numbers before, maybe an exponent"
+    name: "constant.numeric.real.stan"
+  "real-c":
+    match: "-?(0|[1-9]\\d*)[eE]-?(0|[1-9]\\d*)"
+    comment: "no point, have an exponent"
+    name: "constant.numeric.real.stan"
+  integer:
+    match: "-?(0|[1-9]\\d*)"
+    name: "constant.numeric.integer.stan"
+


remove comment

remove comment

--- src/desktop/apps/home/client/index.coffee
+++ src/desktop/apps/home/client/index.coffee
@@ -20,7 +20,6 @@
 sd = require('sharify').data
 _ = require 'underscore'
 _s = require 'underscore.string'
-# Waypoint = require("waypoint")

 module.exports.HomeView = class HomeView extends Backbone.View

@@ -30,7 +29,6 @@
     Backbone.history.start pushState: true

     targetElement = if sd.HOMEPAGE_COLLECTION_HUB_ENTRYPOINTS_TEST_QA is "experiment" then ".home-hubs-entry" else ".home-browse-module"
-    # .home-browse-module

     # Remove after closing the homepage hubs entry points test
     $(targetElement).waypoint(() ->


Speed up drone

Speed up drone

--- src/lazerscripts/stage1/army_drone.coffee
+++ src/lazerscripts/stage1/army_drone.coffee
@@ -65,7 +65,7 @@
     d = Crafty.e('Drone').drone(
       x: Crafty.viewport.width + 40
       y: Crafty.viewport.height / 2
-      defaultSpeed: options.speed ? 300
+      defaultSpeed: options.speed ? 400
       juice: options.juice
     )
     @juice = options.juice
@@ -80,6 +80,7 @@
               w: 10
               h: 10
               damage: 1
+              speed: 500
             )
           projectile.shoot(x, y, angle)
     d
@@ -87,6 +88,12 @@
   execute: ->
     @bindSequence 'Destroyed', @onKilled
     @movePath [
+
+      [.5, .21]
+      [.156, .5]
+      [.5, .833]
+      [.86, .52]
+
       [.5, .21]
       [.156, .5]
       [.5, .833]


Explicitly include the return for readability

--- github.coffee
+++ github.coffee
@@ -551,7 +551,7 @@
               return file?.sha if file?.sha

               # Return a promise that has failed if no sha was found
-              (new jQuery.Deferred()).reject {message: 'SHA_NOT_FOUND'}
+              return (new jQuery.Deferred()).reject {message: 'SHA_NOT_FOUND'}

             # Return the promise
             .promise()


#13 Don't print sock banner

#13 Don't print sock banner

--- src/sockjs.coffee
+++ src/sockjs.coffee
@@ -54,10 +54,6 @@

 class Server extends events.EventEmitter
     constructor: (user_options) ->
-        if not exports.banner_printed and
-                (not('banner' of user_options) or user_options.banner is True)
-            exports.banner_printed = true
-            print_banner()
         @options =
             prefix: ''
             response_limit: 128*1024
@@ -74,6 +70,8 @@
         utils.objectExtend(options, @options)
         if user_options
             utils.objectExtend(options, user_options)
+        console.log('SockJS v' + sockjs_version() + ' ' +
+                    'started on ' + JSON.stringify(options.prefix))

         p = (s) => new RegExp('^' + options.prefix + s + '[/]?$')
         t = (s) => [p('/([^/.]+)/([^/.]+)' + s), 'server', 'session']
@@ -128,16 +126,10 @@
         return true

-print_banner = ->
+sockjs_version = ->
     try
         package = fs.readFileSync(__dirname + '/../package.json', 'utf-8')
     catch x
-    if package
-        version = JSON.parse(package).version
-    else
-        version = 'unknown'
-
-    console.log(" _---\\\n\\     \\\n \\     \\         SockJS-node server\n  \\     \\\n   \\    \\        Version " + version + "\n    \\    \\\n    /     |      Node.js server side counterpart of\n   /    -/       SockJS-client browser library\n,-'    /\n\\___--'\n")
+    return if package then JSON.parse(package).version else null

 exports.Server = Server
-exports.banner_printed = false


Failing tests.

Failing tests.

--- spec/git-spec.coffee
+++ spec/git-spec.coffee
@@ -453,23 +453,34 @@
       it 'returns the status of the given path', ->
         expect(repo.getStatus('a.txt')).toBe 1 << 9

-  describe '.getStatusForPaths([paths])', ->
-    beforeEach ->
-      repoDirectory = temp.mkdirSync('node-git-repo-')
-      wrench.copyDirSyncRecursive(path.join(__dirname, 'fixtures/master.git'), path.join(repoDirectory, '.git'))
-      repo = git.open(repoDirectory)
-
-      newDir = path.join(repo.getWorkingDirectory(), 'secret-stuff')
-      fs.mkdirSync(newDir)
-
-      newFilePath = path.join(newDir, 'b.txt')
-      fs.writeFileSync(newFilePath, '', 'utf8')
+  fdescribe '.getStatusForPaths([paths])', ->
+    repoDirectory = null
+    filePath = null
+    beforeEach ->
+      repoDirectory = temp.mkdirSync('node-git-repo-')
+      console.log(repoDirectory)
+      wrench.copyDirSyncRecursive(path.join(__dirname, 'fixtures/subdir.git'), path.join(repoDirectory, '.git'))
+      repo = git.open(repoDirectory)
+
+      dir = path.join(repo.getWorkingDirectory(), 'dir')
+      filePath = path.join(dir, 'a.txt')
+      fs.writeFileSync(filePath, 'hey there', 'utf8')

     describe 'when a path is specified', ->
       it 'returns the status of only that path', ->
-        statuses = repo.getStatusForPaths(['secret-stuff'])
+        statuses = repo.getStatusForPaths(['dir'])
         expect(_.keys(statuses).length).toBe 1
-        expect(statuses['secret-stuff/b.txt']).toBe 1 << 7
+
+        status = statuses['dir/a.txt']
+        console.log(status)
+        expect(repo.isStatusModified(status)).toBe true
+        expect(repo.isStatusNew(status)).toBe false
+
+      it 'returns the status of only that path2', ->
+        fs.writeFileSync(filePath, '', 'utf8')
+
+        statuses = repo.getStatusForPaths(['dir'])
+        expect(_.keys(statuses).length).toBe 0

     describe 'when no path is specified', ->
       it 'returns an empty object', ->


lib/marie.coffee

lib/marie.coffee

--- lib/marie.coffee
+++ lib/marie.coffee
@@ -87,14 +87,18 @@
 	update: (app) =>
 		ui.warn 'update command'

+
 	list: (app) =>
 		ui.warn 'list command'

+
 	remove: (app) =>
 		ui.warn 'remove command'

+
 	start: (app) =>
 		ui.warn 'start command'
+

 	stop: (app) =>
 		ui.warn 'stop command'


Improve coffeescript formatting

Improve coffeescript formatting

--- homedisplay/repeating_tasks/static/js/repeating_tasks.coffee
+++ homedisplay/repeating_tasks/static/js/repeating_tasks.coffee
@@ -14,7 +14,7 @@
       overdue_by = ""
       if @fields.last_completed_at
         diff = moment(@fields.last_completed_at).add @fields.repeat_every_n_seconds, "seconds"
-        overdue_by = " (" + diff.fromNowSynced() + ")"
+        overdue_by = " (#{diff.fromNowSynced()})"

       if @fields.optional
         icon = "fa-question-circle"
@@ -46,7 +46,7 @@

       task_history = jq "#confirm-repeating-task .task-history ul"
       task_history.children().remove()
-      tasks = JSON.parse repeating_task.data("history")
+      tasks = JSON.parse repeating_task.data "history"
       jq.each tasks, ->
         parsed = moment @fields.completed_at
         task_history.append "
" + parsed.format("YYYY-MM-DD") + " (" + parsed.fromNowSynced() + ")
"


Changed warning style name to warn

Changed warning style name to warn

--- src/styler.coffee
+++ src/styler.coffee
@@ -6,7 +6,7 @@

 styles256 =
     error: chalk("#e74c3c")
-    warning: chalk("#f39c12")
+    warn: chalk("#f39c12")
     info: chalk("#00d7ff")
     verbose: chalk("#5fffd7")

@@ -20,7 +20,7 @@

 styles16 =
     error: chalk.red
-    warning: chalk.yellow
+    warn: chalk.yellow
     info: chalk.blue
     verbose: chalk.cyan


Removed old debug code.

Removed old debug code.

--- core/app/backbone/factlink/alert_mixin.coffee
+++ core/app/backbone/factlink/alert_mixin.coffee
@@ -12,7 +12,6 @@
     @alertErrorTypes = errorTypes

   alertError: (errorType) ->
-    console.log errorType
     if @alertErrorTypes? and errorType in @alertErrorTypes
       @alertShow 'error-' + errorType
     else


removed erroneous url function

removed erroneous url function

--- core/app/backbone/models/fact_relation.coffee
+++ core/app/backbone/models/fact_relation.coffee
@@ -14,11 +14,4 @@
   believe: -> @setOpinion "believes"
   disbelieve: -> @setOpinion "disbelieves"

-  url: ->
-    evidence_type = "weakening_evidence"
-    evidence_type = "supporting_evidence" if @get("fact_relation_type") is "supporting"
-    url = @collection.fact.url() + "/" + evidence_type
-    url += "/" + @id if @id?
-    url
-
   creator: -> new User(@get('created_by'))


beaglebone-green-wifi.coffee: Set initial versioning and change to 1
the partition holding config.json

Signed-off-by: Florin Sarbu <3a837a37a2ac9072a088641ec330e0e5d5b86f4e@resin.io>

--- beaglebone-green-wifi.coffee
+++ beaglebone-green-wifi.coffee
@@ -11,6 +11,7 @@
 ]

 module.exports =
+	version: 1
 	slug: 'beaglebone-green-wifi'
 	name: 'BeagleBone Green Wireless'
 	arch: 'armv7hf'
@@ -46,8 +47,7 @@
 	configuration:
 		config:
 			partition:
-				primary: 4
-				logical: 1
+				primary: 1
 			path: '/config.json'

 	initialization: commonImg.initialization


Error message on call without 'new'

Error message on call without 'new'

--- lib/pages.coffee
+++ lib/pages.coffee
@@ -54,7 +54,7 @@
         continue  unless i?
         i.stop()
   constructor: (collection, settings) ->
-    unless @ instance of Meteor.Pagination
+    unless @ instanceof Meteor.Pagination
       throw "Please use the `new` constructor style " + (new Error).stack.split("\n")[2].trim()
     @setCollection collection
     @setDefaults()


Clean up the sys.prefix checking

Clean up the sys.prefix checking

--- lib/paths.coffee
+++ lib/paths.coffee
@@ -2,14 +2,12 @@

 path = require('path')

-# Getting access to `sys.prefix` from Python
+# Access `sys.prefix` from Python, to handle particular conda and virtualenv setups
 # TODO: Think of something more sensible here, possibly doing this asynchronously elsewhere
 # TODO: Provide a timeout, handle error
 {execSync} = require('child_process')
 response = execSync 'python -c "import sys; print(sys.prefix)"'
 sysPrefix = response.toString().replace /^\s+|\s+$/g, ""
-
-console.log("Time for some sysPrefix: #{sysPrefix}")

 userHome = ->
   return process.env['HOME'] or process.env['USERPROFILE'] or path.resolve('~')


remove extra tooltip for now

remove extra tooltip for now

--- SingularityUI/app/components/taskSearch/TaskSearchForm.cjsx
+++ SingularityUI/app/components/taskSearch/TaskSearchForm.cjsx
@@ -5,9 +5,6 @@
 DropDown = require '../common/formItems/DropDown'
 DateEntry = require '../common/formItems/DateEntry'
 LinkedFormItem = require '../common/formItems/LinkedFormItem'
-Glyphicon = require '../common/atomicDisplayItems/Glyphicon'
-OverlayTrigger = require 'react-bootstrap/lib/OverlayTrigger'
-ToolTip = require 'react-bootstrap/lib/Tooltip'
 Enums = require './Enums'

 TaskSearchForm = React.createClass
@@ -42,21 +39,10 @@

     getLastTaskStatusTitle: ->
-        lastTaskStatusTitle =

-            {if @props.lastTaskStatus is 'TASK_ERROR'
-                <Glyphicon iconClass='info-sign' /> }
+

             Last Task Status
             {{@props.lastTaskStatusCurrentSearch} if @props.lastTaskStatusCurrentSearch}

-        if @props.lastTaskStatus is 'TASK_ERROR'
-            <OverlayTrigger
-                placement = 'top'
-                overlay = {<ToolTip id='lastTaskStatusTitleTip'>Error is an extremely rare task state. You may have meant to search for 'Failed'</ToolTip>}
-            >
-                {lastTaskStatusTitle}
-            </OverlayTrigger>
-        else
-            lastTaskStatusTitle

     render: ->
         render: ->


Translate special fields in precondition filter

--- lib/query.coffee
+++ lib/query.coffee
@@ -289,6 +289,17 @@
         v = v.replace(/[^a-zA-Z0-9\-]+/g, '_')
         filters["Tags.#{v}"] = true
     else
+      switch k
+        when '_id' then k = 'DeviceID.ID'
+        when '_deviceId._Manufacturer' then k = 'DeviceID.Manufacturer'
+        when '_deviceId._OUI' then k = 'DeviceID.OUI'
+        when '_deviceId._ProductClass' then k = 'DeviceID.ProductClass'
+        when '_deviceId._SerialNumber' then k = 'DeviceID.SerialNumber'
+        when '_lastInform' then k = 'Events.Inform'
+        when '_lastBootstrap' then k = 'Events.0_BOOTSTRAP'
+        when '_lastBoot' then k = 'Events.1_BOOT'
+        when '_registered' then k = 'Events.Registered'
+
       if common.typeOf(v) is common.OBJECT_TYPE
         for kk, vv of v
           switch kk


always ()'ing same-line invocations

always ()'ing same-line invocations

--- src/verify.coffee
+++ src/verify.coffee
@@ -68,15 +68,15 @@
   else
     groups = _.groupBy calls, 'args'
     _.reduce groups, (desc, callsMatchingArgs, args) ->
-      desc + "\n    - called #{pluralize callsMatchingArgs.length, 'time'} with `(#{stringifyArgs(callsMatchingArgs[0].args)})`."
-    , "\n\n  #{pluralize calls.length, 'call'} that satisfied this verification:"
+      desc + "\n    - called #{pluralize(callsMatchingArgs.length, 'time')} with `(#{stringifyArgs(callsMatchingArgs[0].args)})`."
+    , "\n\n  #{pluralize(calls.length, 'call')} that satisfied this verification:"

 pluralize = (x, msg) ->
   "#{x} #{msg}#{if x == 1 then '' else 's'}"

 timesMessage = (config) ->
   return "" unless config.times?
-  " #{pluralize config.times, 'time'}"
+  " #{pluralize(config.times, 'time')}"

 ignoreMessage = (config) ->
   return "" unless config.ignoreExtraArgs?


Fix eventType for the build.

Fix eventType for the build.

This (somehow) ensures that the job page is properly populated.

--- assets/scripts/app/models/build.coffee
+++ assets/scripts/app/models/build.coffee
@@ -29,7 +29,7 @@
   # TODO add eventType to the api for api build requests
   eventType: (->
     if @get('pullRequest') then 'pull_request' else 'push'
-  ).property('pull_request')
+  ).property('pullRequest')

   isPullRequest: (->
     @get('eventType') == 'pull_request' || @get('pullRequest')


added 'retrieve' method to types (polymorphic get everything accessor)

--- lib/types.coffee
+++ lib/types.coffee
@@ -16,6 +16,7 @@
     incrby: ['incrby']
     incrbyfloat: ['incrbyfloat']
     psetnx: ['psetnx']
+    retrieve: ['get']
     set: ['set']
     setbit: ['setbit']
     setex: ['setex']
@@ -35,6 +36,7 @@
     len: ['hlen']
     mget: ['hmget']
     mset: ['hmset']
+    retrieve: ['hgetall']
     set: ['hset']
     setnx: ['hsetnx']
     vals: ['hvals']
@@ -53,6 +55,7 @@
     lpushx: ['lpushx']
     range: ['lrange']
     lrem: ['lrem']
+    retrieve: ['lrange', 0, -1]
     set: ['lset']
     sort: ['sort']
     trim: ['ltrim']
@@ -74,6 +77,7 @@
     members: ['smembers']
     pop: ['spop']
     randmember: ['srandmember']
+    retrieve: ['smembers']
     sort: ['sort']
     srem: ['srem']
     union: ['sunion']
@@ -91,6 +95,7 @@
     zrem: ['zrem']
     remrangebyrank: ['zremrangebyrank']
     remrangebyscore: ['zremrangebyscore']
+    retrieve: ['zrange', 0, -1]
     revrange: ['zrevrange']
     revrangebyscore: ['zrevrangebyscore']
     revrank: ['zrevrank']


WIP - tracking is now start/end not top/bottom (so it applys to H and V scrolling)

--- source/Art/Engine/Elements/Widgets/ScrollElement.coffee
+++ source/Art/Engine/Elements/Widgets/ScrollElement.coffee
@@ -348,7 +348,7 @@
     focusedChildAxis:   default: point0
     focusedParentAxis:  default: point0

-    track:              default: "top"
+    track:              default: "start"
     currentlyTracking:  default: null

     scrollPosition:     default: 0
@@ -377,9 +377,9 @@
         offset = _scrollPos - currentPos
       else
         switch @_pendingState._currentlyTracking ||= @_pendingState._track
-          when "top"
+          when "start"
             _scrollPosition
-          when "bottom"
+          when "end"
             _scrollPosition + mainElementSizeForChildren - mainChildrenSize

     else


Make sure global is something defined

Make sure global is something defined

--- src/window.coffee
+++ src/window.coffee
@@ -24,7 +24,7 @@
         str.toUpperCase()

 # Create a copy of the global object.
-globalRef = global
+globalRef = global or {}

 # Maps the given name to a set of vendor-prefixed names, then looks for these objects in the global namespace
 resolveWindowObject = (name) ->


Remove Focus on list if it's empty (message not found)

--- client/app/components/message.coffee
+++ client/app/components/message.coffee
@@ -289,12 +289,15 @@
             MessageActionCreator.delete messageID: @state.currentMessageID

             # Goto to next message
-            @redirect
-                direction: 'second',
-                action: 'conversation',
-                parameters:
-                    messageID: nextConversation.get('id')
-                    conversationID: nextConversation.get('conversationID')
+            unless nextConversation.size
+                @redirect (url = @buildClosePanelUrl 'second')
+            else
+                @redirect
+                    direction: 'second',
+                    action: 'conversation',
+                    parameters:
+                        messageID: nextConversation.get('id')
+                        conversationID: nextConversation.get('conversationID')

         needConfirmation = @props.settings.get('messageConfirmDelete')
         unless needConfirmation


Client: Fix users with spaces in names and clicking PMs

--- client/app/js/views/chat_view.coffee
+++ client/app/js/views/chat_view.coffee
@@ -136,7 +136,7 @@
     highlight = (new RegExp("\\b#{yourName}\\b", 'i').test(message))

     # Render the chat message
-    u = "<b class='open_pm fake_link' data-user-id=#{username}
+    u = "<b class='open_pm fake_link' data-user-id='#{username}'
       style='color: #{@userColor(username)}'>#{displayName}:</b>"
     @updateChat("#{@timestamp()} #{u} #{@sanitize(message)}", {highlight})


MainController: re-apply clientId checker

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -263,14 +263,13 @@
     # async clientId change checking procedures causes
     # race conditions between window reloading and post-login callbacks
     cookieChangeHandler = do (cookie = kookies.get 'clientId') => =>
-      cookieExists = cookie?
-      cookieMatches = cookie is (kookies.get 'clientId')
-
-      if cookieExists and not cookieMatches
-        return @isLoggingIn off  if @isLoggingIn() is on
-
-        global.removeEventListener 'beforeunload', wc.bound 'beforeUnload'
-        @emit "clientIdChanged"
+      cookieExists      = cookie?
+      cookieMatches     = cookie is (kookies.get 'clientId')
+
+      if not cookieExists or (cookieExists and not cookieMatches)
+        location.reload '/'
+
+      kd.utils.wait 1000, cookieChangeHandler

     # Note: I am using wait instead of repeat, for the subtle difference.  See this StackOverflow answer for more info:
     #       http://stackoverflow.com/questions/729921/settimeout-or-setinterval/731625#731625


根据字段是否允许为空区别对待,允许为空的值为 null, 不允许为空的值为字段定义的 defaultValue

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -50,7 +50,10 @@

       # 如果字段允许为空，且默认值为 null 则在等于空字符串的时候赋值为 null
       if (value in ['', null]) and C.hasOwnProperty('defaultValue')
-        value = C.defaultValue
+        if C.allowNull is no
+          value = null
+        else
+          value = C.defaultValue

       attr[x] = value
     )


Don't use promise when showing dialog

Don't use promise when showing dialog

Promise is only called once so it expires after the first callback

--- client/lanes/access/LoginDialog.cjsx
+++ client/lanes/access/LoginDialog.cjsx
@@ -13,20 +13,23 @@
     statics:
         show: (viewport, props = {}) ->
             session = new Session
-            handler = new _.Promise( (onOk, onCancel) ->
-                viewport.modalProps = _.extend({}, props,
-                    title: 'Please Login'
-                    onCancel: onCancel, onOk: onOk, show: true,
-                    buttons: [{ title: 'Ok', style: 'primary'}]
-                    body: ->
-                        <Lanes.Access.LoginDialog model={session} attemptLogin={onOk} />
-                )
-            )
-            handler.then (dlg) ->
+
+            attemptLogin = (dlg) ->
                 session.save(ignoreErrors: true).then ->
                     if session.user
                         Lanes.current_user.setLoginData(session.user, session.access)
+                        dlg.hide()
                     _.extend(viewport.modalProps, {show: !session.user})
+
+            viewport.modalProps = _.extend({}, props,
+                title: 'Please Login'
+                onCancel: null, onOk: attemptLogin, show: true,
+                buttons: [{ title: 'Login', style: 'primary', eventKey: 'ok'}]
+                body: ->
+                    <Lanes.Access.LoginDialog model={session} attemptLogin={attemptLogin} />
+            )
+
+

     mixins: [
         Lanes.React.Mixins.RelayEditingState