update cc popover accessibility id

update cc popover accessibility id

--- src/components/scores/concept-coach-cell.cjsx
+++ src/components/scores/concept-coach-cell.cjsx
@@ -16,7 +16,7 @@
     pieValue =
       Math.round((@props.task.completed_exercise_count / @props.task.exercise_count) * 100)
     tooltip =
-      <BS.Popover id="cc-cell-info-popover-#{@props.task.id}">
+      <BS.Popover id="cc-cell-info-popover-#{@props.task.id}" className='cc-scores-tooltip-completed-info'>
         <div>
           <BS.Table>
             <thead>


Add JSX option to to JS Beautify

Add JSX option to to JS Beautify

--- src/beautifiers/js-beautify.coffee
+++ src/beautifiers/js-beautify.coffee
@@ -12,6 +12,7 @@
     Mustache: true
     JavaScript: true
     EJS: true
+    JSX: true
     JSON: true
     CSS:
       indent_size: true


switch to find pane after find usage command

--- lib/atom-sharper/atom-sharper.coffee
+++ lib/atom-sharper/atom-sharper.coffee
@@ -13,7 +13,10 @@
     atom.workspaceView.command "atom-sharper:go-to-definition", =>
       @navigateToWord = atom.workspace.getActiveEditor()?.getWordUnderCursor()
       Omni.goToDefinition()
-    atom.workspaceView.command "atom-sharper:find-usages", => Omni.findUsages()
+
+    atom.workspaceView.command "atom-sharper:find-usages", =>
+      Omni.findUsages()
+      @outputView.selectPane "find"

     atom.on "omni:navigate-to", (position) =>
       if position.FileName?


:lipstick:

:lipstick:

--- lib/find-view.coffee
+++ lib/find-view.coffee
@@ -208,8 +208,8 @@
       @resultCounter.text("#{markerIndex + 1} of #{@markers.length}")

   setSelectionAsFindPattern: =>
-    if pattern = @findModel.getEditSession().getSelectedText()
-      @findEditor.setText(pattern)
+    if text = @findModel.getEditSession().getSelectedText()
+      @findEditor.setText(text)

   toggleRegexOption: => @findModel.toggleOption('regex')
   toggleCaseSensitiveOption: => @findModel.toggleOption('caseSensitive')


Typo fix

Typo fix

--- components/Confirm.coffee
+++ components/Confirm.coffee
@@ -3,7 +3,7 @@
 class Confirm extends noflo.Component
   icon: 'fa-check'
   constructor: ->
-    @inPorst =
+    @inPorts =
       in: new noflo.Port 'string'
     @outPorts =
       out: new noflo.Port 'bool'


Revert Resize as async

Revert Resize as async

--- components/Resize-node.coffee
+++ components/Resize-node.coffee
@@ -9,7 +9,7 @@
   c = new noflo.Component

   c.icon = 'expand'
-  c.description = 'Resize a given image'
+  c.description = 'Resize a given image to the new dimension'

   c.inPorts.add 'path',
     datatype: 'string'
@@ -17,10 +17,11 @@
   c.inPorts.add 'width',
     datatype: 'integer'
     description: 'New width'
+    required: false
   c.inPorts.add 'height',
     datatype: 'integer'
     description: 'New height'
-
+    required: false
   c.outPorts.add 'canvas',
     datatype: 'string'
   c.outPorts.add 'error',
@@ -31,24 +32,26 @@
     in: ['path']
     params: ['width', 'height']
     out: ['canvas']
+    async: true
     forwardGroups: true
-  , (payload, groups, out) ->
-    width = if c.params.width? then c.params.width else null
-    height = if c.params.height? then c.params.height else null
-    if width is null and height is null
+  , (payload, groups, out, callback) ->
+    width = c.params.width
+    height = c.params.height
+    if not width? and not height?
       width = 256
     path = payload
     try
       inputBuffer = sharp path
       inputBuffer.metadata (err, metadata) ->
         if err
-          throw err
+          return callback err
         inputBuffer
         .resize width, height
         .withMetadata()
+        .withoutEnlargement()
         .toBuffer (err, outputBuffer, info) ->
           if err
-            throw err
+            return callback err
           # Create image with buffer as src
           image = new Canvas.Image
           image.src = outputBuffer
@@ -59,7 +62,8 @@
           canvas.originalWidth = metadata.width
           canvas.originalHeight = metadata.height
           out.send canvas
+          do callback
     catch err
-      out.error err
+      return callback err

   c


Do DOM reads first to prevent thrashing

Do DOM reads first to prevent thrashing

--- services/web/public/coffee/ide/review-panel/directives/reviewPanelSorted.coffee
+++ services/web/public/coffee/ide/review-panel/directives/reviewPanelSorted.coffee
@@ -33,6 +33,7 @@
 							entry.$layout_el = entry.$box_el
 						else
 							entry.$layout_el = entry.$indicator_el
+						entry.height = entry.$layout_el.height() # Do all of our DOM reads first for perfomance, see http://wilsonpage.co.uk/preventing-layout-thrashing/
 						entries.push entry
 					entries.sort (a,b) -> a.scope.entry.offset - b.scope.entry.offset

@@ -69,7 +70,7 @@
 					previousBottom = focused_entry_top + focused_entry.$layout_el.height()
 					for entry in entries_after
 						original_top = entry.scope.entry.screenPos.y
-						height = entry.$layout_el.height()
+						height = entry.height
 						top = Math.max(original_top, previousBottom + PADDING)
 						previousBottom = top + height
 						entry.$box_el.css(top: top)
@@ -83,7 +84,7 @@
 					entries_before.reverse() # Work through backwards, starting with the one just above
 					for entry, i in entries_before
 						original_top = entry.scope.entry.screenPos.y
-						height = entry.$layout_el.height()
+						height = entry.height
 						original_bottom = original_top + height
 						bottom = Math.min(original_bottom, previousTop - PADDING)
 						top = bottom - height


sgconfigure css 2nd

sgconfigure css 2nd

--- lib/languages.coffee
+++ lib/languages.coffee
@@ -22,7 +22,7 @@

   CSS:
     nameMatchers:      ['.css']
-    pygmentsLexer:     'CSS'
+    pygmentsLexer:     'css'
     multiLineComment:  ['/*', '*', '*/']
     ignorePrefix:      '}'
     foldPrefix:        '^'


Fixes #3547 - Ticket selector for first_response_escalation_at, update_escalation_at, close_escalation_at missing.

--- app/assets/javascripts/app/models/ticket.coffee
+++ app/assets/javascripts/app/models/ticket.coffee
@@ -15,6 +15,9 @@
       { name: 'article_count',            display: 'Article#',     readonly: 1, width: '12%' },
       { name: 'time_unit',                display: 'Accounted Time',          readonly: 1, width: '12%' },
       { name: 'escalation_at',            display: 'Escalation at',           tag: 'datetime', null: true, readonly: 1, width: '110px', class: 'escalation' },
+      { name: 'first_response_escalation_at', display: 'Escalation at (First Response Time)', tag: 'datetime', null: true, readonly: 1, width: '110px', class: 'escalation' },
+      { name: 'update_escalation_at', display: 'Escalation at (Update Time)', tag: 'datetime', null: true, readonly: 1, width: '110px', class: 'escalation' },
+      { name: 'close_escalation_at', display: 'Escalation at (Close Time)', tag: 'datetime', null: true, readonly: 1, width: '110px', class: 'escalation' },
       { name: 'last_contact_at',          display: 'Last contact',            tag: 'datetime', null: true, readonly: 1, width: '110px' },
       { name: 'last_contact_agent_at',    display: 'Last contact (agent)',    tag: 'datetime', null: true, readonly: 1, width: '110px' },
       { name: 'last_contact_customer_at', display: 'Last contact (customer)', tag: 'datetime', null: true, readonly: 1, width: '110px' },


Set default value to '' in XLSX parser. Fix #19

--- src/svgtiler.coffee
+++ src/svgtiler.coffee
@@ -447,6 +447,7 @@
         sheet = workbook.Sheets[subname]
         rows = xlsx.utils.sheet_to_json sheet,
           header: 1
+          defval: ''
         rows.subname = subname
         rows
     )


better testing of existence of I18n

better testing of existence of I18n

--- app/assets/javascripts/darkswarm/i18n.js.coffee
+++ app/assets/javascripts/darkswarm/i18n.js.coffee
@@ -1,12 +1,13 @@
 # Declares the translation function t.
 # You can use t('login') in Javascript.
 window.t = (key, options = {}) ->
-  if I18n == undefined
+  unless 'I18n' of window
     console.log 'The I18n object is undefined. Cannot translate text.'
     return key
+  return key unless key of I18n
   text = I18n[key]
-  return key if text == undefined
-  text = text.split("%{#{name}}").join(value) for name, value of options
+  for name, value of options
+    text = text.split("%{#{name}}").join(value)
   text

 # Provides the translation function t on all scopes.


Don't use fat arrow

Don't use fat arrow

--- lib/rubocop-auto-correct.coffee
+++ lib/rubocop-auto-correct.coffee
@@ -150,7 +150,7 @@
       ''' }
     )

-  rubocopOutput: (data) =>
+  rubocopOutput: (data) ->
     debug = atom.config.get('rubocop-auto-correct.debugMode')
     notification = atom.config.get('rubocop-auto-correct.notification')
     onlyFixesNotification =


Javascript widget fixed

Javascript widget fixed

--- app/assets/javascripts/merge_requests.js.coffee
+++ app/assets/javascripts/merge_requests.js.coffee
@@ -27,7 +27,7 @@
     this.$el.find(selector)

   initMergeWidget: ->
-    this.showState( @opts.current_state )
+    this.showState( @opts.current_status )

     if this.$('.automerge_widget').length and @opts.check_enable
       $.get @opts.url_to_automerge_check, (data) =>


fix orthogonal mode allowance

fix orthogonal mode allowance

--- app/assets/javascripts/oxalis/controller.coffee
+++ app/assets/javascripts/oxalis/controller.coffee
@@ -93,11 +93,11 @@

         if @model.getColorBinaries()[0].cube.BIT_DEPTH == 8
           switch allowedMode
-            when "orthogonal" then @allowedModes.push(constants.MODE_PLANE_TRACING)
             when "flight" then @allowedModes.push(constants.MODE_ARBITRARY)
             when "oblique" then @allowedModes.push(constants.MODE_ARBITRARY_PLANE)

         switch allowedMode
+          when "orthogonal" then @allowedModes.push(constants.MODE_PLANE_TRACING)
           when "volume" then @allowedModes.push(constants.MODE_VOLUME)

       # FPS stats


restore underscored taxon concepts path

restore underscored taxon concepts path

--- app/assets/javascripts/species/router.js.coffee
+++ app/assets/javascripts/species/router.js.coffee
@@ -1,5 +1,6 @@
 Species.Router.map (match) ->
   @resource 'taxonConcepts', {
+    path: "/taxon_concepts"
     queryParams: ['taxonomy', 'taxon_concept_query', 'geo_entities_ids', 'geo_entity_scope', 'page']
     }, () ->
     @resource 'taxonConcept', { path: "/:taxon_concept_id" }, () ->


:bug: Just return the code when no language is specified

--- src/template.coffee
+++ src/template.coffee
@@ -31,7 +31,10 @@
   @markedOptions:
     gfm: true
     highlight: (code, lang) ->
-      Template.render('highlight', content: highlightjs.highlight(lang, code).value)
+      if lang
+        Template.render('highlight', content: highlightjs.highlight(lang, code).value)
+      else
+        code
     smartypants: true

   # Public: Renders the `template` using `locals`.


Note about naming of directives and location_arguments

--- lib/manifesto.coffee
+++ lib/manifesto.coffee
@@ -17,7 +17,7 @@
         required: false
         items:
           type: 'string'
-      location_arguments:
+      location_arguments: #This is poorly named. These are also directives. We should probably have a directives hash with location and server properties as arrays.
         type: 'array'
         required: false
         items:


module + api list output json

module + api list output json

--- lib/marie.app.coffee
+++ lib/marie.app.coffee
@@ -331,7 +331,7 @@
 							file = app.file "#{assets}/#{dir}/.bower.json"
 							config = JSON.parse utils.fs.readFileSync file, utils.encoding.UTF8
 							modules["#{config.name}@#{config.version}"] = "/modules/#{dir}/#{config.main}"
-				cb null, JSON.stringify modules
+				cb null, modules

 	###
 	@param [String] id app id
@@ -352,7 +352,7 @@
 						else
 							api = (ctrl.replace /controller|\.js/gi, '').toLowerCase()
 						apis.push api
-				cb null, JSON.stringify apis
+				cb null, apis

 	###
 	Remove package to app


Inline example select list

Inline example select list

.coffee files aren't bundled with Atom

Closes #17

--- lib/space-pen-extensions.coffee
+++ lib/space-pen-extensions.coffee
@@ -1,5 +1,3 @@
-fs = require 'fs'
-path = require 'path'
 _ = require 'underscore-plus'
 {$, $$, $$$, View} = require 'atom-space-pen-views'
 coffee = require 'coffee-script'
@@ -20,7 +18,24 @@

   exampleOverlaySelectList: ->
     selectList = new ExampleSelectListView(['one', 'two', 'three'])
-    coffeeScript = fs.readFileSync(path.join(__dirname, "example-select-list-view.coffee")).toString()
+    coffeeScript = """
+      {SelectListView, $$} = require 'atom-space-pen-views'
+
+      module.exports =
+      class ExampleSelectListView extends SelectListView
+        initialize: (@listOfItems) ->
+          super
+          @setItems(@listOfItems)
+
+        viewForItem: (item) ->
+          $$ -> @li(item)
+
+        cancel: ->
+          console.log("cancelled")
+
+        confirmed: (item) ->
+          console.log("confirmed", item)
+    """

     @div class: 'example', =>
       @div class: 'example-rendered', =>


Add missing time parameter to transition function generator.

--- src/component/ComponentView.coffee
+++ src/component/ComponentView.coffee
@@ -98,7 +98,7 @@
 # @inner
 ###
 makeTransitionFunc = (func, transitionClass, removeClass, state, test) ->
-  (promise) ->
+  (promise, time) ->
     nextTick =>
       promise = promise or new Promise()

@@ -124,7 +124,7 @@
         # Set the new transition timer.
         @_transitionTimer = setTimeout =>
           @[func] promise
-        , (e.data.time or 0)
+        , (time or 0)

         if func is 'hide' then @repaint()

@@ -169,7 +169,7 @@

     for event, handler of contextEvents
       @context.on event, (e) =>
-        handler.call @, e.data.promise
+        handler.call @, e.data.promise, e.data.time
       , @

     @_transitionTimer = null


Restore focus when clicked button. Fixed #87

--- lib/tool-bar-button-view.coffee
+++ lib/tool-bar-button-view.coffee
@@ -1,5 +1,5 @@
 {CompositeDisposable} = require 'atom'
-{View} = require 'space-pen'
+{$, View} = require 'space-pen'

 module.exports = class ToolBarButtonView extends View
   @content: ->
@@ -29,6 +29,8 @@
         else
           options.callback(options.data, @getPreviouslyFocusedElement())

+        @restoreFocus()
+
     @on 'mouseover', =>
       @storeFocusedElement()

@@ -47,6 +49,13 @@
     else
       @eventElement = atom.views.getView(atom.workspace)

+  restoreFocus: ->
+    previouslyFocusedElement = $(@previouslyFocusedElement)
+    if previouslyFocusedElement?.isOnDom()?
+      previouslyFocusedElement.focus()
+    else
+      atom.workspace.focus()
+
   storeFocusedElement: ->
     if not document.activeElement.classList.contains 'tool-bar-btn'
       @previouslyFocusedElement = document.activeElement


add doc

add doc

--- src/util/log.coffee
+++ src/util/log.coffee
@@ -1,9 +1,19 @@
+# A basic logging module.
+
+# Log info messages for debugging. **TODO**: empty later
+
+info = (message) ->
+  console.log message
+
+# Throw an application specific error.
+
+fail = (message) ->
+  throw
+    name: '2cpyError'
+    message: message
+
+# ### Public API
+
 module.exports =
-
-  info: (message) ->
-    console.log message
-
-  fail: (message) ->
-    throw
-      name: '2cpyError'
-      message: message+  info: info
+  fail: fail


allow general page modification

allow general page modification

--- BackofficeBundle/Resources/public/coffee/page/nodeView.coffee
+++ BackofficeBundle/Resources/public/coffee/page/nodeView.coffee
@@ -85,19 +85,22 @@

     $('.js-widget-title', @$el).html $('#generated-title', @$el).html()
     $('.js-widget-blockpanel', @$el).html($('#generated-panel', @$el).html()).show()
-    @renderWidgetStatus()
     for area of @node.get('areas')
       @addAreaToView(@node.get('areas')[area])
-    @addVersionToView()
+    if @node.get('node_type') == 'page'
+      @renderWidgetStatus()
+      @addVersionToView()
+      @addPreviewLink()
+      if @node.attributes.status.published
+        $('.ui-model *', @el).unbind()
+        $('.js-widget-blockpanel', @$el).hide()
+        $('span.action', @el).hide()
+      else
+        $("ul.ui-model-areas, ul.ui-model-blocks", @$el).each ->
+          refreshUl $(this)
+    else if @node.get('node_type') == 'general'
+      @removeVersionFromView()
     @addLanguagesToView()
-    @addPreviewLink()
-    if @node.attributes.status.published
-      $('.ui-model *', @el).unbind()
-      $('.js-widget-blockpanel', @$el).hide()
-      $('span.action', @el).hide()
-    else
-      $("ul.ui-model-areas, ul.ui-model-blocks", @$el).each ->
-        refreshUl $(this)
     return

   addAreaToView: (area) ->
@@ -122,6 +125,9 @@
         for nodeVersion of nodeCollection.get('nodes')
           viewContext.addChoiceToSelectBox(nodeCollection.get('nodes')[nodeVersion])
         return
+
+  removeVersionFromView: ->
+    $('#additionalContent', @$el).hide()

   addChoiceToSelectBox: (nodeVersion) ->
     nodeVersionElement = new Node


Not needed

Not needed

--- apps/personalize/client/views/categories.coffee
+++ apps/personalize/client/views/categories.coffee
@@ -1,6 +1,5 @@
 _ = require 'underscore'
 StepView = require './step.coffee'
-track = require('../../../../lib/analytics.coffee').track
 Items = require '../../../../collections/items.coffee'
 Gene = require '../../../../models/gene.coffee'
 { setSkipLabel } = require '../mixins/followable.coffee'


A draft implementation of the collector pattern

--- library/gearing/document.coffee
+++ library/gearing/document.coffee
@@ -43,6 +43,21 @@
     throw new Error(missing) unless validated
     method.document = new Document(method)
     descriptor.apply(method, document)
+
+# Traverse all of the services that are registered with the router
+# and collect the documentation for each method, then given this
+# information, build a hierarhical tree object of all the methods
+# and the services that implement them and return to the invoker.
+module.exports.collect = (kernel) ->
+    services = kernel.router.services
+    _.map services, (service) -> do (service) ->
+        supported = constructor.SUPPORTED
+        constructor = service.constructor
+        unsupported = service.unsupported
+        implemented = (m) -> service[m] isnt unsupported
+        doc = (m) -> service[m].document or new Document
+        filtered = _.filter(supported, implemented)
+        _.object(filtered, _.map(filtered, doc))

 # Descriptor of some method of arbitrary service, in a structured
 # and expected way, so that it can later be used to programmatically


Fix error creating cache

Fix error creating cache

--- lib/compile.coffee
+++ lib/compile.coffee
@@ -44,13 +44,19 @@
   try
     options.cacheFile ?= path.join os.tmpdir(), 'rmutt_' + hash source
     if options.cacheRegenerate isnt true and fs.existsSync options.cacheFile
-      console.log 'Loading cache: ', options.cacheFile
-      fs.readFile options.cacheFile, callback
+      # console.log 'Loading cache: ', options.cacheFile
+      fs.readFile options.cacheFile, (err, result) ->
+        return callback err if err?
+        callback null,
+          transpiled: result
+          options: options
     else
       transpile source, options, (err, result) ->
         return callback err if err?
         fs.writeFile options.cacheFile, result.transpiled, (err) ->
           return callback err if err?
-          callback null, result.transpiled
+          callback null,
+            transpiled: result.transpiled
+            options: options
   catch err
     callback err


swagger: compare json parsed version of swagger.json

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- scripts/api-generator.coffee
+++ scripts/api-generator.coffee
@@ -311,7 +311,7 @@
       try
         oldDataInJson = (fs.readFileSync swaggerFilePath).toString()
         oldData = JSON.parse oldDataInJson
-        expect(oldData).to.deep.equal swagger
+        expect(oldData).to.deep.equal JSON.parse swaggerInJson
         console.log 'Swagger.json is up-to-date'
       catch e
         console.error '''


Fix bug with i-commands on saved file

Fix bug with i-commands on saved file

--- lib/ghc-modi-process-redirect.coffee
+++ lib/ghc-modi-process-redirect.coffee
@@ -47,30 +47,35 @@
     process=@spawnProcess(dir,options)
     unless process
       return @run {options,command,text,uri,args,callback}
+    parseData = (data)->
+      lines = "#{data}".split("\n")
+      result = lines[lines.length-2]
+      unless result.match(/^OK/)
+        atom.notifications.addError "Haskell-ghc-mod: ghc-modi crashed
+            on #{command} with message #{result}",
+          detail: dir.getPath()
+          dismissable: true
+        console.error lines
+        callback []
+        return
+      lines = lines.slice(0,-2)
+      callback lines.map (line)->
+        line.replace /\0/g,'\n'
     if text?
       process.stdin.write "load #{uri}\n#{text}\x04\n"
-    process.stdout.once 'data', (data)->
-      if "#{data}" isnt 'OK\n'
-        callback []
-        return
       process.stdout.once 'data', (data)->
-        lines = "#{data}".split("\n")
-        result = lines[lines.length-2]
-        unless result.match(/^OK/)
-          atom.notifications.addError "Haskell-ghc-mod: ghc-modi crashed
-              on #{command} with message #{result}",
-            detail: dir.getPath()
-            dismissable: true
-          console.error lines
+        if "#{data}" isnt 'OK\n'
           callback []
           return
-        lines = lines.slice(0,-2)
-        callback lines.map (line)->
-          line.replace /\0/g,'\n'
+        process.stdout.once 'data', parseData
+    else
+      process.stdout.once 'data', parseData
+
     if uri?
       cmd = [command, uri].concat args
     else
       cmd = [command].concat args
     process.stdin.write cmd.join(' ').replace(/\r|\r?\n/g,' ') + '\n'
+
     if text?
       process.stdin.write "unload #{uri}\n"


removed erroneous call to super from within Firehose.WebSocket#cleanUp()

--- lib/assets/javascripts/firehose/web_socket.js.coffee
+++ lib/assets/javascripts/firehose/web_socket.js.coffee
@@ -61,4 +61,3 @@
       @socket.onmessage = null
       @socket.close()
       delete(@socket)
-    super


format mention with <@user> notation.

format mention with <@user> notation.

--- scripts/github-notify.coffee
+++ scripts/github-notify.coffee
@@ -88,7 +88,7 @@
           if "@#{user.githubLogin}" == nick
             nick = "@#{user.name}"
             break
-        nick
+        "<#{nick}>"

       mentioned_line = "\nMentioned: #{mentioned.join(", ")}"
     else


NOT taken emile. NOT taken

NOT taken emile. NOT taken

--- content/keymanager.coffee
+++ content/keymanager.coffee
@@ -214,7 +214,7 @@
       if citekey.citekey.startsWith(proposed.citekey)                                                         # key begins with proposed sitekey
         re = (proposed.postfix == '0' && @postfixRE.numeric) || @postfixRE.alphabetic
         if citekey.citekey.slice(proposed.citekey.length).match(re)                                           # rest matches proposed postfix
-          if other = @keys.findOne({ libraryID: item.libraryID, citekey: citekey.citekey, itemID: { $ne: item.id } }) # noone else is using it
+          if !(other = @keys.findOne({ libraryID: item.libraryID, citekey: citekey.citekey, itemID: { $ne: item.id } })) # noone else is using it
             return citekey
           else
             debug('KeyManager.propose: no, because', other, 'is using it')


Don't bundle native source files

Don't bundle native source files

--- build/tasks/build-task.coffee
+++ build/tasks/build-task.coffee
@@ -125,6 +125,7 @@
     ignoredPaths.push "#{_.escapeRegExp(path.join('runas', 'src') + path.sep)}.*\\.(cc|h)*"
     ignoredPaths.push "#{_.escapeRegExp(path.join('scrollbar-style', 'src') + path.sep)}.*\\.(cc|h)*"
     ignoredPaths.push "#{_.escapeRegExp(path.join('spellchecker', 'src') + path.sep)}.*\\.(cc|h)*"
+    ignoredPaths.push "#{_.escapeRegExp(path.join('keyboard-layout', 'src') + path.sep)}.*\\.(cc|h|mm)*"

     # Ignore build files
     ignoredPaths.push "#{_.escapeRegExp(path.sep)}binding\\.gyp$"


Add local storage for remember the docs state.

This solves an issue when looking at styles only (instead of full docs).
Now when a user refreshes, they will remain in the same state.

Word.

--- app/assets/javascripts/docomo/application.coffee
+++ app/assets/javascripts/docomo/application.coffee
@@ -3,8 +3,11 @@

 class docomo.Docomo
   constructor: ($, @el = $('body')) ->
+    @has_storage = typeof Storage != undefined
+    @examples_only = if @has_storage and localStorage.examples_only is "true" then true else false
     @initialize()
     @addListeners()
+    @toggleStylingMode() if @examples_only

   initialize: ->
@@ -52,6 +55,8 @@
     not_styles = '.docomo-showcase, .docomo-usage, .docomo-usage-toggle, h1'
     @non_styles ?= @el.find('.docomo-section').children().not not_styles
     @non_styles.toggleClass 'docomo-hidden'
+    @examples_only = @non_styles.hasClass('docomo-hidden')
+    localStorage.examples_only = @examples_only if @has_storage

   toggleShortcuts: ->


chat: more emoticons

chat: more emoticons

--- salvus/page/editor_chat.cjsx
+++ salvus/page/editor_chat.cjsx
@@ -147,7 +147,7 @@
         value = @props.message.get('payload')?.get('content')
         # just for fun.
         value = value.replace(/:-\)/g, "☺").replace(/:-\(/g, "☹").replace(/<3/g, "♡")
-        value = value.replace(/:shrug:/g, "¯\\\\_(ツ)_/¯").replace(/o_o/g, "סּ_סּ").replace(/:-p/g, "😛").replace(/\^\^/g, "😄")
+        value = value.replace(/:shrug:/g, "¯\\\\_(ツ)_/¯").replace(/o_o/g, "סּ_\סּ").replace(/:-p/g, "😛").replace(/\^\^/g, "😄")
         <Col key={1} xs={8}>
             <Panel style={wordWrap:"break-word"}>
                 <ListGroup fill>


Remove cruft to show multiple voters

Remove cruft to show multiple voters

--- core/app/backbone/views/opinionators/opinionators_avatars_view.coffee
+++ core/app/backbone/views/opinionators/opinionators_avatars_view.coffee
@@ -13,28 +13,3 @@
   itemView: OpinionatorsAvatarView

   itemViewContainer: ".js-opinionators-avatars-collection"
-
-  events:
-    'click .js-show-all' : 'show_all'
-
-  number_of_items: 4
-
-  initialize: (options) ->
-    @listenTo @collection, 'add remove reset sync', @render
-
-  _initialEvents: -> # don't use default bindings to collection
-
-  appendHtml: (collectionView, itemView, index) ->
-    super if index < @truncatedListSizes().numberToShow
-
-  templateHelpers: =>
-    numberOfOthers: @truncatedListSizes().numberOfOthers
-
-  truncatedListSizes: ->
-    truncatedListSizes @collection.totalRecords, @number_of_items
-
-  show_all: (e) ->
-    e.stopPropagation()
-    e.preventDefault()
-    @number_of_items = Infinity
-    @render()


fixed tutorial bug

fixed tutorial bug

--- app/assets/javascripts/lib/nypl_inspector.coffee
+++ app/assets/javascripts/lib/nypl_inspector.coffee
@@ -181,7 +181,7 @@
     el.html("<span>" + msg + "</span>")
     .show().delay(2000).fadeOut(1000)

-  invokeTutorial: () ->
+  invokeTutorial: () =>
     if (window.innerWidth < 500)
       @hideOthers()
       $(@options.tutorialID).unswipeshow()
@@ -346,13 +346,13 @@
     )
     @intro.init()

-  parseTutorial: () ->
+  parseTutorial: () =>
     if @currentIndex != @intro.getCurrentPolygonIndex() + 1
       @currentIndex = @intro.getCurrentPolygonIndex()
       @showNextPolygon()
     @

-  hideTutorial: () ->
+  hideTutorial: () =>
     # console.log "end of tutorial"
     @clearScreen()
     if (window.innerWidth < 500)


Sync scroll in markdown editor

Sync scroll in markdown editor

--- app/assets/javascripts/markdown_editor.js.coffee
+++ app/assets/javascripts/markdown_editor.js.coffee
@@ -20,6 +20,9 @@
         $('.legislation-draft-versions-edit .warning').show()
         return

+      $(this).find('textarea').on 'scroll', ->
+        $('#markdown-preview').scrollTop($(this).scrollTop())
+
       $(this).find('.fullscreen-toggle').on 'click', ->
         $('.markdown-editor').toggleClass('fullscreen')


Composition class is in lib

Composition class is in lib

--- src/chaplin.coffee
+++ src/chaplin.coffee
@@ -4,7 +4,7 @@
   Dispatcher:     require 'chaplin/dispatcher'
   Controller:     require 'chaplin/controllers/controller'
   Composer:       require 'chaplin/composer'
-  Composition:    require 'chaplin/composition'
+  Composition:    require 'chaplin/lib/composition'
   Collection:     require 'chaplin/models/collection'
   Model:          require 'chaplin/models/model'
   Layout:         require 'chaplin/views/layout'


JComputeStack: maintenance: set status as Initialized to prevent stalled states

--- workers/social/lib/social/models/stack.coffee
+++ workers/social/lib/social/models/stack.coffee
@@ -402,7 +402,9 @@
         @machines?.forEach (_id) -> queue.push (next) ->
           JMachine.update { _id }, { $set: { users: [] } }, next

-        async.series queue, callback
+        async.series queue, (err) =>
+          return callback err  if err
+          @update { $set: { status: { state: 'Initialized' } } }, callback

       else if options.prepareForMount and machineId = options.machineId


CNS-569: User cannot create a New Group when creating or editing an assignment

--- app/coffeescripts/bundles/assignment_edit.coffee
+++ app/coffeescripts/bundles/assignment_edit.coffee
@@ -29,6 +29,7 @@
   assignmentGroupSelector = new AssignmentGroupSelector
     parentModel: assignment
     assignmentGroups: ENV?.ASSIGNMENT_GROUPS || []
+    basePrefix: 'assignment'
   gradingTypeSelector = new GradingTypeSelector
     parentModel: assignment
   groupCategorySelector = new GroupCategorySelector


fixed preferences not being saved

fixed preferences not being saved

--- client/prefs.coffee
+++ client/prefs.coffee
@@ -46,8 +46,14 @@

 ok = ->
   for t in tabImpls when v = t.validate?()
-    $.alert v.message, 'Error', if v.element then do (v = v) -> v.element.focus()
+    setTimeout(
+      ->
+        $.alert v.message, 'Error', if v.element then -> v.element.focus(); return
+        return
+      1
+    )
     return
+  for t in tabImpls then t.save()
   $d.dialog 'close'; false

 D.prefs = prefs = module.exports = (tabName) ->


Call remove directly on element

Call remove directly on element

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -207,7 +207,7 @@
   updateRoot: (expandedEntries={}) ->
     if @root?
       @root.directory.destroy()
-      @list.element.removeChild(@root)
+      @root.remove()

     if projectPath = atom.project.getPath()
       directory = new Directory({


Add stack trace to console during format errors

--- lib/formats.coffee
+++ lib/formats.coffee
@@ -508,6 +508,7 @@
   try
     formatEither isTitle, format, text, leaveTeX
   catch e
+    console.error e.stack ? e.toString()
     if isTitle
       """
         Formatting error (bug in Coauthor)


add factorial example

add factorial example

--- example.coffee
+++ example.coffee
@@ -1,4 +1,9 @@
 @f_context ->
+
+  #factorial
+  f_fact(0) -> 1
+  f_fact(N) -> N * f_fact(N - 1)
+

   #array elements count
   f_count(List) ->


Update originalEvent API

Update originalEvent API

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -261,7 +261,7 @@
   #
   # Returns nothing.
   registerPrefix: (e) ->
-    name = e.keyEvent.keystrokes.split(' ')[1]
+    name = atom.keymap.keystrokeStringForEvent(e.originalEvent)
     @pushOperator(new prefixes.Register(name))

   # Private: A generic way to create a Number prefix based on the event.
@@ -270,7 +270,7 @@
   #
   # Returns nothing.
   repeatPrefix: (e) ->
-    num = parseInt(e.keyEvent.keystrokes)
+    num = parseInt(atom.keymap.keystrokeStringForEvent(e.originalEvent))
     if @topOperator() instanceof prefixes.Repeat
       @topOperator().addDigit(num)
     else


Tidy up whitespace

Tidy up whitespace

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -252,7 +252,6 @@

     if @submode == 'linewise'
       @editor.selectLine()
-

   # Private: Resets the command mode back to it's initial state.
   #


fix when select-all start visual-mode

fix when select-all start visual-mode

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -249,12 +249,11 @@
     nonEmptySelecitons = @editor.getSelections().filter (selection) -> not selection.isEmpty()
     if nonEmptySelecitons.length
       wise = swrap.detectWise(@editor)
-      if @mode is 'visual'
+      if @isMode('visual', wise)
         @editorElement.component.updateSync()
-
-      if @isMode('visual', wise)
         @updateCursorsVisibility()
       else
+        @editorElement.component.updateSync()
         @activate('visual', wise)
     else
       @activate('normal') if @mode is 'visual'


Extract text formatting into function

Extract text formatting into function

Should be easier for JIT to optimize

--- src/compile.coffee
+++ src/compile.coffee
@@ -5,6 +5,10 @@
     ast.value
   else
     model
+
+formatTextValue = (value) ->
+  value = "0" if value is 0
+  value or ""

 Property =
   style: (ast, node, model, controller) ->
@@ -144,13 +148,11 @@
     dynamic

   text: (ast, model, controller) ->
-    getText = ->
-      value = getValue(ast, model)
-      value = "0" if value is 0
-      value or ""
-    textNode = Serenade.document.createTextNode(getText())
+    textNode = Serenade.document.createTextNode(formatTextValue(getValue(ast, model)))
     node = new Node(ast, textNode)
-    node.bindEvent(model["#{ast.value}_property"], -> assignUnlessEqual(textNode, "nodeValue", getText())) if ast.bound
+    if ast.bound
+      node.bindEvent model["#{ast.value}_property"], (_, value) ->
+        assignUnlessEqual textNode, "nodeValue", formatTextValue(getValue(ast, model))
     node

   collection: (ast, model, controller) ->


got rid validation on accountId, since we do not use that anymore

--- addon/singletons/user-session.coffee
+++ addon/singletons/user-session.coffee
@@ -27,7 +27,6 @@
   checkForErrors: ->
     @errors.clear()
     @setError "token", "cannot be blank" if isBlank(@get "rememberToken")
-    @setError "account", "cannot be blank" if isBlank(@get "accountId")
     @get "hasErrors"
   configure: ({token, account}) ->
     @set "accountId", (account ? Cookies.get("accountId"))
@@ -35,7 +34,7 @@
   setup: (store) ->
     return @get("p") if @checkForErrors()

-    store.find "account", @get("accountId")
+    store.find "account", "singleton"
     .then (account) =>
       @set "account", account
       Cookies.set("accountId", account.get("id"))


OHM-224: Fixed small bug - typo

OHM-224: Fixed small bug - typo

--- src/contact.coffee
+++ src/contact.coffee
@@ -17,7 +17,7 @@
     text: messagePlain
     html: messageHTML
   }, (error, response) ->
-    callback err ? null
+    callback error ? null

 sendSMS = (contactAddress, message, callback) ->
   if config.smsGateway.provider is 'clickatell'


fix binding cli in render contexts

fix binding cli in render contexts

--- src/context.coffee
+++ src/context.coffee
@@ -92,7 +92,7 @@
         nested_context = _.extend {}, run_context,
           output: output $item

-        nested_context.cli = bind_cli nested_context
+        nested_context.cli = bind_cli nested_context, cli
         handle_renderable.call nested_context, o
         # TODO warn if not renderable


:art: Use Buffered{Node, }Process instead of vanilla child_process

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -1,4 +1,4 @@
-child_process = require 'child_process'
+{BufferedProcess, BufferedNodeProcess} = require('atom')
 path = require 'path'
 fs = require 'fs'
 path = require 'path'
@@ -14,26 +14,15 @@

   execNode: (filePath, args = [], options = {}) ->
     throw new Error "Nothing to execute." unless arguments.length
-    args.unshift(filePath)
-    return @_exec(process.execPath, args, options, true)
+    return @_exec(filePath, args, options, true)

   _exec: (command, args = [], options = {}, isNodeExecutable = false) ->
     options.stream ?= 'stdout'
-    options.env ?= process.env
     return new Promise (resolve, reject) ->
-      if isNodeExecutable
-        options.env ?= {}
-        options.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE = '1' # Needed for electron
-      spawnedProcess = child_process.spawn(command, args, options)
       data = stdout: [], stderr: []
-      spawnedProcess.stdout.on 'data', (d) -> data.stdout.push(d.toString())
-      spawnedProcess.stderr.on 'data', (d) -> data.stderr.push(d.toString())
-      if options.stdin
-        spawnedProcess.stdin.write(options.stdin.toString())
-        spawnedProcess.stdin.end() # We have to end it or the programs will keep waiting forever
-      spawnedProcess.on 'error', (err) ->
-        reject(err)
-      spawnedProcess.on 'close', ->
+      stdout = (output) -> data.stdout.push(output.toString())
+      stderr = (output) -> data.stderr.push(output.toString())
+      exit = ->
         if options.stream is 'stdout'
           if data.stderr.length
             reject(data.stderr.join(''))
@@ -41,6 +30,14 @@
             resolve(data.stdout.join(''))
         else
           resolve(data.stderr.join(''))
+      if isNodeExecutable
+        spawnedProcess = new BufferedNodeProcess({command, args, stdout, stderr, exit})
+      else
+        spawnedProcess = new BufferedProcess({command, args, stdout, stderr, exit})
+      spawnedProcess.onWillThrowError(reject)
+      if options.stdin
+        spawnedProcess.process.stdin.write(options.stdin.toString())
+        spawnedProcess.process.stdin.end() # We have to end it or the programs will keep waiting forever

   # Due to what we are attempting to do, the only viable solution right now is
   #   XRegExp.


Add organization filter.

Add organization filter.

--- src/control.coffee
+++ src/control.coffee
@@ -343,6 +343,7 @@
             console.assert(cancelToken?.constructor?.name == 'CancelToken', 'wrong canceltoken parameter')
             municipalityIds = queryParameters?.municipality?.split ','
             providerTypes = queryParameters?.provider_type?.split ','
+            organizationUuid = queryParameters?.organization

             serviceIds = serviceIdString.split ','
             services = _.map serviceIds, (id) -> new models.Service id: id
@@ -367,7 +368,7 @@
                     # commands don't return promises so
                     # we need to call @addService directly
                     Analytics.trackCommand 'addService', [srv]
-                    @addService(srv, {municipality: municipalityIds, provider_type: providerTypes}, cancelToken).done ->
+                    @addService(srv, {organization: organizationUuid, municipality: municipalityIds, provider_type: providerTypes}, cancelToken).done ->
                         deferreds[idx].resolve true
             return $.when deferreds...


Update UUID helper

Update UUID helper

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -2,6 +2,9 @@
 fs   = require 'fs'
 uuid = require 'node-uuid'
 {exec} = require 'child_process'
+
+log = new (require 'log')()
+exports.log = log

 # We need to get the server's internal network IP to send out in SSDP messages.
 # Only works on Linux and (probably) Mac.
@@ -22,36 +25,16 @@
         console.info "`ifconfig` returned '#{matches}', after filtering out localhost IPs, '#{match}' will be used."
         callback err, match

+# Try to persist UUID, to let Control Points keep track of devices across restarts.
+exports.getUuid = (callback) ->

-# Try to persist UUID, otherwise Control Points won't know it's the same
-# device on restarts. We attempt to store UUIDs as JSON in a file called
-# **upnp-uuid** in upnp-device's root folder, but err gracefully by
-# returning a new uuid if the file cannot be read/written.
-exports.getUuid = (callback) ->
+    # Attempt to store/fetch UUID's in a JSON file in upnp-device's root folder.
     uuidFile = "#{__dirname}/../upnp-uuid"
-    fs.readFile uuidFile, 'utf8', (err, data) =>
-        data = JSON.parse(data or "{}")
-        if data[@type]?[@name]
-            console.info 'Found UUID for a device with same type and name.'
-            callback null, data[@type][@name]
-        else
-            console.info 'No existing UUID for this device was found.'
-            console.warn err.msg if err
-            console.info 'Generating and returning a new UUID.'
-            uuid = uuid()
-            data ?= {}
-            data[@type] ?= {}
-            data[@type][@name] = uuid
-            # We don't care if the save has finished/succeeded before callback.
+    fs.readFile uuidFile, 'utf8', (err, file) ->
+        log.notice err.message if err
+        data = JSON.parse(file or "{}")
+        unless data[@type]?[@name]
+            (data[@type]?={})[@name] = uuid()
             fs.writeFile uuidFile, JSON.stringify(data)
-            callback null, uuid
-
-# Turn each key/value pair into separate objects. Mostly used for XML element
-# creation. Optionally takes an array to push elements to.
-exports.objToArr = (obj, arr) ->
-    arr ?= []
-    Object.keys(obj).map (key) ->
-        o = {}
-        o[key] = obj[key]
-        arr.push o
-    arr
+        # Call back with UUID even if (and before) read/write fails.
+        callback null, data[@type][@name]


fix log level

fix log level

--- coffee/state.coffee
+++ coffee/state.coffee
@@ -3,7 +3,7 @@
   state =
     debug:             false
     log:               true
-    logLevel:          LogProvider.Level.ALL
+    logLevel:          LogProvider.Level.INFO
     title:             ""
     isAutoTracking:    false
     isPomodoring:      false


Remove unused method stubs

Remove unused method stubs

--- coffee/tools.coffee
+++ coffee/tools.coffee
@@ -7,8 +7,6 @@
   continue: (x, y, lc) ->
   end: (x, y, lc) ->
   drawCurrent: (ctx) ->
-  createToolbar: (el) ->
-  removeToolbar: (el) ->

 class LC.Pencil extends LC.Tool


fix #25

fix #25

--- src/extension/js/background.coffee
+++ src/extension/js/background.coffee
@@ -195,8 +195,9 @@
   group = JU.lsGet(type[0] + 'cGroup', [])
   for g in group
     if g[0] == id
-      urls = urls.concat(getCustomUrl(custom, g[1]))
-      urls = urls.concat(getAllUrl(all, g[1]))
+      for gid in g[1]
+        urls = urls.concat(getCustomUrl(custom, gid))
+        urls = urls.concat(getAllUrl(all, gid))
   for u in urls
     console.debug 'open %s', u
     _gaq.push(['_trackEvent', 'menu', id])


Don't leak file subscription

Don't leak file subscription

--- spec/archive-editor-spec.coffee
+++ spec/archive-editor-spec.coffee
@@ -5,8 +5,13 @@
   describe ".deserialize", ->
     it "returns undefined if no file exists at the given path", ->
       spyOn(console, 'warn') # Don't log during specs
-      editor = new ArchiveEditor(path: path.join(__dirname, 'fixtures', 'nested.tar'))
-      state = editor.serialize()
-      expect(ArchiveEditor.deserialize(state)).toBeDefined()
+      editor1 = new ArchiveEditor(path: path.join(__dirname, 'fixtures', 'nested.tar'))
+      state = editor1.serialize()
+      editor1.destroy()
+
+      editor2 = ArchiveEditor.deserialize(state)
+      expect(editor2).toBeDefined()
+      editor2.destroy()
+
       state.path = 'bogus'
       expect(ArchiveEditor.deserialize(state)).toBeUndefined()


check against current branch

check against current branch

--- spec/built-in-tiles-spec.coffee
+++ spec/built-in-tiles-spec.coffee
@@ -181,12 +181,13 @@
           atom.workspace.open('HEAD')

         runs ->
+          currentBranch = atom.project.getRepositories()[0].getShortHead()
           expect(gitView.branchArea).toBeVisible()
-          expect(gitView.branchLabel.textContent).toBe 'master'
+          expect(gitView.branchLabel.textContent).toBe currentBranch

           atom.workspace.getActivePane().destroyItems()
           expect(gitView.branchArea).toBeVisible()
-          expect(gitView.branchLabel.textContent).toBe 'master'
+          expect(gitView.branchLabel.textContent).toBe currentBranch

         atom.workspace.getActivePane().activateItem(dummyView)
         expect(gitView.branchArea).not.toBeVisible()


:new: Add a spec about lowercasing config values

--- spec/custom-element-spec.coffee
+++ spec/custom-element-spec.coffee
@@ -22,6 +22,14 @@
     element.remove()
     expect(lastRan).toBe('detached')

+  it 'lowercases config values', ->
+    element = new (registerCustomElement(getCustomElement({
+      name: 'x-spec-lowercase-config-values',
+      config: {Wow: {type: Boolean, default: false}}
+    })))
+    expect(element.Wow).toBeUndefined()
+    expect(element.wow).toBe(false)
+
   it 'does not fire attributeChanged on config change', ->
     executed = false
     element = new (registerCustomElement(getCustomElement({


:lipstick: Convert specs to new command dispatch

--- spec/tabs-to-spaces-spec.coffee
+++ spec/tabs-to-spaces-spec.coffee
@@ -32,47 +32,47 @@
       editor.setTabLength(3)

     it 'does not change an empty file', ->
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe ''

     it 'does not change spaces at the end of a line', ->
       buffer.setText('foobarbaz     ')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe 'foobarbaz     '

     it 'does not change spaces in the middle of a line', ->
       buffer.setText('foo  bar  baz')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe 'foo  bar  baz'

     it 'converts one tab worth of spaces to a tab', ->
       editor.setTabLength(2)
       buffer.setText('  foo')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe '\tfoo'

     it 'converts almost two tabs worth of spaces to one tab and some spaces', ->
       editor.setTabLength(4)
       buffer.setText('       foo')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe '\t   foo'

     it 'changes multiple lines of leading spaces to tabs', ->
       editor.setTabLength(4)
       buffer.setText('    foo\n       bar')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe '\tfoo\n\t   bar'

     it 'leaves successive newlines alone', ->
       editor.setTabLength(2)
       buffer.setText('  foo\n\n  bar\n\n  baz\n\n')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe '\tfoo\n\n\tbar\n\n\tbaz\n\n'

     it 'changes mixed spaces and tabs to uniform whitespace', ->
       editor.setTabLength(2)
       buffer.setText('\t \tfoo\n')
-      atom.workspaceView.trigger 'tabs-to-spaces:tabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:tabify')
       expect(editor.getText()).toBe '\t\t foo\n'

   describe 'untabify', ->
@@ -80,41 +80,41 @@
       editor.setTabLength(3)

     it 'does not change an empty file', ->
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe ''

     it 'does not change tabs at the end of a string', ->
       buffer.setText('foobarbaz\t')
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe 'foobarbaz\t'

     it 'does not change tabs in the middle of a string', ->
       buffer.setText('foo\tbar\tbaz')
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe 'foo\tbar\tbaz'

     it 'changes one tab to the correct number of spaces', ->
       editor.setTabLength(2)
       buffer.setText('\tfoo')
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe '  foo'

     it 'changes two tabs to the correct number of spaces', ->
       editor.setTabLength(2)
       buffer.setText('\t\tfoo')
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe '    foo'

     it 'changes multiple lines of leading tabs to spaces', ->
       editor.setTabLength(2)
       buffer.setText('\t\tfoo\n\t\tbar\n\n')
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe '    foo\n    bar\n\n'

     it 'changes mixed spaces and tabs to uniform whitespace', ->
       editor.setTabLength(2)
       buffer.setText(' \t foo\n')
-      atom.workspaceView.trigger 'tabs-to-spaces:untabify'
+      atom.commands.dispatch(atom.workspaceView.element, 'tabs-to-spaces:untabify')
       expect(editor.getText()).toBe '    foo\n'

   describe 'on save', ->


Remove unused variable

Remove unused variable

--- src/packages/wrap-guide/src/wrap-guide.coffee
+++ src/packages/wrap-guide/src/wrap-guide.coffee
@@ -15,7 +15,6 @@
   @content: ->
     @div class: 'wrap-guide'

-  getGuideColumn: null
   defaultColumn: 80

   initialize: (@rootView, @editor) =>


better method of disabling blinking

better method of disabling blinking

--- lib/cursor-blink-interval.coffee
+++ lib/cursor-blink-interval.coffee
@@ -1,32 +1,29 @@
 'use strict'
-_ = require 'underscore'
-
 class CursorBlinkInterval
   config:
-    interval:
-      description: 'Interval of the cursor blink - the period between primaryColor and secondaryColor - in milliseconds. Set to 0 to disable blinking (Note: doesn\'t apply to mini editors yet)'
+    cursorBlinkInterval:
+      description: 'Cursor blink interval in milliseconds. Set to 0 to disable blinking (Note: doesn\'t apply to mini editors)'
       type: 'integer'
-      default: 400
+      default: 800
       minimum: 0

   activate: ->
-    @configSub = atom.config.observe 'cursor-blink-interval.interval', @applyInterval
+    @configSub = atom.config.observe 'cursor-blink-interval.cursorBlinkInterval', @applyCursorBlinkInterval
     @editorSub = null

   deactivate: ->
     @configSub.dispose()
     @editorSub?.dispose?()

-  applyInterval: (interval) =>
+  applyCursorBlinkInterval: (cursorBlinkInterval) =>
     @editorSub?.dispose?()
     @editorSub = atom.workspace.observeTextEditors (editor) ->
       editorPresenter = atom.views.getView(editor).component.presenter
-      editorPresenter.cursorBlinkPeriod = interval * 2
       editorPresenter.stopBlinkingCursors(true)
-      if interval > 0
-        editorPresenter.startBlinkingCursorsAfterDelay = do ->
-          _.debounce(editorPresenter.startBlinkingCursors, editorPresenter.getCursorBlinkResumeDelay())
+      if cursorBlinkInterval > 0
+        editorPresenter.cursorBlinkPeriod = cursorBlinkInterval
       else
-        editorPresenter.startBlinkingCursorsAfterDelay = ->
+        editorPresenter.cursorBlinkPeriod = -1 + Math.pow 2, 32
+      editorPresenter.startBlinkingCursors()

 module.exports = new CursorBlinkInterval()


:art: improve emoji

:art: improve emoji

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -633,7 +633,7 @@
   operatesInclusively: false
   operatesLinewise: true
   complete: false
-  hoverText: "'"
+  hoverText: ":round_pushpin:'"
   requireInput: true

   constructor: ->
@@ -658,7 +658,7 @@
 class MoveToMarkLiteral extends MoveToMark
   @extend()
   operatesLinewise: false
-  hoverText: '`'
+  hoverText: ":round_pushpin:`"

 # Search
 # -------------------------


Test cache support of OrderedSet#fetchItems

--- src/desktop/test/models/ordered_set.coffee
+++ src/desktop/test/models/ordered_set.coffee
@@ -6,13 +6,15 @@
 OrderedSet = rewire '../../models/ordered_set.coffee'

 class Items extends Backbone.Model
-  fetch: -> { then: -> sinon.stub() }

 OrderedSet.__set__ 'Items', Items

 describe 'OrderedSet', ->
   beforeEach ->
     sinon.stub Backbone, 'sync'
+    fetch = -> { then: -> sinon.stub() }
+    @spiedFetch = sinon.spy(fetch)
+    Items.prototype.fetch = @spiedFetch
     @orderedSet = new OrderedSet

   afterEach ->
@@ -25,3 +27,8 @@

     it 'returns a promise', ->
       @orderedSet.fetchItems()
+
+    it 'supports caching', ->
+      @orderedSet.fetchItems(true, 60)
+      @spiedFetch.calledOnce.should.be.ok()
+      @spiedFetch.lastCall.args.should.eql [{cache: true, cacheTime: 60}]


use container instead of window

use container instead of window

--- app/assets/javascripts/jquery.infinite-pages.js.coffee
+++ app/assets/javascripts/jquery.infinite-pages.js.coffee
@@ -33,7 +33,6 @@
       @options = $.extend({}, @defaults, options)
       @$container = $(container)
       @$table = $(container).find('table')
-
       @init()

     # Setup and bind to related events
@@ -43,7 +42,7 @@
       scrollTimeout = null
       scrollHandler = (=> @check())

-      $(window).scroll ->
+      @$container.scroll ->
         if scrollTimeout
           clearTimeout(scrollTimeout)
           scrollTimeout = null
@@ -60,7 +59,7 @@
       if nav.size() == 0
         @_log "No more pages to load"
       else
-        windowBottom = $(window).scrollTop() + $(window).height()
+        windowBottom = @$container.scrollTop() + @$container.height()
         distance = nav.offset().top - windowBottom

         if @options.state.paused


Updated where filter looks for data attributes, due to card refactoring

--- app/assets/javascripts/lib/components/filter.js.coffee
+++ app/assets/javascripts/lib/components/filter.js.coffee
@@ -42,11 +42,11 @@
       $(LISTENER).on 'click', '.js-stack-card-filter', (e) =>
         e.preventDefault()
         $this = $(e.currentTarget)
-        filters = $this.find('[data-filter]').data('filter')
+        filters = $this.data('filter')
         @_set(filters, true)
         @config =
           callback: "trackFilter",
-          stack: $this.find('[data-filter]').data("stack-kind") or ""
+          stack: $this.data("stack-kind") or ""
         @trigger(':cards/request', [@_serialize(), @config])

     # Private area


missed a log

missed a log

--- lib/orpheus.coffee
+++ lib/orpheus.coffee
@@ -145,7 +145,6 @@
 									return if k is 'tokenizer'
 									@validations[key].push (field) ->
 										len = tokenizer field
-										log k, field, len, v
 										unless validations.size[k].fn(len, v)
 											return validations.size[k].msg(field, len, v)
 										return true


fix  https://github.com/sagemathinc/cocalc/issues/2692  -- output metadata in ipynb generation dropped

--- src/smc-webapp/jupyter/export-to-ipynb.coffee
+++ src/smc-webapp/jupyter/export-to-ipynb.coffee
@@ -31,7 +31,7 @@

     return ipynb

-# Return ipynb version of the given cell as Python object
+# Return ipynb version of the given cell as object
 cell_to_ipynb = (id, opts) ->
     cell = opts.cells.get(id)
     metadata = {}
@@ -163,7 +163,7 @@
                 else
                     return  # impossible to include in the output without blob_store
         output_n.output_type = "execute_result"
-        output_n.metadata = {}
+        output_n.metadata ?= {}
         output_n.execution_count = exec_count
     else if output_n.name?
         output_n.output_type = 'stream'


Order alphabetically

Order alphabetically

--- src/fs-plus.coffee
+++ src/fs-plus.coffee
@@ -399,10 +399,10 @@
       '.DS_Store'
       '.a'
       '.o'
+      '.pyc'
+      '.pyo'
       '.so'
       '.woff'
-      '.pyc'
-      '.pyo'
     ], ext, true) >= 0

   # Public: Returns true for files named similarily to 'README'


Remove remaining console.log

Remove remaining console.log

--- lib/process.coffee
+++ lib/process.coffee
@@ -27,7 +27,6 @@
             [code, pid] = stdout.split(' ')
             return callback new Error "Process exit with code #{code}" if code isnt '0'
             pidfile = settings.pidfile or pidfile cmd
-            console.log 'pidfile', pidfile
             fs.writeFileSync pidfile, '' + pid
             callback null, pid
     else # Kill child on exit if started in attached mode


Let's preserve all the logic...

Let's preserve all the logic...

--- lib/project.coffee
+++ lib/project.coffee
@@ -68,6 +68,9 @@
     pool.exec (error) =>
       return callback error if error

-      @log.info ''
-      @log.pass 'Documentation generated'
-      callback()
+      style.renderCompleted (error) =>
+        return callback error if error
+
+        @log.info ''
+        @log.pass 'Documentation generated'
+        callback()


Slightly optimize startsWith.

Slightly optimize startsWith.

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -8,7 +8,7 @@
 logger = require './logger'

 exports.startsWith = startsWith = (string, substring) ->
-  string.indexOf(substring) is 0
+  string.lastIndexOf(substring, 0) is 0

 exports.flatten = flatten = (array) ->
   array.reduce (acc, elem) ->


Use default server from `brunch-server` file.

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -1,5 +1,6 @@
 'use strict'

+fs_utils = require './fs_utils'
 {exec} = require 'child_process'
 os = require 'os'
 sysPath = require 'path'
@@ -338,10 +339,22 @@
     config.paths.packageConfig
     config.paths.bowerConfig
   ].concat Object.keys normalized.paths.possibleConfigFiles
+  normalized.packageInfo = {}
   config._normalized = normalized
   ['on', 'off', 'only'].forEach (key) ->
     if typeof config.plugins[key] is 'string'
       config.plugins[key] = [config.plugins[key]]
+  config
+
+addDefaultServer = (config) ->
+  return config if config.server.path
+  defaultServerPath = 'brunch-server'
+  try
+    resolved = require.resolve sysPath.resolve defaultServerPath
+    require resolved
+    config.server.path ?= resolved
+  catch e
+    # Do nothing.
   config

 loadComponents = (config, type, callback) ->
@@ -387,6 +400,18 @@
       files: [file]
       version: json.dependencies[dep]
   cb components: items
+
+addPackageManagers = (config, callback) ->
+  loadNpm config, (npmRes) ->
+    config._normalized.packageInfo.npm = npmRes
+
+    loadComponents config, 'bower', (bowerRes)->
+      config._normalized.packageInfo.bower = bowerRes
+
+      loadComponents config, 'component', (componentRes) ->
+        config._normalized.packageInfo.component = componentRes
+
+        callback()

 exports.loadConfig = (configPath = 'brunch-config', options = {}, callback) ->
   try
@@ -407,20 +432,13 @@
       throw new Error "couldn\'t load config #{fullPath}. #{error}"

   setConfigDefaults config, configPath
+  addDefaultServer config
   warnAboutConfigDeprecations config
   applyOverrides config, options
   deepExtend config, options
   replaceConfigSlashes config
   normalizeConfig config
-  config._normalized.packageInfo = {}
-
-  loadNpm config, (npmRes) ->
-    config._normalized.packageInfo.npm = npmRes
-
-    loadComponents config, 'bower', (bowerRes)->
-      config._normalized.packageInfo.bower = bowerRes
-
-      loadComponents config, 'component', (componentRes) ->
-        config._normalized.packageInfo.component = componentRes
-        deepFreeze config
-        callback null, config
+
+  addPackageManagers config, ->
+    deepFreeze config
+    callback null, config


:lipstick: Remove unneeded parens

:lipstick: Remove unneeded parens

--- src/helpers.coffee
+++ src/helpers.coffee
@@ -247,12 +247,12 @@
     else String.fromCharCode(charCode)

 isASCII = (charCode) ->
-  (charCode in [13, 32]) or # spacebar & return keys
-  (47  < charCode < 58)  or # number keys
-  (64  < charCode < 91)  or # Uppercase letter keys
-  (96  < charCode < 123) or # Lowercase letter keys
-  (185 < charCode < 193) or # ;=,-./`
-  (218 < charCode < 223)    # [\]'
+  charCode in [13, 32] or # spacebar & return keys
+  47  < charCode < 58  or # number keys
+  64  < charCode < 91  or # Uppercase letter keys
+  96  < charCode < 123 or # Lowercase letter keys
+  185 < charCode < 193 or # ;=,-./`
+  218 < charCode < 223    # [\]'

 numpadToASCII = (charCode, shifted) ->
   trans = NumPadToASCII[charCode]


Add back History::getCheckpointIndex

Add back History::getCheckpointIndex

For now, we need this private API because vim-mode uses it for
repeating insertion operations. Someday we should add a real
public API for this.

--- src/history.coffee
+++ src/history.coffee
@@ -231,6 +231,12 @@
   ###
   Section: Private
   ###
+
+  getCheckpointIndex: (checkpointId) ->
+    for entry, i in @undoStack by -1
+      if entry instanceof Checkpoint and entry.id is checkpointId
+        return i
+    return null

   serializeStack: (stack) ->
     for entry in stack


clear src

clear src

--- static/index.coffee
+++ static/index.coffee
@@ -156,6 +156,7 @@
       lock()

     fail = () ->
+      setContent ''
       edit newTaste

     lock()


fix bugs

fix bugs

--- lib/steedos.coffee
+++ lib/steedos.coffee
@@ -15,7 +15,7 @@
             for sub in subs
                 result.registeredTopics.push(sub.event.name.split("|")[0])

-            result.webCourierURL = "https://" + req.headers.host + "/webcourier"
+            result.webCourierURL = "https://" + req.host + "/webcourier"
             res.json result

@@ -184,24 +184,6 @@
             res.json error: error.message, 400

-    # Get token info
-    app.get '/getToken/:subscriber_id', authorize('listen'), (req, res) ->
-        req.subscriber.getSubscriptions (subs) ->
-            if subs?
-                result = {}
-                result.pushToken = req.subscriber.id
-                result.pushTokenTTL = 6000
-                result.registeredTopics = []
-
-                for sub in subs
-                    result.registeredTopics.push(sub.event.name)
-
-                result.webCourierURL = "https://" + req.headers.host + "/webcourier"
-                res.json result, if result? then 200 else 404
-            else
-                logger.error "No subscriber #{req.subscriber.id}"
-                res.send 404
-

     app.post '/message', authorize('publish'), (req, res) ->


:lipstick: combine statements

:lipstick: combine statements

--- src/install.coffee
+++ src/install.coffee
@@ -217,11 +217,11 @@
     packageVersion = metadata.version

     installGlobally = options.installGlobally ? true
-    if not installGlobally and @isPackageInstalled(packageName, packageVersion)
-      callback()
-      return
-
     unless installGlobally
+      if packageVersion and @isPackageInstalled(packageName, packageVersion)
+        callback()
+        return
+
       label = packageName
       label += "@#{packageVersion}" if packageVersion
       process.stdout.write "Installing #{label} "


[refactor] Inherited Scheduler.Tickets from window.Ticket (10m)

--- app/assets/javascripts/houston-scheduler/models/ticket.coffee
+++ app/assets/javascripts/houston-scheduler/models/ticket.coffee
@@ -1,22 +1,13 @@
-class Scheduler.Ticket extends Backbone.Model
+class Scheduler.Ticket extends @Ticket
   urlRoot: '/scheduler/tickets'

-  tasks: -> @_tasks ?= new Scheduler.Tasks(@get('tasks'))
-  estimatedEffort: ->
-    effort = @tasks().reduce ((sum, task)-> sum + +task.get('effort')), 0
-    if effort == 0 then null else effort
   estimated: -> @tasks().every (task)-> +task.get('effort') > 0
   waitingForDiscussion: -> @get('unableToSetEstimatedEffort') or @get('unableToSetPriority')

-  severity: ->
-    seriousness = @get('seriousness')
-    likelihood = @get('likelihood')
-    clumsiness = @get('clumsiness')
-    return false unless seriousness && likelihood && clumsiness
-    (0.6 * seriousness + 0.3 * likelihood + 0.1 * clumsiness).toFixed(1)
-
   value: ->
     0
+
+  tasks: -> @_tasks ?= new Scheduler.Tasks(@get('tasks'))

   addTask: (attributes)->
     xhr = $.post "/scheduler/tickets/#{@id}/tasks", attributes
@@ -44,6 +35,7 @@
     String.fromCharCode(bytes)

   parse: (ticket)->
+    ticket = super(ticket)
     if ticket.extendedAttributes
       ticket.sequence = +ticket.extendedAttributes['sequence']
       ticket.sequence = null if !ticket.sequence
@@ -62,7 +54,7 @@

-class Scheduler.Tickets extends Backbone.Collection
+class Scheduler.Tickets extends @Tickets
   model: Scheduler.Ticket

   numbered: (numbers)->
@@ -94,22 +86,10 @@
   waitingForDiscussion: -> @scoped (ticket)-> ticket.waitingForDiscussion()
   postponed: -> @scoped (ticket)-> !!ticket.get('postponed')
   unpostponed: -> @scoped (ticket)-> !ticket.get('postponed')
-
-  orderBy: (attribute, ascOrDesc)->
-    tickets = @sortBy(@sorterFor(attribute))
-    tickets = tickets.reverse() if ascOrDesc == 'desc'
-    new Scheduler.Tickets(tickets)

   sorterFor: (attribute)->
     switch attribute
       when 'sequence'     then (ticket)-> +ticket.get('sequence')
-      when 'effort'       then (ticket)-> ticket.estimatedEffort()
-      when 'severity'     then (ticket)-> ticket.severity()
-      when 'seriousness'  then (ticket)-> +ticket.get('seriousness')
-      when 'likelihood'   then (ticket)-> +ticket.get('likelihood')
-      when 'clumsiness'   then (ticket)-> +ticket.get('clumsiness')
-      when 'summary'      then (ticket)-> ticket.get('summary').toLowerCase().replace(/^\W/, '')
-      when 'openedAt'     then (ticket)-> ticket.get('openedAt')
-      else throw "sorterFor doesn't know how to sort #{attribute}!"
+      else                super(attribute)

   scoped: (filter)-> new Scheduler.Tickets(@select(filter))


JasmineStore updated

JasmineStore updated

--- src/jasmine.coffee
+++ src/jasmine.coffee
@@ -1 +1,13 @@
-define 'jasmine', -> {}+define 'jasmine', ->
+  Jasmine = undefined
+
+  ->
+    @set = (value)->
+      Jasmine = value
+
+    @instance = Jasmine
+
+    @defined = ->
+      Jasmine?
+
+    this


Changed easing function for highlight animation when clicking of "read all" navbar button.

Now it stays longer in the "highlighted" state, without changing total animation duration.

--- app/assets/javascripts/ng-services/ng-AnimationsSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-AnimationsSvc.js.coffee
@@ -271,8 +271,8 @@
     #---------------------------------------------
     highlight_read_all_button: ->
       $('#read-all-button')
-        .velocity({backgroundColor: '#e7e7e7'}, {duration: 300, easing: 'swing'})
-        .velocity({backgroundColorAlpha: 0}, {duration: 300, easing: 'swing'})
+        .velocity({backgroundColor: '#e7e7e7'}, {duration: 300, easing: 'ease-out'})
+        .velocity({backgroundColorAlpha: 0}, {duration: 300, easing: 'ease-in'})

   return service
 ]


Fix category route to sync with new paging model

--- app/assets/javascripts/routes/categories-show-route.js.coffee
+++ app/assets/javascripts/routes/categories-show-route.js.coffee
@@ -3,12 +3,16 @@
     App.Category.find(params.id)
   setupController: (controller, model) ->
     @_super controller, model
-    @controllerFor('pagedTransactions').setProperties
-      page: 1
+    transactionsController = @controllerFor('transactions')
+
+    model.reload().then ->
+      transactionsController.setProperties
+        model: model.get('transactions')
+        page: 1

   renderTemplate: ->
     @_super()
     @render 'transactions',
       into: 'categories.show'
       outlet: 'transactions'
-      controller: @controllerFor('pagedTransactions')
+      controller: @controllerFor('transactions')


Added event tracking for when coupon is added

--- app/assets/javascripts/sprangular/directives/promoForm.coffee
+++ app/assets/javascripts/sprangular/directives/promoForm.coffee
@@ -3,12 +3,13 @@
   templateUrl: 'promos/form.html'
   scope:
     order: '='
-  controller: ($scope, Cart, Checkout) ->
+  controller: ($scope, Cart, Checkout, Angularytics) ->
     $scope.showPromoEntry = false
     $scope.promoCode = Cart.current.promoCode

     $scope.save = ->
       Cart.current.promoCode = $scope.promoCode
+      Angularytics.trackEvent("Cart", "Coupon added", $scope.promoCode)

       error = (message) ->
         $scope.promoCode = ''


[bugfix] prevent multiple file upload thumbnails and fix logo spinner

--- app/assets/javascripts/views/journal_thumbnail_view.js.coffee
+++ app/assets/javascripts/views/journal_thumbnail_view.js.coffee
@@ -1,7 +1,7 @@
 ETahi.JournalThumbnailView = Ember.View.extend
   toggleSpinner: (->
     if @get('controller.logoUploading')
-      @spinnerDiv = @$('.journal-logo-spinner')[0]
+      @spinnerDiv = @$('.journal-logo-spinner')?[0]
       @spinner ||= new Spinner(color: "#fff").spin(@spinnerDiv)
       $(@spinnerDiv).show()
     else
@@ -11,7 +11,7 @@
   togglePreview: (->
     Ember.run.schedule 'afterRender', =>
       if @get('controller.logoPreview')
-        @$('.journal-logo-preview').append(@get('controller.logoPreview'))
+        @$('.journal-logo-preview').empty().append(@get('controller.logoPreview'))
       else
         @$('.journal-logo-preview').html('')
   ).observes('controller.logoPreview')


show new appointments on calendar when created

fixes CNVS-32132

test plan
- enable new scheduler
- create an appointment group using the new "Appointment Group" tab
 on the modal event creation dialog
- ensure that events for the appointment slots appear on the
 calendar immediately rather than requiring a refresh

Change-Id: I2e44745409e519dee1bffee810856a636f454beb
Reviewed-on: https://gerrit.instructure.com/90966
Tested-by: Jenkins
Reviewed-by: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
QA-Review: Heath Hales <8ca81b68c7e2592ac614bd07f22fcc735ca55f93@instructure.com>
Product-Review: Joel Hough <4816dabf8db1bc6cac35b3a24cab2ff844b5b0c7@instructure.com>

--- app/coffeescripts/calendar/EditAppointmentGroupDetails.coffee
+++ app/coffeescripts/calendar/EditAppointmentGroupDetails.coffee
@@ -4,6 +4,7 @@
   'compiled/util/fcUtil'
   'i18n!EditAppointmentGroupDetails'
   'str/htmlEscape'
+  'compiled/calendar/commonEventFactory'
   'compiled/calendar/TimeBlockList'
   'jst/calendar/editAppointmentGroup'
   'jst/calendar/genericSelect'
@@ -13,7 +14,7 @@
   'jquery.ajaxJSON'
   'jquery.disableWhileLoading'
   'jquery.instructure_forms'
-], ($, _, fcUtil, I18n, htmlEscape, TimeBlockList, editAppointmentGroupTemplate, genericSelectTemplate, sectionCheckboxesTemplate, ContextSelector, preventDefault) ->
+], ($, _, fcUtil, I18n, htmlEscape, commonEventFactory, TimeBlockList, editAppointmentGroupTemplate, genericSelectTemplate, sectionCheckboxesTemplate, ContextSelector, preventDefault) ->

   class EditAppointmentGroupDetails
     constructor: (selector, @apptGroup, @contexts, @closeCB) ->
@@ -223,7 +224,11 @@
         # TODO: Provide UI for specifying this
         params['appointment_group[min_appointments_per_participant]'] = 1

-      onSuccess = => @closeCB(true)
+      onSuccess = (data) =>
+        for eventData in (data.new_appointments || [])
+          event = commonEventFactory(eventData, @contexts)
+          $.publish('CommonEvent/eventSaved', event)
+        @closeCB(true)
       onError = =>

       method = if @editing() then 'PUT' else 'POST'


Fix Register II

Fix Register II

--- libraries/metrics/metrics.coffee
+++ libraries/metrics/metrics.coffee
@@ -62,8 +62,8 @@

 	injectMetricsRoute: (app) ->
 		app.get('/metrics', (req, res) ->
-			res.set('Content-Type', register.contentType)
-			res.end(register.metrics())
+			res.set('Content-Type', Register.contentType)
+			res.end(Register.metrics())
 		)

 	buildPromKey: (key = "")->


Fix typo, gague -> gauge

Fix typo, gague -> gauge

--- libraries/metrics/metrics.coffee
+++ libraries/metrics/metrics.coffee
@@ -112,13 +112,13 @@

 	gauge : (key, value, sampleRate = 1, opts)->
 		key = Metrics.buildPromKey(key)
-		prom.metric('gague', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value))
+		prom.metric('gauge', key).set({app: appname, host: hostname, status: opts?.status}, this.sanitizeValue(value))
 		if process.env['DEBUG_METRICS']
 			console.log("doing gauge", key, opts)

 	globalGauge: (key, value, sampleRate = 1, opts)->
 		key = Metrics.buildPromKey(key)
-		prom.metric('gague', key).set({app: appname, status: opts?.status},this.sanitizeValue(value))
+		prom.metric('gauge', key).set({app: appname, status: opts?.status},this.sanitizeValue(value))

 	mongodb: require "./mongodb"
 	http: require "./http"


feat: make status code error message more informative

Extend message with information about real status code

--- src/mixins/validatable-http-message.coffee
+++ src/mixins/validatable-http-message.coffee
@@ -293,7 +293,7 @@

     @validation.statusCode.results = @validation.statusCode.results.map (current, index, arr) ->
       if current.message = 'Real and expected data does not match.'
-        current.message = "Status code is not '#{expected}'"
+        current.message = "Status code is '#{real}' instead of '#{expected}'"
       current


payments: plumbing

payments: plumbing

add some essential plumbing to payment settings view

--- client/app/Applications/Dashboard.kdapplication/views/paymentsettingsview.coffee
+++ client/app/Applications/Dashboard.kdapplication/views/paymentsettingsview.coffee
@@ -37,7 +37,6 @@
         billing             :
           label             : "Billing Method"
           itemClass         : BillingMethodView
-          data              : group
         history             :
           label             : "Payment History"
           tagName           : "a"
@@ -113,6 +112,8 @@

     @settingsForm = new KDFormViewWithFields formOptions, group

+    @forwardEvent @settingsForm.inputs.billing, 'BillingEditRequested'
+
     group.fetchBundle (err, bundle)=>
       if err or not bundle
         return
@@ -136,4 +137,8 @@
         inputs.overagePolicy.setOn()
         fields.approval.show()

+  setBillingInfo: (billingInfo) ->
+    { billing: billingView } = @settingsForm.inputs
+    billingView.setBillingInfo billingInfo
+
   pistachio:-> "{{> @settingsForm}}"


minor change to the policies

minor change to the policies

--- library/exposure/policies.coffee
+++ library/exposure/policies.coffee
@@ -69,9 +69,11 @@
         isEmpty = "an empty definition has been given"
         noCondition = "got invalid conditional argument"
         notDefined = "the definition has to be an object"
+        tooMany = "only one definition is allowed at time"
         condition = (-> @decision yes) unless condition
         assert _.isPlainObject(definition), notDefined
         assert _.isFunction(condition or 0), noCondition
+        assert _.keys(definition).length is 1, tooMany
         assert not _.isEmpty(definition or {}), isEmpty
         assert previous = this.policies or new Array()
         assert _.all _.values(definition), _.isString


Give intuitive names to args

Give intuitive names to args

--- library/membrane/validate.coffee
+++ library/membrane/validate.coffee
@@ -83,9 +83,9 @@
         transformed =  _.map _.values(vcontexts), transformer
         transformed = _.object _.keys(vcontexts), transformed
         async.parallel transformed, (error, results) =>
-            assert not error, "internal valdation error"
-            errors = _.any _.values(results), _.isObject
-            return continuation.bind(this) errors, results
+            failure = _.any _.values(results), _.isObject
+            assert.ifError error, "internal valdation error"
+            return continuation.bind(this) failure, results

     # Create new validation context for the values designated by
     # the `name` and add it to the supplied storage. If the `message`
@@ -151,9 +151,9 @@
         assert _.isFunction(continuation), notContinuation
         assert _.isObject(response), notResponse
         assert _.isObject(request), notRequest
-        @validateValues request.params, (error, results) ->
+        @validateValues request.params, (failure, results) ->
             signature = [results, request, response, continuation]
-            return @renderParamValidation signature... if error
+            return @renderParamValidation signature... if failure
             return continuation.bind(this) results

 # This is an ABC service intended to be used only as a compund. It
@@ -205,7 +205,7 @@
         assert _.isFunction(continuation), notContinuation
         assert _.isObject(response), notResponse
         assert _.isObject(request), notRequest
-        @validateValues request.headers, (error, results) ->
+        @validateValues request.headers, (failure, results) ->
             signature = [results, request, response, continuation]
-            return @renderHeaderValidation signature... if error
+            return @renderHeaderValidation signature... if failure
             return continuation.bind(this) results


Raised ratio requirements

Raised ratio requirements

--- server/queues/scoring.coffee
+++ server/queues/scoring.coffee
@@ -202,7 +202,7 @@
       cb null, true
     else
       ratio = (updatedSession.numberOfLosses) / (totalNumberOfGamesPlayed)
-      if ratio > 0.66
+      if ratio > 0.2
         cb null, false
         console.log "Ratio(#{ratio}) is bad, ending simulation"
       else


Added build task

Added build task

--- gulp.coffee
+++ gulp.coffee
@@ -5,6 +5,16 @@
 tasks = {
   clean: () ->
     all.task.clean()
+
+  build: () ->
+    all.lib.gulp
+    .src('src/**/*')
+    .pipe(all.pipe.transpile({
+      coffeeCoverage: null
+      jade: null
+      cson: null
+    }))
+    .pipe(all.lib.gulp.dest('lib'))
 }

 all.task.exportTasks(tasks)


Open dropdown if no plugin selected

Open dropdown if no plugin selected

--- views/single-tabarea.cjsx
+++ views/single-tabarea.cjsx
@@ -58,6 +58,7 @@
   getInitialState: ->
     key: 0
     pluginKey: -2
+    dropdownOpen: false
   nowTime: 0
   pluginKey: 0
   componentWillUpdate: (nextProps, nextState) ->
@@ -65,8 +66,12 @@
   componentDidUpdate: (prevProps, prevState) ->
     cur = (new Date()).getTime()
     console.log "the cost of tab-module's render: #{cur-@nowTime}ms" if process.env.DEBUG?
+  handleToggleDropdown: ->
+    dropdownOpen = !@state.dropdownOpen
+    @setState {dropdownOpen}
   handleSelect: (key) ->
     if key isnt @state.key
+      if key is -2 then @handleToggleDropdown()
       @setState
         key: if key isnt -2 then key else @state.key
         pluginKey: if key > 1 && key < 1000 then key else @state.pluginKey
@@ -174,7 +179,7 @@
                <FontAwesome name='sitemap' />{__ ' Plugins'}
            }
         </NavItem>
-        <NavDropdown id='plugin-dropdown' key={-1} eventKey={-1} pullRight>
+        <NavDropdown id='plugin-dropdown' key={-1} eventKey={-1} pullRight open={@state.dropdownOpen} onToggle={@handleToggleDropdown}>
         {
           counter = 1
           plugins.map (plugin, index) =>


Make atom.setSize() synchronous again, for now

This method is public, and a spec for TextEditorComponent dependend on it
staying synchronous

--- src/application-delegate.coffee
+++ src/application-delegate.coffee
@@ -28,7 +28,7 @@
     {width, height}

   setWindowSize: (width, height) ->
-    ipc.send("call-window-method", "setSize", width, height)
+    remote.getCurrentWindow().setSize(width, height)

   getWindowPosition: ->
     [x, y] = remote.getCurrentWindow().getPosition()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/metered.coffee
+++ src/metered.coffee
@@ -117,6 +117,7 @@
       y: 5
     radius: 3
     showName: true
+    text:

   # =>
   </pre></code>


Add an acceptance test to check the preview endpoint doesn't time out.

This endpoint needs a lot more testing.

--- test/acceptence/coffee/SendingFileTest.coffee
+++ test/acceptence/coffee/SendingFileTest.coffee
@@ -112,3 +112,14 @@
 					request.get newFileUrl, (err, response, body)=>
 						body.should.equal @constantFileContent
 						done()
+
+		describe "getting the preview image", ->
+
+			beforeEach ->
+				@fileUrl = @fileUrl + '?style=preview&cacheWarm=true'
+
+			it "should not time out", (done) ->
+				@timeout(1000 * 20)
+				request.get @fileUrl, (err, response, body) =>
+					expect(response).to.not.equal null
+					done()


Fix scrollTo in Firefox.

Fix scrollTo in Firefox.

Fixes `NS_ERROR_XPC_NOT_ENOUGH_ARGS: Not enough arguments [nsIDOMWindow.scrollTo]`.

--- src/chaplin/views/layout.coffee
+++ src/chaplin/views/layout.coffee
@@ -65,7 +65,7 @@
     # Handler for the global beforeControllerDispose event
     hideOldView: (controller) ->
       # Jump to the top of the page
-      scrollTo @settings.scrollTo if @settings.scrollTo
+      window.scrollTo.apply window, @settings.scrollTo if @settings.scrollTo

       # Hide the current view
       view = controller.view


Implement isAlive() more correctly.

Implement isAlive() more correctly.

--- src/natives.coffee
+++ src/natives.coffee
@@ -288,8 +288,8 @@
             rs.main_thread
         o 'setPriority0(I)V', (rs) -> # NOP
         o 'holdsLock(L!/!/Object;)Z', -> true
-        o 'isAlive()Z', (rs) -> false
-        o 'start0()V', (rs) -> # NOP
+        o 'isAlive()Z', (rs, _this) -> _this.fields.$isAlive ? false
+        o 'start0()V', (rs, _this) -> _this.fields.$isAlive = true
         o 'sleep(J)V', (rs, millis) ->
             rs.curr_frame().resume = -> # NOP
             throw new util.YieldException (cb) ->


Add another native and ... we can run Kawa Scheme now!

--- src/natives.coffee
+++ src/natives.coffee
@@ -772,6 +772,8 @@
             obj.get_field_from_offset rs, offset
         o 'getObject(Ljava/lang/Object;J)Ljava/lang/Object;', (rs,_this,obj,offset) ->
             obj.get_field_from_offset rs, offset
+        o 'putObject(Ljava/lang/Object;JLjava/lang/Object;)V', (rs,_this,obj,offset,new_obj) ->
+            obj.set_field_from_offset rs, offset, new_obj
         o 'putOrderedObject(Ljava/lang/Object;JLjava/lang/Object;)V', (rs,_this,obj,offset,new_obj) ->
             obj.set_field_from_offset rs, offset, new_obj
         o 'defineClass(Ljava/lang/String;[BIILjava/lang/ClassLoader;Ljava/security/ProtectionDomain;)Ljava/lang/Class;', (rs, name, b, offset, len, loader, pd) ->


サンプルに append / remove Router 周りのコードを追加

--- example/coffee/test-main.coffee
+++ example/coffee/test-main.coffee
@@ -43,8 +43,7 @@
   #   '/<string:user>/<int:post>/<friend>':['beforeMinchi']
   #   '/<int:id>':['beforeShow']
   routes :
-    '/':'index'
-    '/foo': FooRouter
+    '/':'index'
     # '/bar': BarRouter
     # '/<int:id>':'show'
     # '/<string:id>':'show'
@@ -149,6 +148,11 @@

   window.App = new Router({root:'/brand/'})
   console.log window.App.handlers
+  foo = new FooRouter({'isAutoStart':false})
+  window.App.appendRouter foo, '/foo/'
+  console.log window.App.handlers
+  window.App.removeRouter foo, '/foo/'
+  console.log window.App.handlers
   # #チェンジイベント
   # window.App.addEventListener( KazitoriEvent.CHANGE, (event)->
   #   console.log event, "change"


Use single capture index replacement string

This will handle both the $1 style and ${1:/downcase} styles in a
single replace call.

--- src/pattern.coffee
+++ src/pattern.coffee
@@ -1,8 +1,7 @@
 _ = require 'underscore-plus'

 AllDigitsRegex = /\\\d+/g
-CaptureIndexRegex = /\$(\d+)/
-CustomCaptureIndexRegex = /\${(\d+):\/(downcase|upcase)}/
+CustomCaptureIndexRegex = /\$(\d+)|\${(\d+):\/(downcase|upcase)}/
 DigitRegex = /\\\d+/

 module.exports =
@@ -115,21 +114,14 @@
       [this]

   resolveScopeName: (scopeName, line, captureIndices) ->
-    resolvedScopeName = scopeName.replace CustomCaptureIndexRegex, (match, index, command) ->
-      capture = captureIndices[parseInt(index)]
+    resolvedScopeName = scopeName.replace CustomCaptureIndexRegex, (match, index, commandIndex, command) ->
+      capture = captureIndices[parseInt(index ? commandIndex)]
       if capture?
         replacement = line.substring(capture.start, capture.end)
         switch command
           when 'downcase' then replacement.toLowerCase()
-          when 'upcase' then replacement.toUpperCase()
+          when 'upcase'   then replacement.toUpperCase()
           else replacement
-      else
-        match
-
-    resolvedScopeName.replace CaptureIndexRegex, (match, index) ->
-      capture = captureIndices[parseInt(index)]
-      if capture?
-        line.substring(capture.start, capture.end)
       else
         match


Make read better + comment

Make read better + comment

--- src/preview.coffee
+++ src/preview.coffee
@@ -61,7 +61,13 @@
 maybeLinkLegacyDir = (app, dir, callback) ->
   manifest.readManifest dir, (err, man) ->
     if err then return callback(err)
-    unless man?.launcher
+
+    # TODO would be nice to validate that there's a manifest.json
+    # (and other things) early on (for any command that requires
+    # there be a manifest in `dir`s) and bail out so we never make
+    # it this far outside a valid gadget dir
+    isLegacyGadget = man?.launcher
+    unless isLegacyGadget
       app.use '/scripts', express.static(path.resolve dir)
     callback null


Comment :lipstick:

Comment :lipstick:

--- src/project.coffee
+++ src/project.coffee
@@ -231,7 +231,7 @@
   getBuffers: ->
     new Array(@buffers...)

-  # Private: DEPRECATED
+  # Private: Only to be used in specs
   bufferForPath: (filePath, text) ->
     absoluteFilePath = @resolve(filePath)


Remove extra registering logging

Remove extra registering logging

--- src/publish.coffee
+++ src/publish.coffee
@@ -301,7 +301,6 @@
         originalName = pack.name

       @registerPackage pack, (error, firstTimePublishing) =>
-        console.log "registering #{pack.name}"
         return callback(error) if error?

         @renamePackage pack, rename, (error) =>


ComputeProvider: better plan handling

ComputeProvider: better plan handling

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -428,7 +428,7 @@
     maxAllowed   = MAX_INT
     if planConfig.plan
       plan       = teamutils.getPlanData planConfig
-      maxAllowed = plan.member
+      maxAllowed = plan.member ? MAX_INT

     JCounter = require '../counter'
     JCounter[change]
@@ -446,15 +446,15 @@

     { group, change, amount } = options

-    return callback null  if group.slug is 'koding'
-
-    planConfig = helpers.getPlanConfig group
-    return callback null  if amount is 0
+    # We don't need to do anything if amount somehow is 0
+    # A stack template without machines in it? ~ GG
+    return callback null  if group.slug is 'koding' or amount is 0

     maxAllowed   = MAX_INT
+    planConfig   = helpers.getPlanConfig group
     if planConfig.plan
       plan       = teamutils.getPlanData planConfig
-      maxAllowed = plan.maxInstance
+      maxAllowed = plan.maxInstance ? MAX_INT

     JCounter = require '../counter'
     JCounter[change]


activity: pass 'payload' to `ActivityAppController::post`

--- client/Social/Activity/views/inputwidget.coffee
+++ client/Social/Activity/views/inputwidget.coffee
@@ -218,7 +218,7 @@
     if channel.typeConstant is 'topic' and not body.match ///##{channel.name}///
       body += " ##{channel.name} "

-    appManager.tell 'Activity', 'post', {body}, (err, activity) =>
+    appManager.tell 'Activity', 'post', {body, payload}, (err, activity) =>

       @reset()  unless err


Activity: remove embedly preview from activity input

--- client/Social/Activity/views/inputwidget.coffee
+++ client/Social/Activity/views/inputwidget.coffee
@@ -346,7 +346,7 @@
     # @addSubView @avatar
     @addSubView @input
     @addSubView @buttonBar
-    @addSubView @embedBox
+    # @addSubView @embedBox
     @addSubView @bugNotification
     @addSubView @helpContainer
     @buttonBar.addSubView @submitButton


Client: Activity: Updated createMessage action to sync socialApiController cache data

--- client/activity/lib/flux/actions/message.coffee
+++ client/activity/lib/flux/actions/message.coffee
@@ -238,7 +238,11 @@
   # since this action works for all types of channel, we need to specify the
   # type when we are posting.
   channel = socialapi.retrieveCachedItemById channelId
-  type = channel.typeConstant
+  type    = channel.typeConstant
+
+  # the reason we are doing this is to sync socialApiController cache data
+  # FIXME: remove this after removing socialApiController
+  channel.unreadCount = 0

   fetchEmbedPayload { body, payload }, (err, embedPayload) ->
     return  if err


helper: toNickKeyedMap checks for publisher existence

--- client/app/lib/videocollaboration/helper.coffee
+++ client/app/lib/videocollaboration/helper.coffee
@@ -55,7 +55,7 @@

   map = {}
   map[subscriber.nick] = subscriber  for own cId, subscriber of subscribers
-  map[publisher.nick] = publisher
+  map[publisher.nick] = publisher  if publisher
   return map


Fixed issue with keyword not being found in first paragraph

--- client/apps/edit/components/layout/index.coffee
+++ client/apps/edit/components/layout/index.coffee
@@ -156,18 +156,26 @@

   checkSeo: =>
     imageCount = 0
+    textIndex = 0
     @fullText = []
-    @fullText.push("
 " + $(@article.get("lead_paragraph")).text() + "
 ")
-    for section in $(@article.get("sections"))
-      if section.type is "text"
+    if ($(@article.get('lead_paragraph')).text() != '')
+      @fullText.push('
 ' + $(@article.get('lead_paragraph')).text() + '
 ')
+      textIndex += 1
+
+    for section in $(@article.get('sections'))
+      if section.type is 'text' && textIndex == 0
+        @fullText.push('
 ' + $(section.body).find('p').andSelf().filter('p:first').text() + '
 ')
+        @fullText.push($(section.body).find('p').andSelf().filter('p:not(:first)').text())
+        textIndex += 1
+      else if section.type is 'text'
         @fullText.push($((section.body).replace(/<\/p>/g,"
")).text())
-      else if section.type is "artworks"
+      else if section.type is 'artworks'
         imageCount += 1
-      else if section.type is "image"
+      else if section.type is 'image'
         imageCount += 1
-    @fullText.push("") for num in [imageCount..1]
+    @fullText.push('') for num in [imageCount..1]
     @fullText = @fullText.join(' ')
-
+
     yoastView = new YoastView
       contentField: @fullText
       title: @article.get('title')


component-lab: update card info with new card icons

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/component-lab/CreditCard/CardInfo.coffee
+++ client/component-lab/CreditCard/CardInfo.coffee
@@ -23,12 +23,9 @@
       </Col>
     </Row>
     <Row className={styles['info-row']}>
-      <Col style={padding: '0 0 0 .5rem', minWidth: '30px'}>
-        <CardIcon
-          light
-          size='small'
-          brand={brand}
-          style={background: '#bbb'} />
+
+      <Col style={padding: '0 .5rem', minWidth: '30px'}>
+        <CardIcon small brand={brand} />
       </Col>

       <Col xs={4}>


Remove escaping HTML char

Remove escaping HTML char

--- src/roaster.coffee
+++ src/roaster.coffee
@@ -16,7 +16,7 @@

   conversion = (data) ->
     mdToHtml = marked(data)
-    emojified = emoji(mdToHtml, emojiFolder, 20).replace(/\\</g, "<")
+    emojified = emoji(mdToHtml, emojiFolder, 20)
     contents = taskLists(emojified)

   if typeof opts is 'function'


brought in TwitterListConversationTimeline from master

--- src/twitter.coffee
+++ src/twitter.coffee
@@ -143,6 +143,14 @@

         @subscribe @replies
         @subscribe @user
+class TwitterListConversationTimeline extends TwitterTimeline
+    constructor: (username, listname, options) ->
+        @list = new TwitterListTimeline username, listname, options
+        @replies = new ReplyTimeline @list
+
+        @subscribe @list
+        @subscribe @replies
+

 class ReplyTimeline extends Timeline
     # This subscribes to another timeline and publishes
@@ -175,6 +183,10 @@
     {
         pattern: /^@([a-z-_]+)\/([a-z-_]+)/i,
         fun: (_, name, list_name) -> new TwitterListTimeline(name, list_name)
+    },
+    {
+        pattern: /^@@([a-z-_]+)\/([a-z-_]+)/i,
+        fun: (_, name, list_name) -> new TwitterListConversationTimeline(name, list_name)
     },
     {
         pattern: /^@@([a-z0-9-_]+)$/i


Throw an error if it's an anonymous module

--- src/udefine.coffee
+++ src/udefine.coffee
@@ -38,6 +38,8 @@

   udefinable = (name, deps, factory, exportable) ->
     throw new Error 'A udefine module needs to have a name' unless name?
+
+    throw new Error 'Anonymous module are not allowed' if Array.isArray name

     unless name is name.toLowerCase()
       console.warn 'A module should be all lowercase'


Adde reset to state machine

Adde reset to state machine

--- framer/LayerStateMachine.coffee
+++ framer/LayerStateMachine.coffee
@@ -9,11 +9,9 @@
 class exports.LayerStateMachine extends BaseClass
 	constructor: (layer) ->
 		super
-		@_previousNames = []
 		@_layer = layer
-		@currentName = 'initial'
 		@initial = LayerStates.filterStateProperties(layer.props)
-		@states = new LayerStates(@)
+		@reset()

 	@define "current",
 		get: -> @states[@currentName]
@@ -41,6 +39,11 @@
 			states = @stateNames
 		Utils.arrayNext(states, @currentName)

+	reset: ->
+		@states = new LayerStates(@)
+		@_previousNames = []
+		@currentName = 'initial'
+
 	emit: (args...) ->
 			super
 			# Also emit this to the layer with self as argument


changed authors email

changed authors email

--- src/coffee/ezBreadcrumbs.coffee
+++ src/coffee/ezBreadcrumbs.coffee
@@ -1,6 +1,6 @@
 ###
  * EzBreadcrumbs - jQuery plugin that transforms a breadcrumbs to a responsive one. Useful when making responsive websites.
- * Copyright(c) Exequiel Ceasar Navarrete <exequiel.navarrete09@gmail.com>
+ * Copyright(c) Exequiel Ceasar Navarrete <exequiel.navarrete@ninthdesign.com>
  * Licensed under MIT
  * Version 1.0.3
 ###


Object: Data fallback is now undefined.

Object: Data fallback is now undefined.

--- src/coffee/object/Object.coffee
+++ src/coffee/object/Object.coffee
@@ -14,7 +14,7 @@
     @param   {*} data Class data
     @extends {goog.events.EventTarget}
   ###
-  constructor: (options = {}, data = null) ->
+  constructor: (options = {}, data) ->

     super options, data


Add canCancel(), canMove() methods to Member_Booking model

--- src/member/javascripts/models/booking.js.coffee
+++ src/member/javascripts/models/booking.js.coffee
@@ -61,3 +61,9 @@
           @member = new BBModel.Member.Member(member)
           defer.resolve(@member)
       defer.promise
+
+    canCancel: () ->
+      return moment(@min_cancellation_time).isAfter(moment())
+
+    canMove: () ->
+      return @canCancel()


Fixed issue #245 - No tag in conditions for new Overviews, Triggers, Schedulers and SLAs.

--- app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee
+++ app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee
@@ -38,6 +38,7 @@
         '^select$': ['is', 'is not', 'has changed']
         '^input$': ['contains', 'contains not', 'has changed']
         '^textarea$': ['contains', 'contains not', 'has changed']
+        '^tag$': ['contains all', 'contains one', 'contains all not', 'contains one not']

     operators_name =
       '_id$': ['is', 'is not']


Tune speech speed

Tune speech speed

--- src/renderer/scripts/app/SpeechHost.coffee
+++ src/renderer/scripts/app/SpeechHost.coffee
@@ -29,6 +29,6 @@
         return if app.config.get("nco.speech", false) is false

         s = new SpeechSynthesisUtterance(text)
-        s.rate = if text.length > 100 then 14 else 8
+        s.rate = if text.length > 100 then 10 else 5
         speechSynthesis.speak(s)
         return


Removed unused method.

Removed unused method.

--- javascripts/src/skeuocard.coffee
+++ javascripts/src/skeuocard.coffee
@@ -47,15 +47,11 @@
     @options = $.extend(optDefaults, opts)

     # initialize the card
-    @_applyBrowserFixes() # replace methods if necessary for specific browsers
     @_conformDOM() # conform the DOM to match our styling requirements
     @_setAcceptedCardProducts() # determine which card products to accept
     @_createInputs() # create reconfigurable input views
     @_updateProductIfNeeded()
     @_flipToInvalidSide()
-
-  _applyBrowserFixes: ->
-    ua = navigator.userAgent

   # Transform the elements within the container, conforming the DOM so that it
   # becomes styleable, and that the underlying inputs are hidden.


removed redundant else

removed redundant else

--- src/components/performance.cjsx
+++ src/components/performance.cjsx
@@ -20,8 +20,6 @@
   renderAverageCell: (heading) ->
     if heading.class_average
       classAverage = Math.round(heading.class_average)
-    else
-      classAverage = heading.class_average
     <th>{classAverage}</th>

   renderStudentRow: (student_data) ->


Properly detect when content has finished loading

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -11,10 +11,12 @@
     template: template
     templateHelpers:
       status: () -> @model.get('status')
-      editable: () -> @model.asPage()?.isEditable()
-      loaded: () -> @model.asPage()?.get('loaded')
+      editable: () -> @model.get('currentPage')?.isEditable()
       content: () -> @model.asPage()?.get('content')
       hasContent: () -> typeof @model.asPage()?.get('content') is 'string'
+      loaded: () ->
+        page = @model.asPage()
+        if page then page.get('loaded') else @model.get('loaded')

     editable:
       '.media-body':
@@ -29,6 +31,7 @@
     initialize: () ->
       super()

+      @listenTo(@model, 'change:loaded', @render)
       @listenTo(@model, 'change:currentPage change:currentPage.active change:currentPage.loaded', @render)

     # Perform mutations to the HTML before loading it on to the page for better performance


Show branch info in why-queued table on build page. Fixes #998.

--- js/inner/pages/build_page.coffee
+++ js/inner/pages/build_page.coffee
@@ -5,6 +5,7 @@
     @project_name = null
     @build_num = null
     @mention_branch = true
+    @show_branch = true

     super(properties)
     @name = "build"