first approach to the final version

first approach to the final version

--- coffee/upload.coffee
+++ coffee/upload.coffee
@@ -21,7 +21,7 @@

 class window.Upload

-  # This will contain all the convenience configuration for the upload class.
+  # This object contains all the convenience configuration for the upload class.
   @uploadSettings =
     uploadScript: 'serverScript.php'  # The script to send the data to. You can
                                       # use an URL here
@@ -33,17 +33,23 @@

   @currentFileSettings = {}

-  constructor: (uploadSettings) ->
-    if typeof uploadSettings.uploadScript isnt undefined and
+  constructor: (uploadSettings = null) ->
+    if uploadSettings != null and
+       typeof uploadSettings.uploadScript isnt undefined and
        typeof uploadSettings.uploadFolder isnt undefined and
        typeof uploadSettings.tmpFolder isnt undefined
+
       @uploadSettings = uploadSettings

-      @currentFileSettings =
-        file: {}
-        chunkIndex: 0
-        numberOfChunks: 0
-        tempName: null
+    else
+
+      @uploadSettings = Upload.uploadSettings
+
+    @currentFileSettings =
+      file: {}
+      chunkIndex: 0
+      numberOfChunks: 0
+      tempName: null

   # This method will handle the upload of each file
   uploadFile: (fileIndex) =>


rename varname

rename varname

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -640,16 +640,16 @@
     [startRow, endRow] = [newRange.start.row, newRange.end.row]
     suggestedLevel = @editor.suggestedIndentForBufferRow(startRow)
     minLevel = null
-    rowAndDetectedLevels = []
+    rowAndActualLevels = []
     for row in [startRow...endRow]
-      detectedLevel = getIndentLevelForBufferRow(@editor, row)
-      rowAndDetectedLevels.push([row, detectedLevel])
+      actualLevel = getIndentLevelForBufferRow(@editor, row)
+      rowAndActualLevels.push([row, actualLevel])
       unless isEmptyRow(@editor, row)
-        minLevel = Math.min(minLevel ? Infinity, detectedLevel)
-
-    if minLevel? and (levelDeltaToSuggestedLevel = suggestedLevel - minLevel)
-      for [row, detectedLevel] in rowAndDetectedLevels
-        newLevel = detectedLevel + levelDeltaToSuggestedLevel
+        minLevel = Math.min(minLevel ? Infinity, actualLevel)
+
+    if minLevel? and (deltaToSuggestedLevel = suggestedLevel - minLevel)
+      for [row, actualLevel] in rowAndActualLevels
+        newLevel = actualLevel + deltaToSuggestedLevel
         @editor.setIndentationForBufferRow(row, newLevel)
     return newRange


:bug: fix selection added in the middle of operation case

Range-marker target add selection in the middle of operation.
But when trying to restorePoint for added selection, it have no
property.
So in this case destroy selection to restore original sate(number of
selection keep same before/after).

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -73,18 +73,19 @@

   restorePoint: (selection) ->
     which = if @wasNeedStay then 'head' else 'start'
-    restore = -> swrap(selection).setBufferPositionTo(which, fromProperty: true)
-
-    if @isWithOccurrence()
-      if swrap(selection).getProperties().head?
+    restore = ->
+      swrap(selection).setBufferPositionTo(which, fromProperty: true)
+
+    if swrap(selection).getProperties().head?
+      if @isWithOccurrence()
         # Deffer restoring cursor point.
         # restorePoint is processed one by one, so immediately updating cursorPosition result in intersecting range with other selection
         # when intersecting selection is destroyed, cursor is moved automatically.
         @onDidFinishOperation -> restore()
       else
-        selection.destroy()
-    else
-      restore()
+        restore()
+    else
+      selection.destroy()

   observeSelectAction: ->
     # Select operator is used only in visual-mode.


KDFramework: KDradioGroup disabled radios support

--- client/Framework/components/inputs/KDInputRadioGroup.coffee
+++ client/Framework/components/inputs/KDInputRadioGroup.coffee
@@ -16,8 +16,10 @@
       radioOptions.visible   ?= yes
       radioOptions.callback or= ->

+      disabledClass = if radioOptions.disabled then 'disabled ' else ''
+
       div      = $ "<div/>",
-        class  : "kd-#{@getType()}-holder #{options.cssClassPrefix}#{@utils.slugify radioOptions.value}"
+        class  : "kd-#{@getType()}-holder #{disabledClass}#{options.cssClassPrefix}#{@utils.slugify radioOptions.value}"

       radio    = $ "<input/>",
         type   : @getType()
@@ -26,6 +28,9 @@
         class  : "no-kdinput#{if options.hideRadios then ' hidden' else ''}"
         id     : "#{@getId()}_#{@getType()}_#{i}"
         change : radioOptions.callback
+
+      if radioOptions.disabled
+        radio[0].setAttribute 'disabled', 'disabled'

       label    = $ "<label/>",
         for    : "#{@getId()}_#{@getType()}_#{i}"
@@ -44,6 +49,7 @@

   click:(event)->
     input = $(event.target).closest(".kd-#{@getType()}-holder").find('input')
+    return no if input[0].getAttribute('disabled') is 'disabled'
     @setValue input[0].getAttribute "value"

   setDefaultValue:(value) ->


Remove event to edit annotation on click

--- client/controllers/curatorInbox/curatorSourceDetails.coffee
+++ client/controllers/curatorInbox/curatorSourceDetails.coffee
@@ -152,14 +152,6 @@
   'click .back-to-list': (event, instance) ->
     instance.data.currentPaneInView.set('')

-  'click span.annotation': (event, instance) ->
-    incidentId = $(event.currentTarget).data('incident-id')
-    Modal.show 'incidentModal',
-      incident: Incidents.findOne(incidentId)
-      articles: [instance.source.get()]
-      edit: true
-      updateEvent: false
-
   'click .tabs a': (event, instance) ->
     instance.selectedIncidentTab.set(instance.$(event.currentTarget).data('tab'))


fix bug where other completions were deactivated

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -9,9 +9,9 @@
   # We don't want it to work in comments
   disableForSelector: '.comment'
   # Priorities for autocomplete
-  inclusionPriority: 2
-  suggestionPriority: 3
-  excludeLowerPriority: true
+  inclusionPriority: 1
+  suggestionPriority: 1
+  excludeLowerPriority: false
   # We want citations to be triggered by the @ symbol
   commandList: "@"


Agent pie testing

Agent pie testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -291,9 +291,10 @@
             .attr('alignment-baseline', 'central')
             .attr('filter','url(#dropshadow)')
             .style("opacity", 0)
-        totalLabel.text.transition()
+        totalLabel.enter().transition()
             .duration(1000)
             .style("opacity", 1)
+        totalLabel.exit()

         oldPieData = piedata
         return


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -403,7 +403,7 @@

         pie = d3.layout.pie()
             .sort(null)
-            #.value((d) -> d.value)
+            .value((d) -> d.value)

         arc = d3.svg.arc()
           .outerRadius(radiuso)


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -111,7 +111,7 @@
         return "translate(" + (x+r/2)*mx + "," + y*my + ")"
         )

-        .append("text").append("div").attr("class","cusipie-div")
+        .append("svg:tspan").attr("class","cusipie-label")

         .attr('fill', "#fff")
         .attr("text-anchor", "middle").text((d, i) ->


cleanup

cleanup

--- lib/ref-view.coffee
+++ lib/ref-view.coffee
@@ -1,5 +1,4 @@

-# {View} = require 'space-pen'
 {SelectListView} = require 'atom-space-pen-views'

 module.exports =
@@ -54,13 +53,7 @@

"""
     else
       return ""
-#

-#   #{item.entryTags.prettyAuthors}
-#   #{item.citationKey}
-#

-#   #{item.entryTags.prettyTitle}
-#

-#

+
   confirmed: (item)->
     #insert ref at cursor
     editor = atom.workspace.getActiveTextEditor()


fix: Highlights with RPM made for Fedora by the Fedora community. (#228)

--- lib/renderer.coffee
+++ lib/renderer.coffee
@@ -3,8 +3,16 @@
 path = require 'path'
 fs = require 'fs-plus'
 cheerio = require 'cheerio'
+
 # No direct dependence with Highlight because it requires a compilation. See #63 and #150 and atom/highlights#36.
-Highlights = require path.join atom.packages.resolvePackagePath('markdown-preview'), '..', 'highlights'
+markdownPreviewPath = atom.packages.resolvePackagePath 'markdown-preview'
+commonHighlightsPath = path.join markdownPreviewPath, '..', 'highlights'
+if fs.isDirectorySync commonHighlightsPath
+  Highlights = require commonHighlightsPath
+else
+  # Fix specific problem with RPM made for Fedora by the Fedora community. See #226.
+  Highlights = require path.join markdownPreviewPath, 'node_modules', 'highlights'
+
 {scopeForFenceName} = require './highlights-helper'

 {makeAttributes, makeOptions} = require './configuration-builder'


Remove empty Private: comment

Remove empty Private: comment

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -17,7 +17,6 @@
   @request: (options) ->
     request options, -> # Callback prevents errors from going to the console

-  # Private:
   @buildParams: (message, url, line, column, error) ->
     message = message.substring(0, 5*1024)


Handle multiple cursors

Handle multiple cursors

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -96,9 +96,10 @@

   getPrefixText: (snippets, editor) ->
     wordRegex = @wordRegexForSnippets(snippets)
-    cursor = editor.getCursor()
-    prefixStart = cursor.getBeginningOfCurrentWordBufferPosition({wordRegex})
-    editor.getTextInRange([prefixStart, cursor.getBufferPosition()])
+    cursors = editor.getCursors()
+    for cursor in cursors
+      prefixStart = cursor.getBeginningOfCurrentWordBufferPosition({wordRegex})
+      editor.getTextInRange([prefixStart, cursor.getBufferPosition()])

   enableSnippetsInEditor: (editorView) ->
     editor = editorView.getEditor()
@@ -160,16 +161,19 @@
     return false if _.isEmpty(snippets)

     prefix = @getPrefixText(snippets, editor)
-    return false unless prefix
+    return false unless prefix and _.uniq(prefix).length is 1

+    prefix = prefix[0]
     snippet = @snippetForPrefix(snippets, prefix)
     return false unless snippet?

     editor.transact =>
-      cursorPosition = editor.getCursorBufferPosition()
-      startPoint = cursorPosition.translate([0, -snippet.prefix.length], [0, 0])
-      editor.setSelectedBufferRange([startPoint, cursorPosition])
-      @insert(snippet, editor)
+      cursors = editor.getCursors()
+      for cursor in cursors
+        cursorPosition = cursor.getBufferPosition()
+        startPoint = cursorPosition.translate([0, -snippet.prefix.length], [0, 0])
+        editor.setSelectedBufferRange([startPoint, cursorPosition])
+        @insert(snippet, editor)
     true

   insert: (snippet, editor=atom.workspace.getActiveEditor()) ->


markup changed

markup changed

--- src/server/views/index.coffee
+++ src/server/views/index.coffee
@@ -29,6 +29,9 @@

         form ->
             div class: 'fromDate', ->
-                label "Период"
+                i class: 'icon-calendar icon-large'
                 span class: 'js-daterange', ->
+                    label "Период"
+                b class: 'caret'

+


delete commented-out test (case is covered several lines below)

--- test/parser/expressions.coffee
+++ test/parser/expressions.coffee
@@ -25,7 +25,6 @@

 assert parses('true || false'), 'logical or should parse'
 assert parses('true && false'), 'logical and should parse'
-#assert parses('!true'), 'logical invert should parse'

 # equality


Slots are now filtered by age. However updating the age filter will break search.

--- web/site/search.coffee
+++ web/site/search.coffee
@@ -132,7 +132,11 @@

       # Set the currently selected filter options here
       if ageRangeMin > 0 or ageRangeMax > 0
-        $scope.query = searchAge($scope.query, ageRangeMin, ageRangeMax)
+        if volId > 0
+          $scope.query = searchAge($scope.query, ageRangeMin, ageRangeMax, false)
+        else
+          $scope.query = searchAge($scope.query, ageRangeMin, ageRangeMax)
+

       console.log("QUERY IS: ", $scope.query)

@@ -376,9 +380,12 @@
       arg = "|arg=volume_id_i:#{ volume.id }"
       return query + arg

-    searchAge = (query, ageMin, ageMax) ->
+    searchAge = (query, ageMin, ageMax, join=true) ->
       # arg = "|arg=record_age_td:[#{ ageMin } TO #{ ageMax }]"
-      arg = "|join=volume_id_i,volume_id_i,record_age_td:[#{ ageMin } TO #{ ageMax }]"
+      if join
+        arg = "|join=volume_id_i,volume_id_i,record_age_td:[#{ ageMin } TO #{ ageMax }]"
+      else
+        arg = "|arg=record_age_td:[#{ ageMin } TO #{ ageMax }]"
       return query + arg

     searchSex = (volume, query, sex) ->


Rename File-Icons package's recompilation command

Refs DanBrooker/file-icons@9f654276

--- .config/keymap.cson
+++ .config/keymap.cson
@@ -34,7 +34,7 @@
 	"shift-cmd-M":    "file-icons:toggle-changed-only"
 	"alt-shift-T":    "file-icons:toggle-tab-icons"
 	"alt-o":          "file-icons:debug-outlines"
-	"alt-c":          "file-icons:recompile-cache"
+	"alt-c":          "file-icons:recompile-config"
 	"cmd-k up":       "unset!"
 	"cmd-k right":    "unset!"
 	"cmd-k left":     "unset!"


Add shortcut to toggle Minimap display

Add shortcut to toggle Minimap display

See also: https://github.com/atom-minimap/minimap#key-bindings

--- .config/keymap.cson
+++ .config/keymap.cson
@@ -34,6 +34,7 @@
 # Navigation
 'atom-workspace atom-text-editor:not(.mini)':
 	'cmd-g':		'go-to-line:toggle'
+	'cmd-enter':	'minimap:toggle'

 '.platform-darwin':
 	'cmd-0':		'tree-view:toggle'


:fire: Remove message modifying code from validate

--- lib/validate.coffee
+++ lib/validate.coffee
@@ -57,8 +57,5 @@
         throw new Error('Invalid filePath field on Linter response') if typeof result.filePath isnt 'string'
       else
         result.filePath = null
-      result.range = Range.fromObject result.range if result.range?
-      result.key = JSON.stringify(result)
-      result.name = result.name or linter.name
       Validate.messages(result.trace, linter) if result.trace and result.trace.length
     return


Change default modal button css classes

Change default modal button css classes

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1673,10 +1673,10 @@
     modalOptions.blocking ?= no
     modalOptions.buttons or=
       Yes        :
-        cssClass : 'modal-clean-green'
+        cssClass : 'solid green medium'
         callback : callback
       No         :
-        cssClass : 'modal-cancel'
+        cssClass : 'solid light-gray medium'
         callback : => @modal.destroy()

     ModalClass = if modalOptions.blocking then KDBlockingModalView else KDModalView


IDE: remove floating panel, use resize for collapsing

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -143,9 +143,11 @@

     # We want double click to work
     # if only the sidebar is collapsed. ~Umut
-    filesPane.on 'dblclick', (event) =>
-      KD.utils.stopDOMEvent event
-      @expandSidebar()  if @isSidebarCollapsed
+    expand = (event) =>
+      KD.utils.stopDOMEvent event  if event?
+      @toggleSidebar()  if @isSidebarCollapsed
+
+    filesPane.on 'TabHandleMousedown', expand

     baseSplit = panel.layout.getSplitViewByName 'BaseSplit'
     baseSplit.resizer.on 'dblclick', @bound 'toggleSidebar'
@@ -349,24 +351,39 @@
     {tabView}    = filesPane
     desiredSize  = 250

-    splitView.once 'PanelSetToFloating', =>
-      floatedPanel._lastSize = desiredSize
-      @getView().setClass 'sidebar-collapsed'
-      @isSidebarCollapsed = yes
-      KD.getSingleton("windowController").notifyWindowResizeListeners()
-
-    splitView.setFloatingPanel 0, 39
+    splitView.resizePanel 39, 0
+    @getView().setClass 'sidebar-collapsed'
+    floatedPanel.setClass 'floating'
     tabView.showPaneByName 'Dummy'
+
+    @isSidebarCollapsed = yes

     tabView.on 'PaneDidShow', (pane) ->
       return if pane.options.name is 'Dummy'
-      splitView.showPanel 0
-      floatedPanel._lastSize = desiredSize
-
-    floatedPanel.on 'ReceivedClickElsewhere', ->
-      KD.utils.defer ->
-        splitView.setFloatingPanel 0, 39
-        tabView.showPaneByName 'Dummy'
+      @expandSidebar()  if @isSidebarCollapsed
+
+
+    # TODO: This will reactivated after release.
+    # temporary fix. ~Umut
+
+    # splitView.once 'PanelSetToFloating', =>
+    #   floatedPanel._lastSize = desiredSize
+    #   @getView().setClass 'sidebar-collapsed'
+    #   @isSidebarCollapsed = yes
+    #   KD.getSingleton("windowController").notifyWindowResizeListeners()
+
+    # # splitView.setFloatingPanel 0, 39
+    # tabView.showPaneByName 'Dummy'
+
+    # tabView.on 'PaneDidShow', (pane) ->
+    #   return if pane.options.name is 'Dummy'
+    #   splitView.showPanel 0
+    #   floatedPanel._lastSize = desiredSize
+
+    # floatedPanel.on 'ReceivedClickElsewhere', ->
+    #   KD.utils.defer ->
+    #     splitView.setFloatingPanel 0, 39
+    #     tabView.showPaneByName 'Dummy'

   expandSidebar: ->
     panel        = @workspace.getView()
@@ -374,12 +391,18 @@
     floatedPanel = splitView.panels.first
     filesPane    = panel.getPaneByName 'filesPane'

-    floatedPanel._lastSize = 250
-    splitView.unsetFloatingPanel 0
-    filesPane.tabView.showPaneByIndex 0
-    floatedPanel.off 'ReceivedClickElsewhere'
+    splitView.resizePanel 250, 0
     @getView().unsetClass 'sidebar-collapsed'
+    floatedPanel.unsetClass 'floating'
     @isSidebarCollapsed = no
+    # filesPane.tabView.showPaneByIndex 0
+
+    # floatedPanel._lastSize = 250
+    # splitView.unsetFloatingPanel 0
+    # filesPane.tabView.showPaneByIndex 0
+    # floatedPanel.off 'ReceivedClickElsewhere'
+    # @getView().unsetClass 'sidebar-collapsed'
+    # @isSidebarCollapsed = no

   toggleSidebar: ->
     if @isSidebarCollapsed then @expandSidebar() else @collapseSidebar()


url was unused

url was unused

--- client/lanes/models/Sync.coffee
+++ client/lanes/models/Sync.coffee
@@ -69,7 +69,7 @@
         })

         # Ensure that we have a URL.
-        url = options.url or Lanes.Models.Sync.urlError()
+        options.url or Lanes.Models.Sync.urlError()
         options.url += '.json'
         unless _.isEmpty(query)
             options.url += '?' + Lanes.lib.objToParam(query)


:bug:Fix hint intro overview duplicates

:bug:Fix hint intro overview duplicates

--- app/views/play/level/HintsState.coffee
+++ app/views/play/level/HintsState.coffee
@@ -10,8 +10,8 @@

   update: ->
     hints = switch me.getHintsGroup()
-      when 'hints' then @level.get('documentation')?.hints or []
-      when 'hintsB' then @level.get('documentation')?.hintsB or []
+      when 'hints' then _.cloneDeep(@level.get('documentation')?.hints or [])
+      when 'hintsB' then _.cloneDeep(@level.get('documentation')?.hintsB or [])
       else []
     haveIntro = false
     haveOverview = false
@@ -25,6 +25,6 @@
       break if haveIntro and haveOverview
     total = _.size(hints)
     @set({
-      hints: hints
+      hints
       total
     })


constructor checks for oriDomiSupport

constructor checks for oriDomiSupport

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -99,7 +99,7 @@

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

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


annotation tweaks

annotation tweaks

--- oridomi.coffee
+++ oridomi.coffee
@@ -43,7 +43,7 @@
       prop = css[prop]
       prop = '-' + prop if prop.match /^(webkit|moz|ms)/i

-    # Convert camelcase to hypenated.
+    # Convert camel case to hyphenated.
     style += "#{ prop.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() }:#{ val };"

   styleBuffer += style + '}'
@@ -54,7 +54,7 @@
   "#{ css.gradientProp }(#{ anchor }, rgba(0, 0, 0, .5) 0%, rgba(255, 255, 255, .35) 100%)"

-# Used mainly when creating camelcased strings.
+# Used mainly when creating camel cased strings.
 capitalize = (s) ->
   s[0].toUpperCase() + s[1...]

@@ -218,7 +218,7 @@
   ]
   @

-# This section is wrapped in an immediately invoked function so that it can exit
+# This section is wrapped in a function call so that it can exit
 # early when discovering a lack of browser support to prevent unnecessary work.
 do ->
   # Loop through the CSS map and replace each value with the result of `testProp()`.


incremental commit - making regex builder for pattern.

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -535,12 +535,39 @@
       window.ParsleyValidator.addValidator('postalcodevalidator', ((value, requirement) ->
         # get formats
         # postal codes are always digits, chars, hyphens and whitespace
-        console.log "#{requirement}"
+        requirements = requirement.split(',')
+        console.log typeof requirements[0]
+        exp = '/^'
+        for c in requirements[0].trim().split("")
+          fragment = switch
+            when c is "A" then '[aA-zZ]{1}'
+            when c is "9" then '[0-9]{1}'
+            when c is "-" then '\\-{1}'
+            when c is " " then '\\s{1}'
+          exp += fragment
+        exp += '/g'
+        console.log(exp)
         # build regex following patterns
         # use regex.test(x) to see if value works
         # return true/false
         return false
       )).addMessage 'en', 'postalcodevalidator', 'Postal code should follow the pattern: %s'
+
+  regexPatternBuilder: (str)->
+    console.log str
+    console.log str.trim()
+    console.log string.trim().split('')
+    exp = '/^'
+    for c in str.trim().split("")
+      fragment = switch
+        when c is "A" then '[aA-zZ]{1}'
+        when c is "9" then '[0-9]{1}'
+        when c is "-" then '\\-{1}'
+        when c is " " then '\\s{1}'
+      exp += fragment
+    exp += '/g'
+    console.log(exp)
+    return exp

   eventGenerateOrderLink: ->


minor: code styling

minor: code styling

--- client/welcome/lib/index.coffee
+++ client/welcome/lib/index.coffee
@@ -1,6 +1,6 @@
-kd = require 'kd'
+kd               = require 'kd'
 KDViewController = kd.ViewController
-WelcomeAppView = require './welcomeappview'
+WelcomeAppView   = require './welcomeappview'

 module.exports = class WelcomeAppController extends KDViewController


Fix scratch

Fix scratch

--- scratch.coffee
+++ scratch.coffee
@@ -9,10 +9,18 @@
 global.Promise = require 'bluebird'
 Orca = require './src'

+class Edit extends Orca.Component
+  render: ->
+    React.createElement 'div', {}, [
+      React.createElement 'h1', {}, 'Edit'
+    ]
+
+class EditContext extends Orca.Context
+  @component: Edit
+
 class Main extends Orca.Component
-  constructor: ->
-    super
-    @state = edit: @createChildContext('edit', EditContext)
+  childContexts:
+    edit: EditContext

   render: ->
     React.createElement 'div', {}, [
@@ -20,17 +28,8 @@
       @createElementByContextKey('edit', {})
     ]

-class Edit extends Orca.Component
-  render: ->
-    React.createElement 'div', {}, [
-      React.createElement 'h1', {}, 'Edit'
-    ]
-
 class MainContext extends Orca.Context
   @component: Main
-
-class EditContext extends Orca.Context
-  @component: Edit

 # # Application
 router = new Orca.Router Orca.DefaultLayout, document.body


fixed monadic ⍨ (commute), issue #22

fixed monadic ⍨ (commute), issue #22

Apparently, f⍨⍵ is supposed to mean {⍵f⍵}, not just {f⍵}

--- src/vocabulary/commute.coffee
+++ src/vocabulary/commute.coffee
@@ -1,13 +1,17 @@
 {assert} = require '../helpers'

-# [Commute](http://www.jsoftware.com/papers/opfns1.htm#3) (`⍨`)
+# Commute (`⍨`)
 #
-# Definition: `x f⍨ y  <->  y f x`
+# Definition:
+#     x f⍨ y  <->  y f x
+#       f⍨ x  <->  x f x
 #
 # 17-⍨23 <=> 6
 # 7⍴⍨2 3 <=> 2 3⍴7
-# -⍨123  <=> ¯123
-@['⍨'] = (f) ->
+# +⍨2    <=> 4
+# -⍨123  <=> 0
+@['⍨'] = (f, g) ->
   assert typeof f is 'function'
+  assert not g?
   (omega, alpha, axis) ->
-    if alpha then f alpha, omega, axis else f omega, undefined, axis
+    if alpha then f alpha, omega, axis else f omega, omega, axis


simplified extendObj

simplified extendObj

--- oridomi.coffee
+++ oridomi.coffee
@@ -132,10 +132,7 @@
 # It is simple and one dimensional.
 extendObj = (target, source) ->
   # Check if the extension object is an object literal by casting it and comparing it.
-  if source isnt Object source
-    console.warn 'oriDomi: Must pass an object to extend with' if devMode
-    # Return the original target if its source isn't valid.
-    return target
+  return target if source isnt Object source
   # If the target isn't an object, set it to an empty object literal.
   target = {} if target isnt Object target
   # Loop through the extension object and copy its values to the target if they don't exist.


small fix for embed pilot live values

small fix for embed pilot live values

--- static/embed/oab_embed.coffee
+++ static/embed/oab_embed.coffee
@@ -1088,6 +1088,8 @@
     this.config[key] = if val is 'true' then true else if val is 'false' then false else val
   # make a "writable" config without unecessary params, such as those setting false etc
   # keep separate from this.config so that additional calls to configure take account of false if they do exist though
+  this.config.pilot = Date.now() if this.config.pilot is true
+  this.config.live = Date.now() if this.config.live is true
   for k of wc = JSON.parse JSON.stringify this.config
     delete wc[k] if not wc[k]? or wc[k] is false or ((typeof wc[k] is 'string' or Array.isArray(wc[k])) and wc[k].length is 0)
   try


When a row is deleted, transfer its childrens' time to the last remaining parent.

--- plugins/time-tracking/time-tracking.coffee
+++ plugins/time-tracking/time-tracking.coffee
@@ -1,3 +1,5 @@
+# Time-tracking keeps track of the amount of time spent in each subtree.
+# Clones are double-counted. This is a known bug and will not be fixed.
 (() ->

   pad = (val, length, padChar = '0') ->
@@ -31,6 +33,8 @@
       @api.view.addRenderHook 'infoElements', (@renderTime.bind @)
       @api.view.data.on 'afterDescendantRemoved', (@onDescendantRemoved.bind @)
       @api.view.data.on 'afterDescendantAdded', (@onDescendantAdded.bind @)
+      @api.view.data.on 'beforeRowRemoved', (@onRowRemoved.bind @)
+      @api.view.data.on 'afterRowAdded', (@onRowAdded.bind @)
       @rowChanges = []
       @currentRow = null
       @api.view.on 'exit', () =>
@@ -172,18 +176,38 @@
           current
     _rebuildTreeTimes: (id) ->
       children = @api.view.data._getChildren id
+      deletedChildren = (@getRowData id, 'deletedChildren') ? {}

       childTotalTimes = _.map children, (child_id) => @getRowData child_id, "treeTotalTime"
       rowTotalTime = @getRowData id, "rowTotalTime"
-      totalTimes = _.compact ([rowTotalTime].concat childTotalTimes)
+      deletedChildrenTotalTimes = _.pluck deletedChildren, 'totalTime'
+      totalTimes = _.compact [rowTotalTime].concat(childTotalTimes).concat(deletedChildrenTotalTimes)
       totalTime = sum totalTimes
       @setRowData id, "treeTotalTime", totalTime

       childDailyTimes = _.map children, (child_id) => @getRowData child_id, "treeDailyTime"
       rowDailyTime = @getRowData id, "rowDailyTime"
-      dailyTimes = _.compact ([rowDailyTime].concat childDailyTimes)
+      deletedChildrenDailyTimes = _.pluck deletedChildren, 'dailyTime'
+      dailyTimes = _.compact [rowDailyTime].concat(childDailyTimes).concat(deletedChildrenDailyTimes)
       dailyTime = @_combineDailyTimes.apply @, dailyTimes
       @setRowData id, "treeDailyTime", dailyTime
+
+    onRowRemoved: (event) ->
+      deletedChildren = (@getRowData event.parent_id, 'deletedChildren') ? {}
+      deletedChildren[event.id] = {
+        totalTime: (@getRowData event.id, "treeTotalTime") ? 0
+        dailyTime: (@getRowData event.id, "treeDailyTime") ? {}
+      }
+      @setRowData event.parent_id, 'deletedChildren', deletedChildren
+      for ancestor_id in @api.view.data.allAncestors event.id, { inclusive: false }
+        @_rebuildTreeTimes ancestor_id
+    onRowAdded: (event) ->
+      deletedChildren = (@getRowData event.parent_id, 'deletedChildren') ? {}
+      if event.id of deletedChildren
+        delete deletedChildren[event.id]
+        @setRowData event.parent_id, 'deletedChildren', deletedChildren
+        for ancestor_id in @api.view.data.allAncestors event.id, { inclusive: false }
+          @_rebuildTreeTimes ancestor_id

     rowTime: (row, range) ->
       if range?


social-api: cast createdAt, deletedAt, and updatedAt properties to `Date`

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -9,6 +9,7 @@
     return  unless plain = data.message or data

     {accountOldId, replies, interactions} = data
+    {createdAt, deletedAt, updatedAt}     = plain

     plain._id = plain.id

@@ -25,6 +26,11 @@
         actorsCount   : 0
         actorsPreview : []
         isInteracted  : no
+
+    m.meta      =
+      createdAt : new Date createdAt
+      deletedAt : new Date deletedAt
+      updatedAt : new Date updatedAt

     return m


LocalStorage: It’s failing to use localStorage when user disabled it in browser settings, we need to handle that. Now LocalStorage tries to use window.localStorage if fails it keeps in memory

--- client/app/MainApp/localstorage.coffee
+++ client/app/MainApp/localstorage.coffee
@@ -1,6 +1,12 @@
 class LocalStorage extends AppStorage

-  storage = window.localStorage
+  # This is necessary to check if its allowed to use window.localStorage
+  # otherwise it crashes the rest of the code
+  try
+    storage = window.localStorage
+  catch e
+    warn "#{e.name} occured while getting localStorage:", e.message
+    storage = {}

   fetchStorage:->
     KD.utils.defer => @emit "ready"


Kloud: add ability to bypass klientInfo mechanism for test

--- client/app/lib/kite/kites/kloud.coffee
+++ client/app/lib/kite/kites/kloud.coffee
@@ -40,15 +40,14 @@

       @needsRequest[machineId] = no

-      @askInfoFromKlient machineId, (klientInfo)=>
-
-        if klientInfo?
-
-          @resolveRequestingInfos machineId, klientInfo
-
-        else
-
-          @askInfoFromKloud machineId, currentState
+      # This is for tests, it bypasses klient info state
+      if @_disableKlientInfo
+        @askInfoFromKloud machineId, currentState
+      else
+        @askInfoFromKlient machineId, (klientInfo)=>
+          if klientInfo?
+          then @resolveRequestingInfos machineId, klientInfo
+          else @askInfoFromKloud machineId, currentState

     new Promise (resolve, reject) =>
       @requestingInfo[machineId] ?= []


Only reload if the query has changed

Only reload if the query has changed

--- client/lanes/components/grid/Grid.cjsx
+++ client/lanes/components/grid/Grid.cjsx
@@ -19,7 +19,7 @@
         @refs.grid?.reload() if newstate.query

     componentWillReceiveProps: (nextProps) ->
-        @refs.grid.reload() if nextProps.query
+        @refs.grid.reload() if nextProps.query isnt @props.query

     propTypes:
         query:  React.PropTypes.instanceOf(Lanes.Models.Query).isRequired


#248 - Question Labels appear in multiline textbox on edit

--- dkobo/koboform/static/js/xlform/view_detail_mixins.coffee
+++ dkobo/koboform/static/js/xlform/view_detail_mixins.coffee
@@ -28,7 +28,6 @@
   afterRender: ->
     viewUtils.makeEditable @, @model, 'blockquote', options:
       placement: 'right'
-      type: 'textarea'
       rows: 3

 DetailViewMixins.hint =


Fix for review

Fix for review

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -3401,18 +3401,17 @@

         binary_to_string: (bin) =>
             # We print the size of the binary, not the size of the base 64 string
-            size = bin.data.length*3/4
             blocks_of_76 = Math.floor(bin.data.length/78) # 78 to count \r\n
             leftover = bin.data.length-blocks_of_76*78

             base64_digits = 76*blocks_of_76+leftover

             blocks_of_4 = Math.floor(base64_digits/4)
-            leftover2 = base64_digits-Math.floor(base64_digits/4)
-
-            if bin.data.slice(-2) is '=='
+
+            end = bin.data.slice(-2)
+            if end is '=='
                 number_of_equals = 2
-            else if bin.data.slice(-1) is '='
+            else if end.slice(-1) is '='
                 number_of_equals = 1
             else
                 number_of_equals = 0
@@ -3421,15 +3420,13 @@

             if size >= 1073741824
                 sizeStr = (size/1073741824).toFixed(1)+'GB'
-            else if size>=1048576
+            else if size >= 1048576
                 sizeStr = (size/1048576).toFixed(1)+'MB'
-            else if size>=1024
+            else if size >= 1024
                 sizeStr = (size/1024).toFixed(1)+'KB'
-            else if size > 1
-                sizeStr = size+' bytes'
             else if size is 1
                 sizeStr = size+' byte'
-            else if size is 0
+            else
                 sizeStr = size+' bytes'

@@ -3437,7 +3434,7 @@
             if size is 0
                 return "<binary, #{sizeStr}>"
             else
-                str = atob bin.data.replace(/[ \r\n]+$/, "")
+                str = atob bin.data.slice(0, 8)
                 snippet = ''
                 for char, i  in str
                     next = str.charCodeAt(i).toString(16)
@@ -3449,11 +3446,7 @@
                         break
                     else
                         snippet += " "
-
-            return "<binary, #{sizeStr}, \"#{snippet}\">"
-
-
-
+                return "<binary, #{sizeStr}, \"#{snippet}\">"

     class @ResultView extends DataExplorerView.SharedResultView
         className: 'result_view'


removed commented out code

removed commented out code

--- app/assets/javascripts/groups.js.coffee
+++ app/assets/javascripts/groups.js.coffee
@@ -11,21 +11,3 @@
       (e) ->
         $(this).text("Membership Requested")
     )
-
-#$ ->
-  #isVisible = false
-  #clickedAway = false
-
-  #$('.info-help').popover(html: true, trigger: 'manual', placement: 'top').click((e) ->
-    #$(this).popover('show')
-    #isVisible = true
-    #e.preventDefault()
-  #)
-
-  #$(document).click((e) ->
-    #if(isVisible & clickedAway)
-      #$('.info-help').popover('hide')
-      #isVisible = clickedAway = false
-    #else
-      #clickedAway = true
-  #)


Checking issue with coffeescript

Checking issue with coffeescript

--- app/assets/javascripts/movies.js.coffee
+++ app/assets/javascripts/movies.js.coffee
@@ -23,6 +23,7 @@
     scenarioPass = (data.actors.indexOf(actorName) >= 0) && #The actor specified is in the movie.
     (data.actors.indexOf(nextActor) >= 0)  #The next actor is in the movie.
     allMovieData[index] = {name: movieName, poster: data.poster, pass: scenarioPass, actors: [actorName,nextActor]}
+    console.log(allMovieData)
     return passed = passed && scenarioPass

 showMovie = (movieData) ->


coerce int for min/max values

coerce int for min/max values

--- app/assets/javascripts/zvg/point.coffee
+++ app/assets/javascripts/zvg/point.coffee
@@ -60,13 +60,13 @@

   min_value: (value) ->
     if value or value is 0
-      @_min_value = value
+      @_min_value = parseInt(value)
       return @
     @_min_value

   max_value: (value) ->
     if value
-      @_max_value = value
+      @_max_value = parseInt(value)
       return @
     @_max_value


SmallFix: moved the dependency injection to the correct taskboard controller

--- app/coffee/controllers/taskboard.coffee
+++ app/coffee/controllers/taskboard.coffee
@@ -325,10 +325,10 @@

 module = angular.module("taiga.controllers.taskboard", [])
-module.controller("TaskboardTaskController", ['$scope', '$rootScope', '$q', "$location", "$favico",
+module.controller("TaskboardTaskController", ['$scope', '$rootScope', '$q', "$location",
                                               TaskboardTaskController])
 module.controller("TaskboardController", ['$scope', '$rootScope', '$routeParams', '$q', 'resource', '$data',
-                                          '$modal', "$model", "$i18next", TaskboardController])
+                                          '$modal', "$model", "$i18next", "$favico", TaskboardController])
 module.controller("TaskboardTaskModalController", ['$scope', '$rootScope', '$gmOverlay', '$gmFlash', 'resource',
                                                    "$i18next", TaskboardTaskModalController])
 module.controller('TaskboardBulkTasksModalController', ['$scope', '$rootScope', '$gmOverlay', 'resource',


fix issue 4573

fix issue 4573

--- app/coffee/modules/related-tasks.coffee
+++ app/coffee/modules/related-tasks.coffee
@@ -168,6 +168,8 @@
             $scope.newTask = $tgmodel.make_model("tasks", newTask)

         render = ->
+            return if $scope.openNewRelatedTask
+
             $scope.openNewRelatedTask = true

             $el.on "keyup", "input", (event)->


enhance: get total projects using meta

enhance: get total projects using meta

--- app/components/project-component.coffee
+++ app/components/project-component.coffee
@@ -11,7 +11,7 @@
     store = @get "store"
     store.query 'project', query
       .then (data)->
-        that.set "projectCount", data.toArray().length
+        that.set "projectCount", data.meta.total
         that.set "projects", data
   ).property()


True realtime URL

True realtime URL

--- app/frontend/scripts/realtime.js.coffee
+++ app/frontend/scripts/realtime.js.coffee
@@ -1,6 +1,6 @@
 play = exports ? this

-socket = new WebSocket('ws://localhost:9393/realtime')
+socket = new WebSocket('ws://localhost:5050/realtime')

 socket.onopen = () ->

@@ -12,4 +12,4 @@

   list = listFromJson(JSON.parse(message.data))
   songs = Mustache.to_html(templates.list,list,templates)
-  $('#songs').html(songs)+  $('#songs').html(songs)


Tidy up.

Tidy up.

Remove reference to unused setting "vomnibarInTopFrame".

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -44,7 +44,7 @@
   loadedValues: 0
   valuesToLoad: [ "scrollStepSize", "linkHintCharacters", "linkHintNumbers", "filterLinkHints", "hideHud",
     "previousPatterns", "nextPatterns", "regexFindMode", "userDefinedLinkHintCss",
-    "helpDialog_showAdvancedCommands", "smoothScroll", "grabBackFocus", "vomnibarInTopFrame" ]
+    "helpDialog_showAdvancedCommands", "smoothScroll", "grabBackFocus" ]
   isLoaded: false
   eventListeners: {}

@@ -275,7 +275,6 @@
 executePageCommand = (request) ->
   # Vomnibar commands are handled in the tab's main/top frame.  They are handled even if Vimium is otherwise
   # disabled in the frame.
-  console.log frameId, request
   if request.command.split(".")[0] == "Vomnibar"
     if DomUtils.isTopFrame()
       # We pass the frameId from request.  That's the frame which originated the request, so that's the frame


Add spec for stopping on first install failure

--- spec/install-spec.coffee
+++ spec/install-spec.coffee
@@ -97,6 +97,20 @@
           expect(fs.existsSync(path.join(testModule2Directory, 'package.json'))).toBeTruthy()
           expect(callback.mostRecentCall.args[0]).toBeUndefined()

+      it "installs them in order and stops on the first failure", ->
+        testModuleDirectory = path.join(atomHome, 'packages', 'test-module')
+
+        callback = jasmine.createSpy('callback')
+        apm.run(['install', "test-module3", "test-module"], callback)
+
+        waitsFor 'waiting for install to complete', 600000, ->
+          callback.callCount is 1
+
+        runs ->
+          expect(fs.existsSync(path.join(testModuleDirectory, 'index.js'))).toBeFalsy()
+          expect(fs.existsSync(path.join(testModuleDirectory, 'package.json'))).toBeFalsy()
+          expect(callback.mostRecentCall.args[0]).not.toBeUndefined()
+
     describe 'when no path is specified', ->
       it 'installs all dependent modules', ->
         moduleDirectory = path.join(temp.mkdirSync('apm-test-module-'), 'test-module-with-dependencies')


Fix indentation of till motion spec

Fix indentation of till motion spec

--- spec/motions-spec.coffee
+++ spec/motions-spec.coffee
@@ -954,51 +954,53 @@
       commandModeInputKeydown('a')
       expect(editor.getText()).toEqual 'abcbc\n'

-describe 'the t/T keybindings', ->
-  beforeEach ->
-    editor.setText("abcabcabcabc\n")
-    editor.setCursorScreenPosition([0, 0])
-
-  it 'moves to the character previous to the first specified character it finds', ->
-    keydown('t')
-    commandModeInputKeydown('a')
-    expect(editor.getCursorScreenPosition()).toEqual [0, 2]
-
-  it 'moves backwards to the character after the first specified character it finds', ->
-    editor.setCursorScreenPosition([0, 2])
-    keydown('T', shift: true)
-    commandModeInputKeydown('a')
-    expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-
-  it 'respects count forward', ->
-    keydown('2')
-    keydown('t')
-    commandModeInputKeydown('a')
-    expect(editor.getCursorScreenPosition()).toEqual [0, 5]
-
-  it 'respects count backward', ->
-    editor.setCursorScreenPosition([0, 6])
-    keydown('2')
-    keydown('T', shift: true)
-    commandModeInputKeydown('a')
-    expect(editor.getCursorScreenPosition()).toEqual [0, 1]
-
-  it "doesn't move if the character specified isn't found", ->
-    keydown('t')
-    commandModeInputKeydown('d')
-    expect(editor.getCursorScreenPosition()).toEqual [0, 0]
-
-  it "doesn't move if there aren't the specified count of the specified character", ->
-    keydown('1')
-    keydown('0')
-    keydown('t')
-    commandModeInputKeydown('a')
-    expect(editor.getCursorScreenPosition()).toEqual [0, 0]
-
-  it "composes with d", ->
-    editor.setCursorScreenPosition([0,3])
-    keydown('d')
-    keydown('2')
-    keydown('t')
-    commandModeInputKeydown('a')
-    expect(editor.getText()).toEqual 'abcabc\n'
+  describe 'the t/T keybindings', ->
+    beforeEach ->
+      editor.setText("abcabcabcabc\n")
+      editor.setCursorScreenPosition([0, 0])
+
+    it 'moves to the character previous to the first specified character it finds', ->
+      keydown('t')
+      commandModeInputKeydown('a')
+      expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+    it 'moves backwards to the character after the first specified character it finds', ->
+      editor.setCursorScreenPosition([0, 2])
+      keydown('T', shift: true)
+      commandModeInputKeydown('a')
+      expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+    it 'respects count forward', ->
+      keydown('2')
+      keydown('t')
+      commandModeInputKeydown('a')
+      expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+
+    it 'respects count backward', ->
+      editor.setCursorScreenPosition([0, 6])
+      keydown('2')
+      keydown('T', shift: true)
+      commandModeInputKeydown('a')
+      expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+    it "doesn't move if the character specified isn't found", ->
+      keydown('t')
+      commandModeInputKeydown('d')
+      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+    it "doesn't move if there aren't the specified count of the specified character", ->
+      keydown('1')
+      keydown('0')
+      keydown('t')
+      commandModeInputKeydown('a')
+      expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+    it "composes with d", ->
+      editor.setCursorScreenPosition([0,3])
+      keydown('d')
+      keydown('2')
+      keydown('t')
+      commandModeInputKeydown('a')
+      expect(editor.getText()).toEqual 'abcabc\n'
+
+


removed flickering at the end of transition

--- source/javascripts/morpher/lib/morpher.js.coffee
+++ source/javascripts/morpher/lib/morpher.js.coffee
@@ -166,8 +166,10 @@
     @animationStep()
     @updateMesh()
     blend = @blendFunction || MorpherJS.Morpher.defaultBlendFunction
-    if @canvas.width > 0 && @canvas.height > 0
-      for image in @images
+    if @canvas.width > 0 && @canvas.height > 0
+      sortedImages = @images.slice().sort (a, b) ->
+        b.weight - a.weight
+      for image in sortedImages
         @tmpCanvas.width = @tmpCanvas.width
         image.draw @tmpCtx, @mesh
         blend @canvas, @tmpCanvas, image.weight
@@ -193,8 +195,8 @@
       img.setMaxSize(@canvas.width, @canvas.height)

   updateMesh: =>
-    x0 = @canvas.width/2
-    y0 = @canvas.height/2
+    x0 = @canvas.width / 2
+    y0 = @canvas.height / 2
     for p, i in @mesh.points
       p.x = x0
       p.y = y0


reset the 'failedLoad' state when a new entity is selected

--- services/web/public/coffee/ide/binary-files/controllers/BinaryFileController.coffee
+++ services/web/public/coffee/ide/binary-files/controllers/BinaryFileController.coffee
@@ -1,9 +1,11 @@
 define [
 	"base"
 ], (App) ->
-	App.controller "BinaryFileController", ["$scope", ($scope) ->
+	App.controller "BinaryFileController", ["$scope", "$rootScope", ($scope, $rootScope) ->

 		$scope.failedLoad = false
+		$rootScope.$on 'entity:selected', () ->
+			$scope.failedLoad = false

 		window.sl_binaryFilePreviewError = () =>
 			$scope.failedLoad = true


project description placeholder

project description placeholder

--- project.coffee
+++ project.coffee
@@ -6,6 +6,7 @@
   title: 'Orchid Observers'
   summary: 'hello world'
   description: '''
+    short project description goes here.
                  '''


add link

add link

--- src/Index.cjsx
+++ src/Index.cjsx
@@ -1,7 +1,11 @@
 React = require "react"
+{Link} = require "react-router"

 Index = React.createClass
   render: ->
-
Welcome,Home

-
+

+
Welcome,Home

+
<Link to="/movies">电影</Link>

+
<Link to="/books">书籍</Link>

+

 module.exports = Index


Remove unusued cluster.coffee

Remove unusued cluster.coffee

--- cluster.coffee
+++ cluster.coffee
@@ -1,9 +0,0 @@
-recluster = require "recluster" # https://github.com/doxout/recluster
-path = require "path"
-
-cluster = recluster path.join(__dirname, 'app.js'), {
-		workers: 2,
-		backoff: 0,
-		readyWhen: "listening"
-}
-cluster.run()


Remove unnecessary parameter

Remove unnecessary parameter

--- command.coffee
+++ command.coffee
@@ -197,7 +197,7 @@
         rewatch()
         compile()
       catch e
-        removeSource source, base, yes
+        removeSource source, base
         compileJoin()
     else throw e

@@ -247,17 +247,17 @@
   delete watchedDirs[source]
   sourcesChanged = no
   for file in sources when source is path.dirname file
-    removeSource file, base, yes
+    removeSource file, base
     sourcesChanged = yes
   compileJoin() if sourcesChanged

 # Remove a file from our source list, and source code cache. Optionally remove
 # the compiled JS version as well.
-removeSource = (source, base, removeJs) ->
+removeSource = (source, base) ->
   index = sources.indexOf source
   sources.splice index, 1
   sourceCode.splice index, 1
-  if removeJs and not opts.join
+  unless opts.join
     jsPath = outputPath source, base
     try
       fs.unlinkSync jsPath


Add timeout

Add timeout

--- command.coffee
+++ command.coffee
@@ -1,20 +1,23 @@
 _         = require 'lodash'
+async     = require 'async'
 commander = require 'commander'
 redis     = require 'redis'
 RedisNS   = require '@octoblu/redis-ns'
+Siphon    = require './src/siphon'

 class Command
   constructor: ->

   parseOptions: =>
     commander
-      .option '-i, --input-ns <namespace>', 'Namespace from which to siphon (env: SIPHON_INPUT_NS)'
+      .option '-i, --input-ns <namespace>',  'Namespace from which to siphon (env: SIPHON_INPUT_NS)'
       .option '-o, --output-ns <namespace>', 'Namespace to siphon in to (env: SIPHON_OUTPUT_NS)'
-      .option '-r, --rate <rate>', 'Rate at which to siphon work, defaults to x'
+      .option '-t, --timeout <seconds>', 'Timeout in seconds when waiting for jobs, default 30s (env: SIPHON_TIMEOUT)'
       .parse process.argv

-    @inputNS = commander.inputQueue ? process.env.SIPHON_INPUT_NS
-    @outputNS = commander.outputQueue ? process.env.SIPHON_OUTPUT_NS
+    @inputNS = commander.inputNs ? process.env.SIPHON_INPUT_NS
+    @outputNS = commander.outputNs ? process.env.SIPHON_OUTPUT_NS
+    @timeoutSeconds = parseInt(commander.timeout ? process.env.SIPHON_OUTPUT_NS || 30)

     unless @inputNS && @outputNS
       commander.outputHelp()
@@ -23,16 +26,15 @@
   run: =>
     @parseOptions()

-    inClient     = _.bindAll new RedisNS(@inputNS, redis.createClient @redisUri)
-    inJobManager = new JobManager client: inClient
+    inClient  = new RedisNS(@inputNS, redis.createClient @redisUri)
+    inClient  = _.bindAll inClient, _.functions(inClient)
+    outClient = new RedisNS(@outputNS, redis.createClient @redisUri)
+    outClient = _.bindAll outClient, _.functions(outClient)

-    outClient     = _.bindAll new RedisNS(@outputNS, redis.createClient @redisUri)
-    outJobManager = new JobManager client: outClient
-
-    timeoutSeconds = 1
-
-    siphon = new Siphon {inClient, outClient, timeoutSeconds}
-    siphon.do()
+    siphon = new Siphon {inClient, outClient, @timeoutSeconds}
+    async.forever siphon.do, (error) =>
+      console.error error.stack
+      console.error 'No longer accepting new work'

 command = new Command
 command.run()


Promise.try

Promise.try

--- src/app.coffee
+++ src/app.coffee
@@ -19,11 +19,9 @@

 getIptablesRules = (callback) ->
 	async.retry {times: 100, interval: 100}, (cb) ->
-		try
-			myIP = os.networkInterfaces().tether[0].address
-			cb(null, myIP)
-		catch err
-			cb(err)
+		Promise.try ->
+			os.networkInterfaces().tether[0].address
+		.nodeify(cb)
 	, (err, myIP) ->
 		throw err if err?
 		callback null, [


Update camera tab: at first check capture,

if false, check getUserMedia support

--- app/assets/javascripts/uploadcare/widget/tabs/camera-tab.coffee
+++ app/assets/javascripts/uploadcare/widget/tabs/camera-tab.coffee
@@ -11,10 +11,6 @@
   class ns.CameraTab

     constructor: (@container, @tabButton, @dialogApi, @settings, @name) ->
-      if not @__checkCompatibility()
-        @dialogApi.hideTab(@name)
-        return
-
       if @__checkCapture()
         @container.append(tpl('tab-camera-capture'))
         @container.addClass('uploadcare--camera')
@@ -28,6 +24,9 @@
         fileButton.on 'click', =>
           utils.fileSelectDialog @container, {inputAcceptTypes: 'video/*'}, handleFiles, {capture: 'camera'}
       else
+        if not @__checkCompatibility()
+          @dialogApi.hideTab(@name)
+          return
         @__initCamera()

     __initCamera: ->


Handle debug log with emitting 'esa.debug' event

--- src/esa.coffee
+++ src/esa.coffee
@@ -137,38 +137,38 @@
   return robot.logger.error "Missing configuration: HUBOT_ESA_ACCESS_TOKEN" unless options.token?
   return robot.logger.error "Missing configuration: HUBOT_ESA_WEBHOOK_DEFAULT_ROOM" unless options.room?

-  debugLogger = (msg) ->
-    robot.logger.info "hubot-esa: #{msg}" if options.debug
-
-  debugLogger 'Enabled script'
+  robot.on 'esa.debug', (message) ->
+    robot.logger.info "hubot-esa: #{message}" if options.debug
+
+  robot.emit 'esa.debug', 'Enabled script'

   esa = new EsaClientRobot(robot, options.team, options.token)

   robot.respond /esa stats/, (res) ->
-    debugLogger 'heared stats command'
+    robot.emit 'esa.debug', 'heared stats command'
     esa.getStats (stats) ->
       robot.emit 'esa.hear.stats', res, stats
-      debugLogger "emit esa.hear.stats with stats:\n#{stats}"
+      robot.emit 'esa.debug', "emit esa.hear.stats with stats:\n#{stats}"

   robot.hear /https:\/\/(.+)\.esa\.io\/posts\/(\d+)(?!(\#comment-\d+))\b/, (res) ->
-    debugLogger 'heared post url'
+    robot.emit 'esa.debug', 'heared post url'
     [_, team, post_id] = res.match
     unless team == options.team then return
     esa.getPost post_id, (post) ->
       robot.emit 'esa.hear.post', res, post
-      debugLogger "emit esa.hear.post with post:\n#{post}"
+      robot.emit 'esa.debug', "emit esa.hear.post with post:\n#{post}"

   robot.hear /https:\/\/(.+)\.esa\.io\/posts\/(\d+)\#comment-(\d+)\b/, (res) ->
-    debugLogger 'heared comment url'
+    robot.emit 'esa.debug', 'heared comment url'
     [_, team, post_id, comment_id] = res.match
     unless team == options.team then return
     esa.getComment comment_id, (comment) ->
       esa.getPost post_id, (post) ->
         robot.emit 'esa.hear.comment', res, comment, post
-        debugLogger "emit esa.hear.comment with post:\n#{post}\n comment:\n#{comment}"
+        robot.emit 'esa.debug', "emit esa.hear.comment with post:\n#{post}\n comment:\n#{comment}"

   robot.router.post options.endpoint, (req, res) ->
-    debugLogger "received a webhook by #{req.headers['user-agent']}"
+    robot.emit 'esa.debug', "received a webhook by #{req.headers['user-agent']}"
     new EsaWebhook(robot.brain, req, options.webhook_secret)
     .on 'unauthorized', (err) ->
       robot.logger.warning err
@@ -179,7 +179,7 @@
       res.writeHead(409)
       res.end()
     .handle (kind, data) ->
-      debugLogger "emit esa.webhook with kind: #{kind}\n data:\n#{data}"
+      robot.emit 'esa.debug', "emit esa.webhook with kind: #{kind}\n data:\n#{data}"
       robot.emit 'esa.webhook', kind, data
       res.writeHead(204)
       res.end()


- Removed calibration routines, since we're focusing on using the   EyeX now instead of the EyeTribe. Calibration will most likely   need to be accomplished using the tracker's utilities. - Corrected some problems since converting to a class.

--- src/eye.coffee
+++ src/eye.coffee
@@ -1,9 +1,8 @@
 _ = require 'lodash'
 Buffer = require './buffer'
 Indicator = require './indicator'
-Interface = require './interface'
-utilities = require './utilities'
 connection = require './connection'
+

 module.exports = class Eye

@@ -43,7 +42,7 @@
     @connection.connect()

-  triggerEvent: (event) ->
+  triggerEvents: (event) ->
     event = event.split /\s+/
     if event.length == 1
       event = event[0]
@@ -52,7 +51,7 @@
         if el isnt null then el.dispatchEvent(evt)
     else
       for e in event
-        @triggerEvent e
+        @triggerEvents e

   handleWink: (side, el) ->
@@ -60,11 +59,11 @@
       when 'left'
         if ++leftCount <= 3 then return
         leftCount = 0
-        @triggerEvent 'leftwink wink'
+        @triggerEvents 'leftwink wink'
       when 'right'
         if ++rightCount <= 3 then return
         rightCount = 0
-        @triggerEvent 'rightwink wink'
+        @triggerEvents 'rightwink wink'

   handleBlink: (open, close) ->
@@ -79,7 +78,7 @@
     if ((diff >= blinkTime - cushion) && (diff <= blinkTime + cushion))
       @indicator.scale(0.8, 200)
       @freeze()
-      @triggerEvent 'blink mousedown mouseup click'
+      @triggerEvents 'blink mousedown mouseup click'

   handleDoubleBlink: (open, close) ->
@@ -88,7 +87,7 @@
     if (diff < 200)
       @indicator.scale(0.8, 200)
       @freeze()
-      @triggerEvent 'doubleblink mousedown mouseup click'
+      @triggerEvents 'doubleblink mousedown mouseup click'

   handleBlinks = (frame) ->
@@ -115,9 +114,9 @@
     els = @indicator.getGazeElements() or []
     for el in @gazeEls
       if el not in els
-        @triggerEvent 'gazeleave mouseleave mouseout'
+        @triggerEvents 'gazeleave mouseleave mouseout'
     @gazeEls = els
-    @triggerEvent 'gaze mousemove mouseenter mouseover'
+    @triggerEvents 'gaze mousemove mouseenter mouseover'

   freeze: ->
     @frozen = true
@@ -130,11 +129,16 @@
     @enabled = true

   disable: ->
-    @triggerEvent 'gazeleave'
+    @triggerEvents 'gazeleave'
     @gazeEls = []
     @indicator.hide()
     @enabled = false

+  ##
+  # Calculates the positional offsets of the browser window relative to the
+  # screen.
+  #
+  # @todo This should use a click event, or perhaps be delegated to the clients.
   calcScreenOffsets: ->
     # compute width of borders
     borderWidth = (window.outerWidth - window.innerWidth) / 2
@@ -148,8 +152,11 @@
     @innerScreenY = innerScreenY

+  ##
+  # @todo This method should use the timestamp on the frame, not a new Date
+  # object when pushing opens and closes.
   handleFrame: (frame) ->
-    if window.Eye.frozen or !Eye.enabled or !windowActive then return
+    if @frozen or !@enabled or !@windowActive then return

     if @lastFrame

@@ -160,10 +167,10 @@
       openThisFrame   = frame.avg.x != 0 and frame.avg.y != 0

       if closedThisFrame and openLastFrame
-        closes.push(new Date());
+        @closes.push(new Date());

       if closedLastFrame and openThisFrame
-        opens.push(new Date());
+        @opens.push(new Date());

     @lastFrame = frame

@@ -171,91 +178,10 @@
       @calcScreenOffsets()

       # Correct for window offsets.
-      frame.avg.x -= Eye.innerScreenX
-      frame.avg.y -= Eye.innerScreenY
+      frame.avg.x -= @innerScreenX
+      frame.avg.y -= @innerScreenY

       @indicator.move frame.avg.x, frame.avg.y

       @handleGaze()
       @handleBlinks(frame)
-
-  calibrate: ->
-    maxPointCount = 16
-    pointCount = 0
-
-    @connection.send 'calibration:start', maxPointCount
-
-    indicator = @indicator
-    transition = 'all 0.5s'
-    transform = 'translate3d(-5px, -5px, 0)'
-
-    @calcScreenOffsets()
-
-    @indicator.hide()
-
-    points = _.shuffle [
-      [0.1, 0.1], [0.4, 0.1], [0.6, 0.1], [0.9, 0.1]
-      [0.1, 0.4], [0.4, 0.4], [0.6, 0.4], [0.9, 0.4]
-      [0.1, 0.6], [0.4, 0.6], [0.6, 0.6], [0.9, 0.6]
-      [0.1, 0.9], [0.4, 0.9], [0.6, 0.9], [0.9, 0.9]
-    ]
-
-    curtain = utilities.makeElement 'div',
-      zIndex: 100000
-      position: 'fixed'
-      height: '100%'
-      width: '100%'
-      left: 0
-      top: 0
-      backgroundColor: 'transparent'
-      transition:       transition
-      MozTransition:    transition
-      WebkitTransition: transition
-      msTransition:     transition
-
-    point = utilities.makeElement 'div',
-      zIndex: 100001
-      position: 'fixed'
-      height: '10px'
-      width: '10px'
-      borderRadius: '999px'
-      backgroundColor: 'white'
-      left: 0
-      top: 0
-      transform:        transform
-      MozTransform:     transform
-      WebkitTransform:  transform
-      msTransform:      transform
-
-    document.body.appendChild curtain
-    document.body.appendChild point
-
-    setTimeout ->
-      curtain.style.backgroundColor = 'rgba(0,0,0,0.8)'
-    , 100
-
-    nextPoint = ->
-      x = parseInt((window.innerWidth) * points[pointCount][0])
-      y = parseInt((window.innerHeight) * points[pointCount][1])
-
-      point.style.left = x + 'px'
-      point.style.top = y + 'px'
-      Eye.connection.send 'calibration:pointstart',
-        x: x + Eye.innerScreenX
-        y: y + Eye.innerScreenY
-
-      setTimeout ->
-        Eye.connection.send 'calibration:pointend'
-        pointCount++
-        if pointCount < maxPointCount
-          nextPoint()
-        else
-          curtain.style.backgroundColor = 'transparent'
-          setTimeout ->
-            indicator.show()
-            document.body.removeChild curtain
-            document.body.removeChild point
-          , 500
-      , 2000
-
-    nextPoint()


Handle errors in initialize() as well.

Handle errors in initialize() as well.

--- src/jvm.coffee
+++ src/jvm.coffee
@@ -41,29 +41,31 @@
     rs.print "\tat #{entry.cls.toExternalString()}.#{entry.method}(#{entry.file}:#{entry.line})\n"

 # main function that gets called from the frontend
-root.run_class = (rs, class_name, cmdline_args, cb) ->
+root.run_class = (rs, class_name, cmdline_args, done_cb) ->
   main_spec = class: class_name, sig: 'main([Ljava/lang/String;)V'
-  rs.initialize(class_name,cmdline_args)
-  run = ->
+  yielded = false
+  run = (fn) ->
     try
-      rs.method_lookup(main_spec).run(rs)
-      cb?()
+      fn()
+      true
     catch e
       if e instanceof util.JavaException
         console.error "\nUncaught Java Exception"
         show_state(rs)
         show_stacktrace(rs,e)
-        cb?()
       else if e instanceof util.HaltException
         console.error "\nExited with code #{e.exit_code}" unless e.exit_code is 0
-        cb?()
       else if e instanceof util.YieldException
+        yielded = true
         e.condition ->
           rs.resuming_stack = 0  # <-- index into the meta_stack of the frame we're resuming
           run()
       else
         console.error "\nInternal JVM Error!"
         show_state(rs)
-        cb?()
-        throw e  # so we get the JS traceback? TODO: figure out why this doesn't print the trace
-  run()
+        console.log e.stack
+      false
+  # we're assuming that initialize() never yields
+  (run -> rs.initialize(class_name,cmdline_args)) and
+  (run -> rs.method_lookup(main_spec).run(rs))
+  done_cb?() unless yielded


Hotfix: no bounds fitting for selected services unit click.

--- src/map.coffee
+++ src/map.coffee
@@ -79,7 +79,7 @@
                     return
                 unit = units.first()
                 @highlight_selected_unit unit
-                @refit_bounds(true)
+                @refit_bounds()

             @listenTo p13n, 'position', @handle_position
             @listenTo @selected_position, 'change:value', =>


add missing bind

add missing bind

--- src/xml.coffee
+++ src/xml.coffee
@@ -298,6 +298,7 @@
         @show = @show.bind(this)
         @hide = @hide.bind(this)
         @remove = @remove.bind(this)
+        @replace = @replace.bind(this)
         # values
         @builder = this
         @checkers = {} # all the middlewares that have to approve a new tag


Add required or not null properties for new workflow creation (#6217)

* Add project's primary_language to new workflow

* Add not null first_task and tasks to new workflow

--- app/pages/lab/workflow-create-form.cjsx
+++ app/pages/lab/workflow-create-form.cjsx
@@ -27,6 +27,9 @@
     newWorkflow =
       id: workflowToClone?.id
       display_name: @refs.newDisplayName.value
+      first_task: ''
+      primary_language: @props.project.primary_language
+      tasks: {}

     awaitSubmission = @props.onSubmit(@props.project, newWorkflow)


replace gcm title with user defined title

--- config/notify.coffee
+++ config/notify.coffee
@@ -14,7 +14,7 @@
     gcm: (device, data) ->
       msg = new gcm.Message()
       msg.addNotification
-        title: 'Instant Messaging'
+        title: data.title
         body: data.message || ' '
         sound: 'default'
       gcmProvider.sendAsync msg, registrationTokens: [device]


Send network packets as IP objects to work around noflo/noflo#491

--- components/ListenNetwork.coffee
+++ components/ListenNetwork.coffee
@@ -40,7 +40,7 @@
     if command is 'icon'
       c.outPorts.icon.send payload
       return
-    c.outPorts.packet.send
+    c.outPorts.packet.sendIP new noflo.IP 'data',
       edge: payload.id
       type: command
       group: if payload.group? then payload.group else ''


Update dematerialize.coffee comment

Update dematerialize.coffee comment

--- components/dematerialize.coffee
+++ components/dematerialize.coffee
@@ -1,7 +1,7 @@
 # *************************************
 #
 #   Dematerialize
-#   -> Hides and element and keeps it hidden
+#   -> Hides an element and keeps it hidden
 #
 # *************************************


Add inlist support to remade rdfa

Add inlist support to remade rdfa

--- js/rdfa/parser.coffee
+++ js/rdfa/parser.coffee
@@ -65,19 +65,33 @@
         for type in types
           addPropToObj(typed, "@type", type)

+      # TODO:
+      #if hanging.*
+      #  if no s or o but predicates
+      #    hangingSubject = hanging.subject
+      #  else if s or o
+      #    attach to state.current: hangingSubject or if s then current else nextObj
+      #    if hanging.subject used current = hangingSubject
+      #    nextHanging = {...}
+
+      if desc.inlist
+        addToObj = addToPropListToObj
+      else
+        addToObj = addPropToObj
+
       if o
         for link in desc.getLinks()
-          addPropToObj(current, link, {"@id": o})
+          addToObj(current, link, {"@id": o})
         revs = desc.getRevLinks()
         if revs.length
           subjRef = {"@id": s or current["@id"]}
           for rev in revs
-            addPropToObj(nextObj or getOrCreate(res, o), rev, subjRef)
+            addToObj(nextObj or getOrCreate(res, o), rev, subjRef)

       value = desc.getLiteral()
       if value
         for prop in desc.getValueProperties()
-          addPropToObj(current, prop, value)
+          addToObj(current, prop, value)

       subState = desc.state
       #nextListMap
@@ -111,6 +125,23 @@
     values = obj[prop]
     unless values
       values = obj[prop] = []
+    values.push(value)
+
+  addToPropListToObj = (obj, prop, value) ->
+    values = obj[prop]
+    # TODO: list in Array or direct object (latter prevents sets of mixed refs+lists)
+    if values instanceof Array
+      if values[0]['@list']
+        values = values[0]['@list']
+      else
+        l = []
+        values.unshift({'@list': l})
+        values = l
+    else if values
+      values = values['@list']
+    else
+      values = []
+      obj[prop] = {"@list": values}
     values.push(value)

@@ -199,8 +230,7 @@
         # TODO: .. and not content attr and getReference()
       if @properties and not @propertiesAsLinks
         @literal = data.getLiteral()
-      if data.isInlist()
-        @inlist = true
+      @inlist = data.isInlist()

     getErrors: ->
       @data.errors
@@ -240,10 +270,6 @@
         return @properties
       else
         return []
-
-    getListLinks: ->
-
-    getListValueProperties: ->

     getRevLinks: ->
       if @revs then @revs else []


Add rudimentary hanging support to remade rdfa

--- js/rdfa/parser.coffee
+++ js/rdfa/parser.coffee
@@ -65,28 +65,44 @@
         for type in types
           addPropToObj(typed, "@type", type)

-      # TODO:
-      #if hanging.*
-      #  if no s or o but predicates
-      #    hangingSubject = hanging.subject
-      #  else if s or o
-      #    attach to state.current: hangingSubject or if s then current else nextObj
-      #    if hanging.subject used current = hangingSubject
-      #    nextHanging = {...}
-
-      if desc.inlist
+      rels = desc.getLinks()
+      revs = desc.getRevLinks()
+      inlist = desc.inlist
+
+      hanging = state.hanging
+      if hanging.present
+        # TODO: this just supports connecting resource; see commented below
+        if o
+          s = null
+          current = state.current
+          rels = hanging.rels
+          revs = hanging.revs
+          inlist = hanging.inlist
+          hanging = {present: false}
+        #if not (s or o) and (desc.rels or desc.revs or desc.properties)
+        #  hangingSubject = hanging.subject
+        #  nextHanging
+        #else if s or o
+        #  attach to state.current: hangingSubject or if s then current else nextObj
+        #  if hanging.subject used current = hangingSubject
+        #  nextHanging
+
+      if inlist
         addToObj = addToPropListToObj
       else
         addToObj = addPropToObj

       if o
-        for link in desc.getLinks()
+        for link in rels
           addToObj(current, link, {"@id": o})
-        revs = desc.getRevLinks()
         if revs.length
           subjRef = {"@id": s or current["@id"]}
           for rev in revs
             addToObj(nextObj or getOrCreate(res, o), rev, subjRef)
+      else
+        present = !!(rels.length or revs.length)
+        hanging = {present: present, rels: rels, revs: revs, inlist: inlist}
+        console.log

       value = desc.getLiteral()
       if value
@@ -94,8 +110,7 @@
           addToObj(current, prop, value)

       subState = desc.state
-      #nextListMap
-      #nextHangSubject, nextHangRel, nextHangRev
+      subState.hanging = hanging
       subState.current = nextObj or current
       return subState

@@ -150,7 +165,7 @@
       @mapper = new Mapper(null, contexts[@profile])
       @lang = null
       @lists = {}
-      @hanging = {rels: [], revs: [], lists: []}
+      @hanging = {present: false, rels: null, revs: null, lists: null}
       @result = null
       @current = null
       @resolveURI = resolveURI


removing width/height which are undefined anyways because @dpi_ratio is not set

--- bokehjs/src/coffee/common/canvas.coffee
+++ bokehjs/src/coffee/common/canvas.coffee
@@ -58,9 +58,6 @@
       width = @mget('width')
       height = @mget('height')

-      @canvas.width = width * @dpi_ratio
-      @canvas.height = height * @dpi_ratio
-
       @$el.attr('style', "z-index: 50; width:#{width}px; height:#{height}px")
       @canvas.attr('style', "width:#{width}px;height:#{height}px")
       @canvas.attr('width', width*ratio).attr('height', height*ratio)


activity: remove debug statement

activity: remove debug statement

--- client/activity/lib/components/chatinputwidget/test/view.coffee
+++ client/activity/lib/components/chatinputwidget/test/view.coffee
@@ -90,7 +90,7 @@
       result = TestUtils.renderIntoDocument(
         <ChatInputWidget data={data} />
       )
-      console.log 'result ', result
+
       component = TestUtils.findRenderedComponentWithType result, EmojiDropbox
       expect(component).toExist()


small refactorings

small refactorings

--- client/landing/app/MainApp/maincontroller/maincontroller.coffee
+++ client/landing/app/MainApp/maincontroller/maincontroller.coffee
@@ -119,7 +119,7 @@
   unmarkUserAsTroll:(data)->

     kallback = (acc)=>
-      acc.unflagAccount "exempt", (err, res)->
+      acc.markUserAsExempt false, (err, res)->
         if err then warn err
         else
           new KDNotificationView
@@ -153,7 +153,7 @@
             diameter : 16
           callback   : =>
             kallback = (acc)=>
-              acc.flagAccount "exempt", (err, res)->
+              acc.markUserAsExempt false, (err, res)->
                 if err then warn err
                 else
                   modal.destroy()


Implement Dependency using array not object

--- tracker.coffee
+++ tracker.coffee
@@ -257,7 +257,7 @@
             else
                 creator

-        @_dependentsById = {}
+        @_dependents = []

     depend: (computation) ->
@@ -265,21 +265,21 @@
             return false if not Tracker.active
             computation = Tracker.currentComputation

-        id = computation._id
-        if id of @_dependentsById
+        if computation in @_dependents
             false
         else
-            @_dependentsById[id] = computation
+            @_dependents.push computation
             computation.onInvalidate =>
-                delete @_dependentsById[id]
+                i = @_dependents.indexOf computation
+                @_dependents.splice i, 1
             true

     changed: ->
-        for id, computation of @_dependentsById
+        for computation in @_dependents
             unless computation is Tracker.currentComputation is @creator
-                @_dependentsById[id].invalidate()
+                computation.invalidate()

     hasDependents: ->
-        not _.isEmpty @_dependentsById
+        @_dependents.length > 0


Change scan split accelerators: o => new post

"o" is now new post, and first post shows (1).

--- scanblog/static/js/moderation/scans.coffee
+++ scanblog/static/js/moderation/scans.coffee
@@ -126,7 +126,6 @@
     # NOTE: These definitions are duplicated with event.keyCode below.  Here,
     # they're used only to pick which letter to underline in the view.
     typeAccelerators:
-        "post": "o"
         "profile": "f"
         "request": "r"
         "license": "l"
@@ -172,8 +171,7 @@
             #when 220 then @addPhotoChoice(event) # back slash
             #when 13        then @save(event) # enter
             when 73, 192 then @ignoreView._toggleChoice(event) # i, backtick
-            when 79 # o -> first pOst
-                _.find(@choiceViews, (c) -> c.choice.get("type") == "post")?._toggleChoice(event)
+            when 79 then @addPostChoice(event) # o -> add pOst
             when 70 # f -> first proFile
                 _.find(@choiceViews, (c) -> c.choice.get("type") == "profile")?._toggleChoice(event)
             when 76 # l -> license
@@ -255,7 +253,10 @@
                     break
             title = "#{title} #{@typeCount[type]} (#{pos + 1})"
         else
-            title = title.replace(new RegExp("(#{@typeAccelerators[type]})"), "$1")
+            if type == "post"
+              title = title + " (1)"
+            else
+              title = title.replace(new RegExp("(#{@typeAccelerators[type]})"), "$1")
             @choices.push doc
         doc.set choiceTitle: title

@@ -411,7 +412,7 @@
             })
         $(".page-image img").load =>
             @setPageScale parseFloat $.cookie("scanpagesize") or 1
-        unless @$(".choose-code input").val()
+        unless @$(".choose-code input").val() or @split.get("scan").author
             @$(".choose-code input").focus()
         this


watch out for errors from JSDOM

watch out for errors from JSDOM

--- unshrtn.coffee
+++ unshrtn.coffee
@@ -102,7 +102,11 @@

 canonical = (url, html) ->
-  dom = new jsdom.JSDOM(html, url: url, virtualConsole: virtualConsole)
+  try
+    dom = new jsdom.JSDOM(html, url: url, virtualConsole: virtualConsole)
+  catch e
+    console.log "jsdom error " + e
+    return url
   link = dom.window.document.querySelector('head link[rel=canonical]')
   if link and link.attributes and link.attributes.href
     url = link.attributes.href.value


When closing a layer, the log message will say "dismiss" or "accept" instead of "close"

--- lib/assets/javascripts/unpoly/classes/change/close_layer.coffee
+++ lib/assets/javascripts/unpoly/classes/change/close_layer.coffee
@@ -8,20 +8,7 @@
   constructor: (options) ->
     super(options)

-    verb = options.verb
-    verbGerund = "#{verb}ing"
-    verbPast = "#{verb}ed"
-    @valueAttr = "up-#{verb}"
-
-    @closeEventType = "up:layer:#{verb}"
-    @closeCallbackName = "on#{u.upperCaseFirst(verb)}"
-
-    @closingEventType = "up:layer:#{verbGerund}"
-    @closingCallbackName = "on#{u.upperCaseFirst(verbGerund)}"
-
-    @closedEventType = "up:layer:#{verbPast}"
-    @closedCallbackName = "on#{u.upperCaseFirst(verbPast)}"
-
+    @verb = options.verb
     @layer = up.layer.get(options)
     @origin = options.origin
     @value = options.value
@@ -29,7 +16,7 @@

   execute: ->
     if @origin && u.isUndefined(value)
-      value = e.jsonAttr(@origin, @valueAttr)
+      value = e.jsonAttr(@origin, "up-#{@verb}")

     unless @layer.isOpen()
       return Promise.resolve()
@@ -74,19 +61,25 @@

   emitCloseEvent: ->
     return @layer.emit(
-      @buildEvent(@closeEventType),
-      callback: @layer.callback(@closeCallbackName),
-      log: "Will close #{@layer}"
+      @buildEvent("up:layer:#{@verb}"),
+      callback: @layer.callback("on#{u.upperCaseFirst(@verb)}"),
+      log: "Will #{@verb} #{@layer}"
     )

   emitClosingEvent: ->
+    verbGerund = "#{@verb}ing"
+    verbGerundUpperCaseFirst = u.upperCaseFirst(verbGerund)
+
     return @layer.emit(
-      @buildEvent(@closingEventType),
-      callback: @layer.callback(@closingCallbackName),
-      log: "Closing #{@layer}"
+      @buildEvent("up:layer:#{verbGerund}"),
+      callback: @layer.callback("on#{verbGerundUpperCaseFirst}"),
+      log: "#{verbGerundUpperCaseFirst} #{@layer}"
     )

   emitClosedEvent: (formerParent) ->
+    verbPast = "#{@verb}ed"
+    verbPastUpperCaseFirst = u.upperCaseFirst(verbPast)
+
     # layer.emit({ ensureBubbles: true }) will automatically emit a second event on document
     # because the layer is detached. We do not want to emit it on the parent layer where users
     # might confuse it with an event for the parent layer itself. Since @layer.element
@@ -94,13 +87,13 @@
     # event listeners can receive it. So we explicitely emit the event a second time
     # on the document.
     return @layer.emit(
-      @buildEvent(@closedEventType),
+      @buildEvent("up:layer:#{verbPast}"),
       # Set up.layer.current to the parent of the closed layer, which is now likely
       # to be the front layer.
       currentLayer: formerParent,
-      callback: @layer.callback(@closedCallbackName),
+      callback: @layer.callback("on#{verbPastUpperCaseFirst}"),
       ensureBubbles: true,
-      log: "Closed #{@layer}"
+      log: "#{verbPastUpperCaseFirst} #{@layer}"
     )

   buildEvent: (name) ->


remove dependency on inflection.js, use our own underscore method

--- lib/generators/nas_extjs/templates/public/app/model/Base.coffee
+++ lib/generators/nas_extjs/templates/public/app/model/Base.coffee
@@ -73,7 +73,7 @@

     prefixedAttrs: (names...)->
         [ names, opts ] = Util.extractOptions( names )
-        prefix = ( opts.prefix || Util.baseClassName( this ).underscore() ) + '_'
+        prefix = opts.prefix || ( Util.underscore( Util.baseClassName( this ) ) + '_' )
         ret = {}
         for name in names
             ret[ prefix+name ] = this.get( name )


cloud 9 host ip & port

cloud 9 host ip & port

--- web/app.coffee
+++ web/app.coffee
@@ -130,7 +130,7 @@
   util.puts "Uncaught Exception: #{err.toString()}"

 # Start the server.
-port = parseInt(process.env.PORT || process.env.C9_PORT || 8001)
-app.listen port
-console.log "Astrolin has started on http://localhost:%s", port
-
+port = parseInt(process.env.PORT || 8001)
+host = process.env.IP || '127.0.0.1'
+app.listen port, host
+console.log "Astrolin has started on http://#{host}:#{port}"


exponential backoff for lock up to maximum time

--- app/coffee/LockManager.coffee
+++ app/coffee/LockManager.coffee
@@ -14,6 +14,7 @@

 module.exports = LockManager =
 	LOCK_TEST_INTERVAL: 50 # 50ms between each test of the lock
+	MAX_TEST_INTERVAL: 1000 # back off to 1s between each test of the lock
 	MAX_LOCK_WAIT_TIME: 10000 # 10s maximum time to spend trying to get the lock
 	LOCK_TTL: 30 # seconds. Time until lock auto expires in redis.

@@ -41,6 +42,7 @@

 	getLock: (doc_id, callback = (error, lockValue) ->) ->
 		startTime = Date.now()
+		testInterval = LockManager.LOCK_TEST_INTERVAL
 		do attempt = () ->
 			if Date.now() - startTime > LockManager.MAX_LOCK_WAIT_TIME
 				e = new Error("Timeout")
@@ -52,7 +54,9 @@
 				if gotLock
 					callback(null, lockValue)
 				else
-					setTimeout attempt, LockManager.LOCK_TEST_INTERVAL
+					setTimeout attempt, testInterval
+					# back off when the lock is taken to avoid overloading
+					testInterval = Math.max(testInterval * 2, LockManager.MAX_TEST_INTERVAL)

 	checkLock: (doc_id, callback = (err, isFree)->)->
 		key = keys.blockingKey(doc_id:doc_id)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/number_extensions.coffee
+++ test/number_extensions.coffee
@@ -18,7 +18,8 @@

 test "#clamp", ->
   equals 5.clamp(0, 3), 3
-  equals 5.clamp()
+  equals 5.clamp(0, 0), 0
+  equals

 test "#floor", ->
   equals 4.9.floor(), 4, "(4.9).floor() equals 4"


fetch initial data only on init

fetch initial data only on init

--- SingularityUI/app/controllers/Tail.coffee
+++ SingularityUI/app/controllers/Tail.coffee
@@ -16,10 +16,10 @@
             model: @models.taskHistory

         app.showView @view
+        @collections.logLines.fetchInitialData()
         @refresh()

     refresh: ->
-        @collections.logLines.fetchInitialData()
         @models.taskHistory.fetch()


changed water color to navy

changed water color to navy

--- test/rainflow/src/drop.coffee
+++ test/rainflow/src/drop.coffee
@@ -3,9 +3,9 @@
     super
     @dt = 1
     @size = .7
-    @fill('white')
+    @fill('navy')
     @stroke('none')
-    @image.attr('opacity', '0.8').attr('stroke-width', 0.25)
+    @image.attr('opacity', '0.6').attr('stroke-width', 0.25)
     @lifetime = Utils.timestamp()
     @max_lifetime = 3e4
     @vscale = .7


Calibrate wait timeouts

Calibrate wait timeouts

--- test/src/promises-test.coffee
+++ test/src/promises-test.coffee
@@ -8,8 +8,9 @@
 browser = undefined
 asserters = undefined

-delay = 4000
+delay = 20000
 errorDelay = 1000
+pollFreq = 100

 baseUrl = 'http://localhost:9001'
 pageTitle = 'Pääkaupunkiseudun palvelukartta'
@@ -36,14 +37,14 @@

     it 'Should contain button "Selaa palveluita"', (done) ->
       browser
-        .waitForElementByCss(browseButtonSelector, delay)
+        .waitForElementByCss(browseButtonSelector, delay, pollFreq)
         .click().should.be.fulfilled
         .should.notify(done)

     it 'Should contain list item "Terveys"', (done) ->
       browser
         .waitForElementByCss(serviceTreeItemSelector,
-          asserters.textInclude('Terveys'), delay)
+          asserters.textInclude('Terveys'), delay, pollFreq)
         .should.be.fulfilled
         .should.notify(done)

@@ -51,7 +52,7 @@
     it 'Should not contain list item "Sairaus"', (done) ->
       browser
         .waitForElementByCss(serviceTreeItemSelector,
-          asserters.textInclude('Sairaus'), errorDelay)
+          asserters.textInclude('Sairaus'), errorDelay, pollFreq)
         .should.be.rejected
         .should.notify(done)

@@ -66,10 +67,10 @@
     it 'Should find item "Kallion kirjasto"', (done) ->
       searchText = 'kallion kirjasto'
       browser
-        .waitForElementByCss(searchFieldPath, delay)
+        .waitForElementByCss(searchFieldPath, delay, pollFreq)
         .click()
         .type(searchText)
-        .waitForElementByCss(typeaheadResultPath, asserters.textInclude("Kallion kirjasto"), delay)
+        .waitForElementByCss(typeaheadResultPath, asserters.textInclude("Kallion kirjasto"), delay, pollFreq)
         .should.be.fulfilled
         .should.notify(done)

@@ -83,7 +84,7 @@
     it 'Should manage to input search text', (done) ->
       searchText = 'kallion kirjasto'
       browser
-        .waitForElementByCss(searchFieldPath, delay)
+        .waitForElementByCss(searchFieldPath, delay, pollFreq)
         .click()
         .type(searchText)
         .should.be.fulfilled
@@ -91,18 +92,18 @@

     it 'Should manage to click search button', (done) ->
       browser
-        .waitForElementByCss(searchButton, delay)
+        .waitForElementByCss(searchButton, delay, pollFreq)
         .click().should.be.fulfilled
         .should.notify(done)

     it 'Should find item "Kallion kirjasto"', (done) ->
       browser
-        .waitForElementByCss(searchResultPath, asserters.textInclude("Kallion kirjasto"), delay)
+        .waitForElementByCss(searchResultPath, asserters.textInclude("Kallion kirjasto"), delay, pollFreq)
         .should.be.fulfilled
         .should.notify(done)

     it 'Should not find item "Kallio2n kirjasto"', (done) ->
       browser
-        .waitForElementByCss(searchResultPath, asserters.textInclude("Kallio2n kirjasto"), errorDelay)
+        .waitForElementByCss(searchResultPath, asserters.textInclude("Kallio2n kirjasto"), errorDelay, pollFreq)
         .should.be.rejected
         .should.notify(done)


CredentialsController: refactoring of _loadCredentials() method

--- client/app/lib/providers/resourcestatemodal/controllers/credentialscontroller.coffee
+++ client/app/lib/providers/resourcestatemodal/controllers/credentialscontroller.coffee
@@ -237,15 +237,9 @@

   helpers =

-    _loadCredentials: (selector, selectedCredentials, callback) ->
-
-      options  = { '_id' : -1 }
-      remote.api.JCredential.some selector, options, (err, items) ->
-        return callback err  if err
-
-        { provider } = selector
-        defaultItem  = selectedCredentials?[provider]?.first
-        callback null, _.extend { items, defaultItem }, selector
+    _loadCredentials: (selector, callback) ->
+
+      remote.api.JCredential.some selector, { '_id' : -1 }, callback

     loadCredentials: (stack, callback) ->
@@ -256,10 +250,12 @@
         break  if provider in ['aws', 'vagrant']
       provider ?= (Object.keys stack.credentials ? { aws : yes }).first

-      helpers._loadCredentials { provider }, stack.credentials, (err, result) ->
+      helpers._loadCredentials { provider }, (err, items) ->
         return callback err  if err

-        { items, defaultItem } = result
+        defaultItem = stack.credentials?[provider]?.first
+        result = { items, defaultItem, provider }
+
         return callback null, result  unless defaultItem

         isAvailable = (
@@ -286,10 +282,9 @@
       requiredFields = requiredData[provider]
       fields = requiredFields.map (field) -> field.name ? field

-      helpers._loadCredentials { provider, fields }, stack.credentials, (err, data) ->
+      helpers._loadCredentials { provider, fields }, (err, items) ->
         return callback err  if err
-        data.fields = requiredFields
-        callback null, data
+        callback null, { items, provider, fields : requiredFields }

     getKDCmd: (callback) ->


Support configuring multiple behaviours globally

Closes #10

--- lib/behaviours.coffee
+++ lib/behaviours.coffee
@@ -123,19 +123,31 @@
   config: ->
     @configure.apply @, arguments

-  configure: (name, options) ->
-    check name, String
-    check options, Object
+  configure: (nameOrObject, options) ->
+    check nameOrObject, Object, String
+    check options, Match.Optional Object

-    name = name.toLowerCase()
+    if Match.test nameOrObject, String
+      check options, Object
+      tmp = {}
+      tmp[nameOrObject] = options
+      nameOrObject = tmp

-    behaviourObject = definedBehaviours[name]
+    if Match.test nameOrObject, Object
+      for name, behaviourOptions of nameOrObject
+        name = name.toLowerCase()

-    if behaviourObject
-      behaviourObject.options = options
+        behaviourObject = definedBehaviours[name]

-    else
-      console.error "Configure failed, behaviour \"#{name}\" not found"
+        if behaviourObject
+          behaviourObject.options = behaviourOptions
+
+        else
+          console.error "Configure failed, behaviour \"#{name}\" not found"
+
+      return
+
+    console.log "Configure failed, unknown reason"

   define: (name, behaviour, options) ->
     check name, String


fix(specs): Spec fixes for 37e1f6bb

fix(specs): Spec fixes for 37e1f6bb

--- internal_packages/composer-spellcheck/spec/spellcheck-composer-extension-spec.coffee
+++ internal_packages/composer-spellcheck/spec/spellcheck-composer-extension-spec.coffee
@@ -12,7 +12,7 @@
     spyOn(SpellcheckComposerExtension, 'isMisspelled').andCallFake (word) ->
       spellings[word]

-  describe "walkTree", ->
+  describe "update", ->
     it "correctly walks a DOM tree and surrounds mispelled words", ->
       dom = document.createElement('div')
       dom.innerHTML = initialHTML
@@ -21,7 +21,7 @@
         rootNode: dom
         whilePreservingSelection: (cb) -> cb()

-      SpellcheckComposerExtension.walkTree(editor)
+      SpellcheckComposerExtension.update(editor)
       expect(dom.innerHTML).toEqual(expectedHTML)

   describe "finalizeSessionBeforeSending", ->


caring for rc user

caring for rc user

--- packages/rocketchat-ui-flextab/flex-tab/tabs/membersList.coffee
+++ packages/rocketchat-ui-flextab/flex-tab/tabs/membersList.coffee
@@ -34,9 +34,13 @@
 					utcOffset = "+#{utcOffset}"
 				utcOffset = "(UTC #{utcOffset})"
 			user = Meteor.users.findOne({username:username})
+			if (user)
+				realname = user.name
+			else
+				realname = username

 			return {
-				username: user.name
+				username: realname
 				status: onlineUsers[username]?.status
 				muted: username in roomMuted
 				utcOffset: utcOffset


instructions book: fix ace editor's advanced settings menu presentation

--- client/app/MainApp/book/bookview.coffee
+++ client/app/MainApp/book/bookview.coffee
@@ -603,18 +603,21 @@
     @pointer.once 'transitionend', =>
       @clickAnimation()
       @mainView.appSettingsMenuButton.$().click()
-      {advancedSettings} = @mainView.appSettingsMenuButton.contextMenu.treeController.nodes
-
-      offsetTo = advancedSettings?.$().offset()
-      # navigate settings icon
-      @utils.wait 1000, =>
+
+      @utils.wait 200, =>
+        {advancedSettings} = @mainView.appSettingsMenuButton.contextMenu.treeController.nodes
+
+        offsetTo = advancedSettings?.$().offset()
+        # navigate settings icon
         @pointer.once 'transitionend', =>
-          advancedSettings.setClass "selected"
-          advancedSettings.$().click()
-          @clickAnimation()
           @utils.wait 1000, =>
-            @unsetClass 'aside'
-            @destroyPointer()
+            advancedSettings.setClass "selected"
+            advancedSettings.$().click()
+            @clickAnimation()
+            @utils.wait 1000, =>
+              @unsetClass 'aside'
+              @destroyPointer()
+
         @pointer.$().offset offsetTo

     # find ace settings menu icon


klient: terminal tab renaming

klient: terminal tab renaming

--- client/app/lib/kite/kites/klient.coffee
+++ client/app/lib/kite/kites/klient.coffee
@@ -29,6 +29,7 @@
     webtermKillSessions: 'webterm.killSessions'
     webtermGetSessions : 'webterm.getSessions'
     webtermPing        : 'webterm.ping'
+    webtermRename      : 'webterm.rename'

     klientShare        : 'klient.share'
     klientUnshare      : 'klient.unshare'


removed wrong import #65

removed wrong import #65

--- app/assets/javascripts/oxalis/model/skeletontracing/user_annotation_collection.coffee
+++ app/assets/javascripts/oxalis/model/skeletontracing/user_annotation_collection.coffee
@@ -1,7 +1,6 @@
 ### define
 underscore : _
 backbone : Backbone
-./user_annotation_model : UserAnnotationModel
 admin/models/pagination_collection : PaginationCollection
 ###


Bug fix: jump to First and Last buttons left the heap visualization looking like Python not Ruby.

--- views/coffee/application.coffee
+++ views/coffee/application.coffee
@@ -136,11 +136,10 @@
       setupVisualizer i
       i++

-    $('#jmpStepFwd').click (event) ->
-      changePythonToRuby()
-
-    $('#jmpStepBack').click (event) ->
-      changePythonToRuby()
+    $('#jmpFirstInstr').click (event) -> changePythonToRuby()
+    $('#jmpStepBack').click (event)   -> changePythonToRuby()
+    $('#jmpStepFwd').click (event)    -> changePythonToRuby()
+    $('#jmpLastInstr').click (event)  -> changePythonToRuby()

   for word of word_to_method_indexes
     for i of word_to_method_indexes[word]


Catch open events when local file doesn't exist

--- virtual-file-system/main.coffee
+++ virtual-file-system/main.coffee
@@ -23,17 +23,24 @@
     @shell = new ShellAdapter(this)

     @websocket = new WebSocket("#{serverURI}?token=#{token}")
+    @addOpener()
     @observeSave()
     @handleEvents()

+  addOpener: ->
+    atom.workspace.addOpener (uri) =>
+      if @hasPath(uri) and not fs.existsSync(uri)
+        @open(uri)
+
   observeSave: ->
     atom.workspace.observeTextEditors (editor) =>
-      editor.getBuffer()?.onWillSave ({path}) =>
+      editor.onDidSave ({path}) =>
         @save(path)

   handleEvents: ->
     messageCallbacks =
       sync: @onRecievedSync
+      open: @onRecievedOpen
       build: @onRecievedBuild
       fetch: @onRecievedFetch
       change: @onRecievedChange
@@ -117,6 +124,20 @@
       decoded = new Buffer(content, 'base64').toString('utf8')
       fs.writeFile(localPath, decoded)

+  onRecievedOpen: ({path, attributes, content}) =>
+    localPath = @convert.remoteToLocal(path)
+    dirname = _path.dirname(localPath)
+    return unless localPath? and dirname?
+    return if fs.existsSync(localPath)
+
+    fs.makeTreeSync(dirname) unless fs.existsSync(dirname)
+    decoded = new Buffer(content, 'base64').toString('utf8')
+    fs.writeFileSync(localPath, decoded)
+
+    buffer = atom.project.findBufferForPath(localPath)
+    buffer.updateCachedDiskContentsSync()
+    buffer.reload()
+
   onRecievedRescue: ({message, backtrace}) ->
     console.log 'RESCUE:', message, backtrace

@@ -188,6 +209,9 @@

   trash: (path) ->
     @send {command: 'trash', path}
+
+  open: (path) ->
+    @send {command: 'open', path}

   save: (path) ->
     atom.project.bufferForPath(path).then (textBuffer) =>


roll back

roll back

--- server/lib/server/services-presence.coffee
+++ server/lib/server/services-presence.coffee
@@ -41,8 +41,11 @@
       else KONFIG.broker.webHostname
   else
     (koding.getClient().collection 'jKontrolWorkers')
-      .findOne { serviceUniqueName, serviceGenericName, status: 0 },
-        { hostname: 1 }, (err, worker) ->
+      .findOne {
+        serviceUniqueName
+        hostname  : ///^#{ serviceGenericName }///
+        status    : 0
+      }, { hostname: 1 }, (err, worker) ->
           return callback err  if err?
           callback null, worker?.hostname ? null


IDEView: plus menu items, add experimental child menu

--- client/ide/views/tabview/ideview.coffee
+++ client/ide/views/tabview/ideview.coffee
@@ -227,6 +227,7 @@
     {appManager} = KD.singletons

     machine = appManager.getFrontApp().mountedMachine
+
     terminalSessions =
       "New Session"  :
         callback     : => @createTerminal machine
@@ -240,8 +241,14 @@
       delete terminalSessions["Existing Sessions"]

     sessions.forEach (session, i) =>
-      terminalSessions["Session #{i+1}"] =
-        callback : => @createTerminal machine, null, session
+      terminalSessions["Session #{session}"] =
+        children :
+          'Open'          :
+            callback      : => @createTerminal machine, null, session
+          'Terminate'     :
+            callback      : => alert session
+          'Rename'        :
+            callback      : => alert "rename", session

     items =
       'New File'          : callback : => @createEditor()


use _.result so modelForAccess can be a fn

--- client/lanes/react/mixins/Access.coffee
+++ client/lanes/react/mixins/Access.coffee
@@ -1,5 +1,5 @@
 calculateAccess = (comp, props) ->
-    model = comp[comp.modelForAccess || 'model']
+    model = _.result(comp, 'modelForAccess') || comp.model

     accessRight = if props.readonly or comp.context?.readonly
         'r'


add link to examples in the data digging repo

--- app/pages/lab/data-dumps.cjsx
+++ app/pages/lab/data-dumps.cjsx
@@ -33,7 +33,17 @@
   render: ->

Project data exports

-
Please note that the Zooniverse will process at most 1 of each export within a 24 hour period and some exports may take a long time to process. We will email you when they are ready.

+

+        Please note that the Zooniverse will process at most 1 of each
+        export within a 24 hour period and some exports may take a
+        long time to process. We will email you when they are ready.
+

+

+        For examples of how to work with the data exports, see our&nbsp
+
+          Data Digging code repository
+        .
+

           Project Data


Ghetto error handling

Ghetto error handling

--- SingularityUI/app/application.coffee
+++ SingularityUI/app/application.coffee
@@ -48,6 +48,15 @@

         Object.freeze? @

+    caughtError: ->
+        # Ghetto try-catch
+        #
+        # If there's some sort of AJAX error we can choose to handle this ourselves
+        # If we do handle it, we can call app.caughtError() in that bit of code
+        # and it'll prevent the default error message from being displayed,
+        # e.g. `model.fetch().error => app.caughtError()`
+        @caughtThisError = true
+
     setupGlobalErrorHandling: ->
         unloading = false
         $(window).on 'beforeunload', ->
@@ -58,7 +67,14 @@
         $(window).on 'blur', -> blurred = true
         $(window).on 'focus', -> blurred = false

+        # When an Ajax error occurs this is the default message that is displayed.
+        # You can add your own custom error handling using app.caughtError() above.
         $(document).on 'ajaxError', (e, jqxhr, settings) ->
+            # If we handled this already, ignore it
+            if app.caughtThisError
+                app.caughtThisError = false
+                return
+
             return if settings.suppressErrors
             return if jqxhr.statusText is 'abort'
             return if unloading


tag homepage has ability to add new proposals

--- @client/homepage.coffee
+++ @client/homepage.coffee
@@ -228,6 +228,23 @@
             show_category: true
             category_color: hsv2rgb(colors[cluster], .7, .8)

+        if (show_all.show_all || proposals.length <= 20) && (customization('list_show_new_button', "list/#{dummy_cluster}")  || current_user.is_admin)
+          LI
+            key: "newlist/#{dummy_cluster}"
+            style:
+              margin: 0
+              padding: 0
+              listStyle: 'none'
+              display: 'inline-block'
+              marginBottom: 20
+              marginTop: 6
+
+
+            NewProposal
+              cluster_name: dummy_cluster
+              local: @local.key
+              label_style: {}
+
       if !show_all.show_all && proposals.length > 20
         BUTTON
           style:
@@ -251,6 +268,9 @@

+
+
+
 window.filter_sort_options = ->
   proposals = fetch '/proposals'

@@ -302,8 +322,6 @@
       if !collapsed[cluster.key]?
         collapsed[cluster.key] = customization('list_is_archived', cluster.key)
         save collapsed
-
-

     DIV


Also support deselect_text from factlink_created and started states

--- core/app/assets/javascripts/tour.coffee
+++ core/app/assets/javascripts/tour.coffee
@@ -36,6 +36,8 @@
                                           'text_selected'],                      to: 'text_selected' }
         { name: 'select_text',     from: ['factlink_created',
                                           'factlink_created_and_text_selected'], to: 'factlink_created_and_text_selected' }
+        { name: 'deselect_text',   from:  'started',                             to: 'started' }
+        { name: 'deselect_text',   from:  'factlink_created',                    to: 'factlink_created' }
         { name: 'deselect_text',   from:  'text_selected',                       to: 'started' }
         { name: 'deselect_text',   from:  'factlink_created_and_text_selected',  to: 'factlink_created' }
         { name: 'open_modal',      from:  'text_selected',                       to: 'modal_opened' }


DOMAIN env variable

DOMAIN env variable

--- lib/app.coffee
+++ lib/app.coffee
@@ -20,7 +20,7 @@
 app = express()

 app.use (request, response, next) ->
-    response.header 'Access-Control-Allow-Origin', process.env.CORS_ORIGIN
+    response.header 'Access-Control-Allow-Origin', 'http://' + process.env.DOMAIN
     response.header 'Access-Control-Allow-Credentials', 'true'
     next()

@@ -32,7 +32,7 @@
     saveUninitialized: no
     name: 'themis-session-id'
     cookie:
-        domain: 'api.2015.volgactf-dev.org'
+        domain: 'api.' + process.env.DOMAIN
         path: '/'
         httpOnly: yes
         secure: false


Update hello.coffee

Update hello.coffee

boa noite

--- scripts/hello.coffee
+++ scripts/hello.coffee
@@ -40,6 +40,10 @@
     "ótimo (hehe) e você %?",
     "bem eu acho e você %?",
     "Melhor e você %?"
+]
+noite = [
+    "Boa noite, %",
+    "Boa noite pra você também, %"
 ]
 saudades= [
     "É bom vê-lo de novo, %!!"
@@ -109,4 +113,8 @@
     robot.hear /Lain, quantos anos você tem?/i, (msg) ->
         hello = msg.random idade
         msg.send hello.replace "%", msg.message.user.name
+
+     robot.hear /boa noite lain|boa noite, lain/i, (msg) ->
+        hello = msg.random noite
+        msg.send hello.replace "%", msg.message.user.name