if there is a validation error re enable the button

--- services/web/public/coffee/main/new-subscription.coffee
+++ services/web/public/coffee/main/new-subscription.coffee
@@ -81,6 +81,7 @@
 		completeSubscription = (err, recurly_token_id) ->
 			$scope.validation.errorFields = {}
 			if err?
+				$scope.processing = false
 				$scope.genericError = err.message
 				_.each err.fields, (field)-> $scope.validation.errorFields[field] = true
 			else


Klient: on webtermConnect if there is no existing sessions, re-fetch all again

--- client/Main/kite/kites/klient.coffee
+++ client/Main/kite/kites/klient.coffee
@@ -69,8 +69,11 @@

       .then (remote) =>

-        unless remote.session in @terminalSessions
-          @terminalSessions.push remote.session
+        if @terminalSessions.length is 0
+          @fetchTerminalSessions()
+        else
+          unless remote.session in @terminalSessions
+            @terminalSessions.push remote.session

         return remote


client: main: removed scope paranoia

client: main: removed scope paranoia

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -350,11 +350,11 @@

       return  unless id

-      run = do -> -> callback window._chatlio[method] options
+      run = -> callback window._chatlio[method] options

       if window._chatlio
-      then run()
-      else document.addEventListener 'chatlio.ready', -> run()
+      then do run
+      else document.addEventListener 'chatlio.ready', run


Look for icon path in icon and iconPath fields

--- client/app/models/application.coffee
+++ client/app/models/application.coffee
@@ -15,7 +15,7 @@
         if iconType
             return iconType is 'svg'
         else
-            icon = @get 'icon'
+            icon = @get 'icon' or @get 'iconPath'
             return icon?.indexOf '.svg'

     isRunning: -> @get('state') is 'installed'


Prevent bugs in plugins to break the application

--- client/app/utils/plugin_utils.coffee
+++ client/app/utils/plugin_utils.coffee
@@ -57,6 +57,8 @@
         #            else if change.type is 'delete'
         #                @deactivate change.name

+        window.plugins.helpers = helpers
+
         # Init every plugins
         Object.keys(window.plugins).forEach (pluginName) =>
             pluginConf = window.plugins[pluginName]
@@ -67,8 +69,6 @@
             else
                 if pluginConf.active
                     @activate pluginName
-
-        window.plugins.helpers = helpers

         if MutationObserver?

@@ -121,50 +121,56 @@
             , 200

     activate: (key) ->
-        plugin = window.plugins[key]
-        type   = plugin.type
-        plugin.active = true
-
-        # Add custom events listeners
-        if plugin.listeners?
-            for own event, listener of plugin.listeners
-                window.addEventListener event, listener.bind(plugin)
-
-        if plugin.onActivate
-            plugin.onActivate()
-
-        if type?
-            for own pluginName, pluginConf of window.plugins
-                if pluginName is key
-                    continue
-                if pluginConf.type is type and pluginConf.active
-                    @deactivate pluginName
-
-        event = new CustomEvent('plugin',
-            detail:
-                action: 'activate'
-                name: key
-        )
-        window.dispatchEvent event
+        try
+            plugin = window.plugins[key]
+            type   = plugin.type
+            plugin.active = true
+
+            # Add custom events listeners
+            if plugin.listeners?
+                for own event, listener of plugin.listeners
+                    window.addEventListener event, listener.bind(plugin)
+
+            if plugin.onActivate
+                plugin.onActivate()
+
+            if type?
+                for own pluginName, pluginConf of window.plugins
+                    if pluginName is key
+                        continue
+                    if pluginConf.type is type and pluginConf.active
+                        @deactivate pluginName
+
+            event = new CustomEvent('plugin',
+                detail:
+                    action: 'activate'
+                    name: key
+            )
+            window.dispatchEvent event
+        catch e
+            console.log "Unable to activate plugin #{key}: #{e}"

     deactivate: (key) ->
-        plugin = window.plugins[key]
-        plugin.active = false
-
-        # remove custom events listeners
-        if plugin.listeners?
-            for own event, listener of plugin.listeners
-                window.removeEventListener event, listener
-
-        if plugin.onDeactivate
-            plugin.onDeactivate()
-
-        event = new CustomEvent('plugin',
-            detail:
-                action: 'deactivate'
-                name: key
-        )
-        window.dispatchEvent event
+        try
+            plugin = window.plugins[key]
+            plugin.active = false
+
+            # remove custom events listeners
+            if plugin.listeners?
+                for own event, listener of plugin.listeners
+                    window.removeEventListener event, listener
+
+            if plugin.onDeactivate
+                plugin.onDeactivate()
+
+            event = new CustomEvent('plugin',
+                detail:
+                    action: 'deactivate'
+                    name: key
+            )
+            window.dispatchEvent event
+        catch e
+            console.log "Unable to deactivate plugin #{key}: #{e}"

     merge: (remote) ->
         for own pluginName, pluginConf of remote


make sure subclasses can access boxUrl

make sure subclasses can access boxUrl

--- client/code/view/view/content.coffee
+++ client/code/view/view/content.coffee
@@ -2,9 +2,10 @@
   id: 'fullscreen'

   initialize: ->
+    @boxUrl = @model.endpoint()
     @settings (settings) =>
       frag = encodeURIComponent JSON.stringify(settings)
-      @setupEasyXdm "#{@model.endpoint()}/#{@model.get 'box'}/#{settings.source.publishToken}/container.html##{frag}"
+      @setupEasyXdm "#{@boxUrl}/#{@model.get 'box'}/#{settings.source.publishToken}/container.html##{frag}"

   render: ->
     $('body').addClass('fullscreen')


add some properties for indicating state

--- client/lanes/models/JobStatus.coffee
+++ client/lanes/models/JobStatus.coffee
@@ -3,7 +3,7 @@
     props:
         id:          'string'
         job_name:    'string'
-        progress:    'integer'
+        progress:    'number'
         attempt:     'integer'
         state:       'string'
         recorded_at: 'date'
@@ -16,10 +16,17 @@

     derived:
         isSubmitted:
-            deps: ['state'], fn: -> !!@state?
+            deps: ['id'], fn: -> !@isNew()
         isExecuting:
             deps: ['state'], fn: ->
                 _.contains(['unqueued', 'queued', 'started'], @state)
+        isActive:
+            deps: ['isSubmitted', 'isExecuting'], fn: ->
+                !(@isSubmitted or @isExecuting)
+        stepsCompleted:
+            deps: ['data'], fn: ->
+                _.map(_.keys(@data?.output), _.titleize)

     onUpdate: ->
+        @trigger('update', @)
         @parent?.trigger('update', @)


allow post purchase message to contain html

Fixes #47

--- client/skr/api/OrderingComplete.cjsx
+++ client/skr/api/OrderingComplete.cjsx
@@ -1,3 +1,7 @@
+PostPurchaseMessage = (props) ->
+    return null unless props.message
+

+
 class Skr.Api.OrderingComplete extends Skr.Api.Components.Base

     propTypes:
@@ -19,7 +23,7 @@

                 Order number {@sale.visible_id} was successfully saved

-
{@props.options.post_purchase_message}

+            <PostPurchaseMessage message={@props.options.post_purchase_message} />

                 <button onClick={@props.onComplete}>
                     Place new order


JSON fields yield native values

JSON fields yield native values

--- resource/translators/translator.coffee
+++ resource/translators/translator.coffee
@@ -469,7 +469,7 @@
         Translator.debug('Unmapped CSL field', name, '=', value.value)
       continue

-    if value.value.trim() == ''
+    if ((typeof value.value == 'string') && value.value.trim() == '')
       @remove(name)
       continue


dont show checkbutton if domain is not new

--- client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
@@ -117,9 +117,12 @@
               keydown                 :
                 =>
                   @clearSuggestions()
-                  {registerButton, checkButton} = form.buttons
-                  registerButton.hide()
-                  checkButton.show()
+                  {DomainOption} = @forms["Domain Address"].inputs
+                  actionState = DomainOption.getValue()
+                  if actionState is "new"
+                    {registerButton, checkButton} = form.buttons
+                    registerButton.hide()
+                    checkButton.show()
               nextElement             :
                 regYears              :
                   cssClass            : "hidden"


brackets work slightly better

brackets work slightly better

--- coffeequate/src/operators/Pow.coffee
+++ coffeequate/src/operators/Pow.coffee
@@ -11,7 +11,7 @@
 	# Node in the expression tree representing exponentiation.
 	class Pow extends nodes.BinaryNode
 		# Represent powers.
-
+
 		# Make a new power node.
 		# Arguments passed as children will be parsed as children from whatever type they are.
 		#
@@ -443,7 +443,8 @@
 						return new FractionNode(new NumberNode(1),
 								new SurdNode(@children.left.toDrawingNode(), -@children.right.denominator))

-			return new PowNode(@children.left.toDrawingNode(), @children.right.toDrawingNode())
+			return new PowNode(PowNode::bracketIfNeeded(@children.left.toDrawingNode()),
+																			@children.right.toDrawingNode())

 		# Differentiate this node with respect to a variable.
 		#


cleaned up block comment output; fixes #1186

--- nodes.coffee
+++ nodes.coffee
@@ -441,7 +441,7 @@
   makeReturn:      THIS

   compileNode: (o, level) ->
-    code = '/*' + multident(@comment, @tab) + '*/'
+    code = '/*' + multident(@comment, @tab) + "\n#{@tab}*/\n"
     code = o.indent + code if (level or o.level) is LEVEL_TOP
     code

@@ -1851,4 +1851,5 @@
   ref

 multident = (code, tab) ->
-  code.replace /\n/g, '$&' + tab
+  code = code.replace /\n/g, '$&' + tab
+  code.replace /\s+$/, ''


Make modulo operator convert arguments to numbers

--- nodes.coffee
+++ nodes.coffee
@@ -2194,7 +2194,7 @@
   "

   modulo: -> """
-    function(a, b) { return (a % b + b) % b; }
+    function(a, b) { return (a % b + +b) % b; }
   """

   # Shortcuts to speed up the lookup time for native functions.


waypoint -- documented down to the ThrowNode

--- nodes.coffee
+++ nodes.coffee
@@ -881,7 +881,10 @@
     [@first.compile(o), @operator, @second.compile(o)].join ' '

   # Mimic Python's chained comparisons when multiple comparison operators are
-  # used sequentially. For example: `50 < 65 > 10`
+  # used sequentially. For example:
+  #
+  #     bin/coffee -e "puts 50 < 65 > 10"
+  #     true
   compile_chain: (o) ->
     shared: @first.unwrap().second
     [@first.second, shared]: shared.compile_reference(o) if shared instanceof CallNode
@@ -897,19 +900,23 @@
     return "$first = ${ ExistenceNode.compile_test(o, @first) } ? $first : $second" if @operator is '?='
     "$first = $first ${ @operator.substr(0, 2) } $second"

+  # If this is an existence operator, we delegate to `ExistenceNode.compile_test`
+  # to give us the safe references for the variables.
   compile_existence: (o) ->
     [first, second]: [@first.compile(o), @second.compile(o)]
     test: ExistenceNode.compile_test(o, @first)
     "$test ? $first : $second"

+  # Compile a unary **OpNode**.
   compile_unary: (o) ->
     space: if @PREFIX_OPERATORS.indexOf(@operator) >= 0 then ' ' else ''
     parts: [@operator, space, @first.compile(o)]
     parts: parts.reverse() if @flip
     parts.join('')

-
-# A try/catch/finally block.
+#### TryNode
+
+# A classic *try/catch/finally* block.
 exports.TryNode: class TryNode extends BaseNode
   type: 'Try'

@@ -918,6 +925,8 @@
     @error: error
     this

+  # Compilation is more or less as you would expect -- the *finally* clause
+  # is optional, the *catch* is not.
   compile_node: (o) ->
     o.indent:     @idt(1)
     o.top:        true


alright, really fixing the comments this time

--- nodes.coffee
+++ nodes.coffee
@@ -310,8 +310,7 @@
     this

   compile_node: (o) ->
-    delimiter: @idt() + '//'
-    delimiter + @lines.join(delimiter)
+    @idt() + '//' + @lines.join('\n' + @idt() + '//')

 }


Allow passing separately loaded modules as components

--- noflo.coffee
+++ noflo.coffee
@@ -7,6 +7,8 @@
     processes: []

     load: (component) ->
+        if typeof component is "object"
+            return component
         try
             return require component
         catch error


adapt coffee image demo to use new data format

--- bokehjs/demo/coffee/image.coffee
+++ bokehjs/demo/coffee/image.coffee
@@ -11,11 +11,13 @@

 N = 600

-d = new Float32Array(N*N)
+d = new Array(N)
 xs = linspace(0,10,N)
-for j in [0..(N-1)]
-  for i in [0..(N-1)]
-    d[j*N+i] = Math.sin(xs[i])*Math.cos(xs[j])
+for i in [0..(N-1)]
+  for j in [0..(N-1)]
+    if j == 0
+      d[i] = new Array(N)
+    d[i][j] = Math.sin(xs[i])*Math.cos(xs[j])

 data = {
   image: [d]
@@ -30,8 +32,6 @@
   dh: 10
   dh_units: 'data'
   image: 'image'
-  width: N
-  height: N
   palette: 'Spectral-10'
 }


directly get editor from event

directly get editor from event

--- lib/base.coffee
+++ lib/base.coffee
@@ -260,7 +260,8 @@
     atom.commands.add(@getCommandScope(), @getCommandName(), (event) => @run(event))

   @run: (event) ->
-    if vimState = getEditorState(atom.workspace.getActiveTextEditor())
+    vimState = getEditorState(event.target.getModel()) ? getEditorState(atom.workspace.getActiveTextEditor())
+    if vimState?
       vimState.domEvent = event
       # Reason: https://github.com/t9md/atom-vim-mode-plus/issues/85
       vimState.operationStack.run(this)


Revert "fix auto grow height calculation procedure"

This reverts these commits:
618656b6045583a81fcab72d4b0ad7a82742beeb
775d3ca16e55f6280faf34bcd98e7b96b1ca20a8 fdd2ee120fb5dc84e7887a7c437769f99df4c25d.

--- components/inputs/KDInputView.coffee
+++ components/inputs/KDInputView.coffee
@@ -314,14 +314,12 @@
     $input = @$()

     @setClass "autogrow"
-
-    # input content is copied into clone element to get calculated height
-    @_clone = $ "<div/>", class : "invisible"
+    $growCalculator = $ "<div/>", class : "invisible"

     @on "focus", =>
       @utils.defer =>
-        @_clone.appendTo 'body'
-        @_clone.css
+        $growCalculator.appendTo 'body'
+        $growCalculator.css
           height        : "auto"
           "z-index"     : 100000
           width         : $input.width()
@@ -331,23 +329,18 @@
           "line-height" : $input.css('line-height')

     @on "blur", =>
-      @_clone.detach()
+      $growCalculator.detach()
       @$()[0].style.height = "none" # hack to set to initial

-    @on "keydown", @bound "resize"
-    @on "keyup", (event) => @resize() if @getValue().length is 0
-
-  resize: ->
-    return  unless @_clone
-    @_clone.appendTo 'body' unless document.body.contains @_clone[0]
-    @_clone.html @getValue().replace /\n/gm, "<br />"
-    height = @_clone.height()
-    if @$().css('box-sizing') is "border-box"
-      padding    = parseInt(@_clone.css("padding-top"), 10) + parseInt(@_clone.css("padding-bottom"), 10)
-      border     = parseInt(@_clone.css("border-top-width"), 10) + parseInt(@_clone.css("border-bottom-width"), 10)
-      height     = height + border + padding
-
-    @setHeight height
+    @on "keydown", =>
+      $growCalculator.text @getValue()
+      height = $growCalculator.height()
+      if @$().css('box-sizing') is "border-box"
+        padding    = parseInt($growCalculator.css("padding-top"), 10) + parseInt($growCalculator.css("padding-bottom"), 10)
+        border     = parseInt($growCalculator.css("border-top-width"), 10) + parseInt($growCalculator.css("border-bottom-width"), 10)
+        height     = height + border + padding
+
+      @setHeight height

   enableTabKey:-> @inputTabKeyEnabled = yes


readability and a comment

readability and a comment

--- components/inputs/KDInputView.coffee
+++ components/inputs/KDInputView.coffee
@@ -241,9 +241,10 @@
       @valid = no
     else
       @validationResults[rule] = null
+      # if there is any true on validation results' values then is not valid
       @valid = not _.values(@validationResults)
-                    .map((valid)-> not valid)
-                    .indexOf(false) > -1
+                    .map((result)-> Boolean result)
+                    .indexOf true > -1

   showValidationError:(message)->


Increase max infinite scroll items to 2000

--- static/coffee/controllers.coffee
+++ static/coffee/controllers.coffee
@@ -10,7 +10,7 @@
 INTERVAL_CASE_TIMELINE = 30000
 INTERVAL_ITEM_REFRESH = 10000

-INFINITE_SCROLL_MAX_ITEMS = 1000
+INFINITE_SCROLL_MAX_ITEMS = 2000

 # Form constraints
 CASE_SUMMARY_MAX_LEN = 255


remove redundant brackets

remove redundant brackets

--- lib/eval.coffee
+++ lib/eval.coffee
@@ -26,7 +26,7 @@
     "#{code}.call(#{mod})"

   eval: (mod, code, key) ->
-    result = vm.runInThisContext (@wrapModule mod, @coffee(code))
+    result = vm.runInThisContext @wrapModule mod, @coffee(code)
     if key?
       mod = vm.runInThisContext(mod)
       mod[key] = result


Fix inspect for new browsers

Fix inspect for new browsers

--- lib/info.coffee
+++ lib/info.coffee
@@ -5,6 +5,10 @@
   ie:      'IE'
   ie_mob:  'IE Mobile'
   ios_saf: 'iOS'
+  op_mini: 'Opera Mini'
+  op_mob:  'Opera Mobile'
+  and_chr: 'Chrome for Android'
+  and_ff:  'Firefox for Android'

 prefix = (name, transition, prefixes) ->
     out  = '  ' + name + (if transition then '*' else '') + ': '


coffeescript

coffeescript

--- lib/init.coffee
+++ lib/init.coffee
@@ -72,12 +72,12 @@

 atom.workspace.addLeftPanel(item: el)

-document.getElementById('lupa-load-index-file').addEventListener('click', function () {
+document.getElementById('lupa-load-index-file').addEventListener('click', () ->
     plugin.send({
         type: 'loadIndexFile',
         path: document.getElementById('lupa-index-file').value
-    });
-});
+    })
+})
 lastState = {}

 update1 = ->


coffeescript

coffeescript

--- lib/init.coffee
+++ lib/init.coffee
@@ -19,7 +19,7 @@
 onUpdate = () -> 0
 plugin = child_process.fork(__dirname + '/plugin')
 bar = (data)-> {
-    console.log("result: ", data)
+    console.log "result: " ,  data
     onUpdate(data)
 }


Social: added forgotten queue.next s

Social: added forgotten queue.next s

--- workers/social/lib/social/models/invitation.test.coffee
+++ workers/social/lib/social/models/invitation.test.coffee
@@ -96,11 +96,13 @@

             JInvitation.create adminClient, invitationReq, (err) ->
               expect(err).to.not.exist
+              queue.next()

           ->
               JInvitation.one { email: userFormData.email, groupName: client.context.group }, (err, invitation) ->
                 expect(err).to.not.exist
                 expect(invitation).to.exist
+                queue.next()

           -> done()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/clamp_bounds.coffee
+++ test/clamp_bounds.coffee
@@ -7,7 +7,7 @@
   # Hack in App.width, App.height
   App = {}
   App.width = 480
-  App.height = 32
+  App.height = 320

   player.I.x = - 400
   player.update()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/clamp_bounds.coffee
+++ test/clamp_bounds.coffee
@@ -4,7 +4,7 @@
   player = GameObject()
   player.include(ClampBounds)

-  # Hack
+  # Hack in App.

   player.I.x = - 400
   player.update()


Faster, simpler suspend() function.

Faster, simpler suspend() function.

--- lib/lazy.coffee
+++ lib/lazy.coffee
@@ -16,9 +16,7 @@
 exports ?= this.pazy ?= {}

 exports.suspend = (code) ->
-  cache = [->
-    val = code()
-    cache[0] = -> val
+  val = null
+  ->
+    [val, code] = [code(); null] if code
     val
-  ]
-  -> cache[0]()


:memo: check location when mouse event didn't bubbled up #32

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,7 +1,3 @@
-{inspect} = require 'util'
-logLocation = (msg, loc) ->
-  # console.log msg, inspect(loc)
-
 {CompositeDisposable, Disposable} = require 'atom'
 History = null

@@ -77,16 +73,34 @@
   #  - Event bubbling phase: Cursor position updated to clicked position.
   observeMouse: ->
     locationStack = []
+    locationCheckTimeoutID = null
+
+    checkLocationChangeAfter = (location, timeout) =>
+      clearTimeout(locationCheckTimeoutID)
+      locationCheckTimeoutID = setTimeout =>
+        locationCheckTimeoutID = null
+        @checkLocationChange(location)
+      , timeout
+
     handleCapture = (event) ->
       if editor = closestTextEditorHavingURI(event.target)
-        loc = createLocation(editor, 'mousedown')
-        # logLocation('push', loc)
-        locationStack.push(loc)
+        location = createLocation(editor, 'mousedown')
+        locationStack.push(location)
+        # In case, mousedown event was not **bubbled** up, detect location change
+        # by comparing old and new location after 300ms
+        # This task is cancelled when mouse event bubbled up to avoid duplicate
+        # location check.
+        #
+        # E.g. hyperclick package open another file by mouseclick, it explicitly
+        # call `event.stopPropagation()` to prevent default mouse behavior of Atom.
+        # In such case we can't catch mouseclick event at bublling phase.
+        checkLocationChangeAfter(location, 300)

     handleBubble = (event) =>
-      if editor = closestTextEditorHavingURI(event.target)
+      clearTimeout(locationCheckTimeoutID)
+      if location = locationStack.pop()
         setTimeout =>
-          @checkLocationChange(locationStack.pop())
+          @checkLocationChange(location)
         , 100

     workspaceElement = atom.views.getView(atom.workspace)
@@ -137,7 +151,6 @@
     if editor.element.hasFocus() and (editor.getURI() is oldLocation.URI)
       # Move within same buffer.
       newLocation = createLocation(editor, oldLocation.type)
-      # logLocation('compare new', newLocation)
       oldPoint = oldLocation.point
       newPoint = newLocation.point


fix description

fix description

--- lib/main.coffee
+++ lib/main.coffee
@@ -14,7 +14,7 @@
       order: 0
     customArguments:
       title: "Custom Arguments"
-      description: "Specify your preferred arguments for BridleNSIS"
+      description: "Specify your preferred arguments for nsL Assembler"
       type: "string"
       default: "/nopause /nomake"
       order: 1


Use the file path from jolie --check

Use the file path from jolie --check

--- lib/main.coffee
+++ lib/main.coffee
@@ -17,7 +17,7 @@
       lintOnFly: true
       lint: ( editor ) ->
         return helpers.exec( executablePath, [ "--check", editor.getPath() ], { stream: "both" } ).then ( data ) ->
-          helpers.parse( data.stderr, pattern, { filePath: editor.getPath() } )
+          helpers.parse( data.stderr, pattern )
             .map ( issue ) ->
               [ [ lineStart, colStart ], [ lineEnd, colEnd ] ] = issue.range
               issue.range = helpers.rangeFromLineNumber editor, lineStart, colStart


add table configs

add table configs

--- lib/main.coffee
+++ lib/main.coffee
@@ -51,6 +51,16 @@
     title: "File Extension"
     type: "string"
     default: config.getCurrentDefault("fileExtension")
+  tableAlignment:
+    title: "Table Cell Alignment"
+    type: "string"
+    default: config.getDefault("tableAlignment")
+    enum: ["empty", "left", "right", "center"]
+  tableExtraPipes:
+    title: "Table Extra Pipes"
+    description: "Insert extra pipes at the start and the end of the table rows"
+    type: "boolean"
+    default: config.getDefault("tableExtraPipes")

 module.exports =
   config: basicConfig


Issue #62 Selecting your folder

Issue #62 Selecting your folder

Hi, I just happen to be reading your code and think this could be a quick solution to Issue #62.
It seems like you are missing an event handler for the input box (or I missed it somewhere in the file... I didn't read all of them after all), so I add a simple one for it. :)

--- lib/main.coffee
+++ lib/main.coffee
@@ -341,6 +341,9 @@
 $(document).on 'click', '#browse', ->
   openFolder()

+$(document).on 'input', '#install_path', ->
+  checkInstallPath($(this).val(), setInstallPath)
+
 $('.github > a').click (e) ->
   e.preventDefault()
   open('https://github.com/dustinblackman/Championify#faq')


:art: Add some vertical spaces

:art: Add some vertical spaces

--- lib/main.coffee
+++ lib/main.coffee
@@ -37,12 +37,14 @@
       default: []
       items:
         type: 'string'
+
   provideLinter: ->
     helpers = require('atom-linter')
     regex =
     '(.*?):(?<line>\\d+):(?<col>\\d+): ' +
       '(?<message>((?<error>E11|E9)|' +
       '(?<warning>W|E|F4|F84|N*|C|D|Q|H|I)|F)\\d+ .*?)\r?\n'
+
     provider =
       grammarScopes: ['source.python', 'source.python.django']
       scope: 'file' # or 'project'
@@ -51,6 +53,7 @@
         filePath = textEditor.getPath()
         fileText = textEditor.getText()
         parameters = []
+
         if maxLineLength = atom.config.get('linter-flake8.maxLineLength')
           parameters.push('--max-line-length', maxLineLength)
         if (ignoreErrorCodes = atom.config.get('linter-flake8.ignoreErrorCodes')).length
@@ -62,9 +65,11 @@
         if (selectErrors = atom.config.get('linter-flake8.selectErrors')).length
           parameters.push('--select', selectErrors.join(','))
         parameters.push('-')
+
         return helpers.exec(atom.config.get('linter-flake8.executablePath'), parameters, stdin: fileText).then (result) ->
           toReturn = []
           regex = /stdin:(\d+):(\d+):\s*(.*?) (.*?):\s*(.*)/g
+
           while (match = regex.exec(result)) isnt null
             line = parseInt(match[1]) or 0
             col = parseInt(match[2]) or 0


:art: for simplicity don't skip event for consistency

--- lib/main.coffee
+++ lib/main.coffee
@@ -56,7 +56,7 @@
       'paner:very-right':  => @moveToVery 'right'

     @onDidPaneSplit ({oldPane, newPane, direction, options}) ->
-      oldEditor = oldPane.getActiveEditor()
+      return unless oldEditor = oldPane.getActiveEditor()
       newEditor = newPane.getActiveEditor()
       switch direction
         when 'right', 'left'
@@ -99,13 +99,13 @@

   split: (direction) ->
     oldPane = getActivePane()
-    editor = oldPane.getActiveEditor()
+    editor =

     options = null
-    options = @getCursorPositionInfo(editor) if direction in ['up', 'down']
+    if direction in ['up', 'down']
+      options = @getCursorPositionInfo(oldPane.getActiveEditor())
     newPane = splitPane(oldPane, direction)
-    if editor?
-      @emitter.emit 'did-pane-split', {oldPane, newPane, direction, options}
+    @emitter.emit 'did-pane-split', {oldPane, newPane, direction, options}

   swapItem: ->
     currentPane = getActivePane()


:art: Set default inlineTooltipInterval to 60

--- lib/main.coffee
+++ lib/main.coffee
@@ -26,9 +26,9 @@
       order: 3
     inlineTooltipInterval:
       title: 'Inline tooltip interval'
-      description: 'Interval at which inline tooltip is updated'
+      description: 'Interval at which inline tooltip is updated (in ms)'
       type: 'integer'
-      default: 200
+      default: 60
       order: 3
     gutterEnabled:
       title: 'Highlight error lines in gutter'


Added empty_block to warnings

Added empty_block to warnings

--- lib/main.coffee
+++ lib/main.coffee
@@ -49,7 +49,8 @@
     helpers = require('atom-linter')
     #reporter = require('jshint-json') # a string path
     warnings = [
-      'unused_a',
+      'unused_a'
+      'empty_block'
     ]
     infos = [
       'nested_comment'


Breaking: Switch to standard stream patterns

--- lib/main.coffee
+++ lib/main.coffee
@@ -15,9 +15,9 @@
       stream.emit 'error', e

     globber.on 'end', ->
-      stream.emit 'end'
+      stream.end()

     globber.on 'match', (filename) ->
-      stream.emit 'data', filename
+      stream.write filename

     return stream


Push top-level require() calls down into the functions that use them.

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,6 +1,3 @@
-_ = require 'underscore-plus'
-TabBarView = require './tab-bar-view'
-
 module.exports =
   config:
     showIcons:
@@ -20,6 +17,8 @@
   activate: ->
     @tabBarViews = []

+    TabBarView = require './tab-bar-view'
+    _ = require 'underscore-plus'
     @paneSubscription = atom.workspace.observePanes (pane) =>
       tabBarView = new TabBarView(pane)


additional loggin

additional loggin

--- lib/markem.iced
+++ lib/markem.iced
@@ -125,89 +125,91 @@
       return
     cb(err,stdout,stderr)
   @_generate: (layout,cb)->
+    await fs.readdir @tmp,defer err, list
+    for file in list
+      continue if file.match /^\./
+      await fs.stat path.join(@tmp,file),defer err, stat
+      if stat.isDirectory()
+        console.log "rm -Rf #{file}" if @options.verbose
+        await utils.rmdirDeep file,defer err
+      else
+        console.log "rm -f #{file}" if @options.verbose
+        await utils.unlink file,defer err
+
+    console.log "cp -R markem.conf #{@tmp}" if @options.verbose
+    await utils.cpdir 'markem.conf',@tmp,defer err
+
+    console.log "rm -f #{path.join(@tmp,'layout.jade')}" if @options.verbose
+    await utils.unlink path.join(@tmp,'layout.jade'),defer err
     utils.scandir
-      path: @tmp,
-      readFiles:false
+      path: @source
+      readFiles: false
       ignoreHiddenFiles: true
-      recurse:false
-      next:(err,list)->
-        for file,type of list
-          file=path.join @tmp,file
-          if type=='dir'
-            await utils.rmdirDeep file,defer err
+      next: (err,list) ->
+        globals={}
+        documents={}
+
+        # initialize some basic stuff
+        for relative,type of list
+          if type=='file'&&!relative.match /node_modules/
+            target=null
+            if relative.match /\.markdown$/
+              target=path.join @tmp,relative.replace /\.markdown$/,'.html'
+            if relative.match /\.md$/
+              target=path.join @tmp,relative.replace /\.md$/,'.html'
+            if relative.match new RegExp("readme\\.md$",'i')
+              target=path.join @tmp,relative.replace new RegExp("[^#{path.sep}]*$"),'index.html'
+            if target?
+              document=
+                dirs:[]
+                files:[]
+                pathSource:'/'+relative
+                pathFile:'/'+path.relative(@tmp,target)
+                target:target
+                globals:globals
+              document.path=document.pathFile.replace(/\/index\.html$/,'/')
+              document.root=path.relative document.path.replace(/\/[^\/]*$/,'/'),'\/'
+              if !document.root.length
+                document.root='.'
+              documents[document.path]=document
+              await fs.readFile relative,'utf8',defer err,document.source
+
+
+        # build relationships,content,title between documents
+        for p,document of documents
+          document.content=marked document.source
+          document.title=(document.content.match(/<h1>([^<]*)<\/h1>/m)||[null,'untitled'])[1]
+          if p=='/'
+            globals.root=document
+          if p.match /\/$/
+            document.parent=documents[p.replace(/[^\/]*\/$/,'')]
+            document.type='dir'
           else
-            await utils.unlink file,defer err
-        await utils.cpdir 'markem.conf',@tmp,defer err
-        await utils.unlink path.join(@tmp,'layout.jade'),defer err
-        utils.scandir
-          path: @source
-          readFiles: false
-          ignoreHiddenFiles: true
-          next: (err,list) ->
-            globals={}
-            documents={}
-
-            # initialize some basic stuff
-            for relative,type of list
-              if type=='file'&&!relative.match /node_modules/
-                target=null
-                if relative.match /\.markdown$/
-                  target=path.join @tmp,relative.replace /\.markdown$/,'.html'
-                if relative.match /\.md$/
-                  target=path.join @tmp,relative.replace /\.md$/,'.html'
-                if relative.match new RegExp("readme\\.md$",'i')
-                  target=path.join @tmp,relative.replace new RegExp("[^#{path.sep}]*$"),'index.html'
-                if target?
-                  document=
-                    dirs:[]
-                    files:[]
-                    pathSource:'/'+relative
-                    pathFile:'/'+path.relative(@tmp,target)
-                    target:target
-                    globals:globals
-                  document.path=document.pathFile.replace(/\/index\.html$/,'/')
-                  document.root=path.relative document.path.replace(/\/[^\/]*$/,'/'),'\/'
-                  if !document.root.length
-                    document.root='.'
-                  documents[document.path]=document
-                  await fs.readFile relative,'utf8',defer err,document.source
-
-
-            # build relationships,content,title between documents
-            for p,document of documents
-              document.content=marked document.source
-              document.title=(document.content.match(/<h1>([^<]*)<\/h1>/m)||[null,'untitled'])[1]
-              if p=='/'
-                globals.root=document
-              if p.match /\/$/
-                document.parent=documents[p.replace(/[^\/]*\/$/,'')]
-                document.type='dir'
-              else
-                document.parent=documents[p.replace(/[^\/]+$/,'')]
-                document.type='file'
-              if document.parent?
-                if document.type=='dir'
-                  document.parent.dirs.push document
-                else
-                  document.parent.files.push document
-
-            try
-              markemConf=require path.join process.cwd(),'markem.conf'
-            catch e
-            if markemConf? and markemConf.preRender?
-              await markemConf.preRender globals,defer err
-
-            # render each documents
-            for p,document of documents
-              if markem.options.verbose
-                console.log "rendering #{document.target}"
-              await mkdirp path.dirname(document.target),defer err
-              try
-                document.output=layout document
-              catch e
-                console.error e
-                utils.rmdirDeep @tmp,->
-                process.exit 1
-                return
-              await fs.writeFile document.target,document.output,'utf8',defer err
-            cb()+            document.parent=documents[p.replace(/[^\/]+$/,'')]
+            document.type='file'
+          if document.parent?
+            if document.type=='dir'
+              document.parent.dirs.push document
+            else
+              document.parent.files.push document
+
+        try
+          markemConf=require path.join process.cwd(),'markem.conf'
+        catch e
+        if markemConf? and markemConf.preRender?
+          await markemConf.preRender globals,defer err
+
+        # render each documents
+        for p,document of documents
+
+          console.log "rendering #{document.target}" if markem.options.verbose
+          await mkdirp path.dirname(document.target),defer err
+          try
+            document.output=layout document
+          catch e
+            console.error e
+            utils.rmdirDeep @tmp,->
+            process.exit 1
+            return
+          await fs.writeFile document.target,document.output,'utf8',defer err
+        cb()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -24,7 +24,7 @@

   equals player.I.x, 8

-  window.keydown
+  window.keydown.left = f

 test "should move player right while key is pressed", ->
   window.keydown.right = true


Send byebye to "kill" any instances that haven't timed out

We can't send this when you "turn off" the device since it might be with
a simple kill, but it shouldn't hurt to send it when we (re)start.

--- lib/ssdp.coffee
+++ lib/ssdp.coffee
@@ -8,10 +8,12 @@
 {debug} = require './helpers'

 announce = exports.announce = (dev, httpServer) ->
-    advertise dev, httpServer
+    # to "kill" any instances that haven't timed out on control points yet, first send byebye message
+    byebye dev, httpServer
+    alive dev, httpServer
     # recommended delay between advertisements is a random interval of less than half of timeout
     setInterval(
-        advertise
+        alive
         Math.floor(Math.random() * ((config.ssdp.timeout / 2) * 1000))
         dev, httpServer
     )
@@ -37,7 +39,7 @@
     socket.bind config.ssdp.port

 # initial announcement
-advertise = (dev, httpServer) ->
+alive = (dev, httpServer) ->
     sendMessages(
         makeMessage(
             'notify'
@@ -58,6 +60,15 @@
         ) for st in makeNotificationHeaders(dev)
         req.address
         req.port
+    )
+
+byebye = (dev, httpServer) ->
+    sendMessages(
+        makeMessage(
+            'notify'
+            nt: nt, nts: 'ssdp:byebye', host: null
+            dev, httpServer
+        ) for nt in makeNotificationHeaders(dev)
     )

 # send 3 messages about the device, and then one for each service


Update repost.coffee

Update repost.coffee

Removed the "-" separator between the title and the URL

--- repost.coffee
+++ repost.coffee
@@ -105,7 +105,7 @@
   index = urls.indexOf last_post
   index = if index - 1 < 0 then urls.length - 1 else index - 1

-  status = "#{entries[urls[index]]} - #{urls[index]}"
+  status = "#{entries[urls[index]]} #{urls[index]}"
   console.log "posting tweet: #{status}"
   request
     proxy: proxy
@@ -127,4 +127,4 @@
   fs.writeFile last_post_file, posted_url, (err) ->
     callback()

-main()+main()


make resolve_tests pass

make resolve_tests pass

--- test/resolve_test.coffee
+++ test/resolve_test.coffee
@@ -11,13 +11,14 @@
   path

 assert.equal resolve('underscore'), "#{root}/vendor/underscore.js"
-assert.equal resolve('app'), "#{root}/src/app.js"
+assert.equal resolve('atom/window'), "#{root}/src/atom/window.js"
 assert.equal resolve('tabs/tabs'), "#{root}/extensions/tabs/tabs.js"

-# assert.equal resolve('./document'), "#{root}/src/document.js"
-# assert.equal resolve('../README.md'), "#{root}/README.md"
-dotatom = fs.absolute "~/.atomicity"
-assert.equal resolve('~/.atomicity'), "#{dotatom}/index.coffee"
+#assert.equal resolve('./resource'), "#{root}/src/resource.js"
+#assert.equal resolve('../README.md'), "#{root}/README.md"
+
+dotatom = fs.absolute "~/.atom"
+assert.equal resolve('~/.atom'), "#{dotatom}/index.coffee"

 assert.equal resolve('ace/requirejs/text!ace/css/editor.css'),
   "#{root}/vendor/ace/css/editor.css"


fix broken tests

fix broken tests

--- test/roaster-spec.coffee
+++ test/roaster-spec.coffee
@@ -1,6 +1,7 @@
 roaster = require '../lib/roaster'
 Path = require 'path'
 Fs = require 'fs'
+cheerio = require 'cheerio'

 fixtures_dir = Path.join(__dirname, "fixtures")

@@ -36,9 +37,25 @@

       runs ->
         [err, contents] = callback.mostRecentCall.args
+        expect(err).toBeNull()

-        expect(err).toBeNull()
-        expect(contents).toEqual '

\n

\n

'
+        $ = cheerio.load(contents)
+        expect($("p img").length).toBe 3
+
+        expect($('p img[title=":trollface:"]').length).toBe 1
+        expect($('p img[title=":trollface:"]').attr("class")).toEqual "emoji"
+        expect($('p img[title=":trollface:"]').attr("alt")).toEqual "trollface"
+        expect($('p img[title=":trollface:"]').attr("src")).toMatch /.*trollface\.png$/
+
+        expect($('p img[title=":shipit:"]').length).toBe 1
+        expect($('p img[title=":shipit:"]').attr("class")).toEqual "emoji"
+        expect($('p img[title=":shipit:"]').attr("alt")).toEqual "shipit"
+        expect($('p img[title=":shipit:"]').attr("src")).toMatch /.*shipit\.png$/
+
+        expect($('p img[title=":smiley:"]').length).toBe 1
+        expect($('p img[title=":smiley:"]').attr("class")).toEqual "emoji"
+        expect($('p img[title=":smiley:"]').attr("alt")).toEqual "smiley"
+        expect($('p img[title=":smiley:"]').attr("src")).toMatch /.*smiley\.png$/
     it "can sanitize and return", ->
       callback = jasmine.createSpy()
       roaster Path.join(fixtures_dir, "emoji.md"), {isFile: true, sanitize:true}, callback
@@ -48,9 +65,25 @@

       runs ->
         [err, contents] = callback.mostRecentCall.args
+        expect(err).toBeNull()

-        expect(err).toBeNull()
-        expect(contents).toEqual '

\n

\n

'
+        $ = cheerio.load(contents)
+        expect($("p img").length).toBe 3
+
+        expect($('p img[title=":trollface:"]').length).toBe 1
+        expect($('p img[title=":trollface:"]').attr("class")).toEqual "emoji"
+        expect($('p img[title=":trollface:"]').attr("alt")).toEqual "trollface"
+        expect($('p img[title=":trollface:"]').attr("src")).toMatch /.*trollface\.png$/
+
+        expect($('p img[title=":shipit:"]').length).toBe 1
+        expect($('p img[title=":shipit:"]').attr("class")).toEqual "emoji"
+        expect($('p img[title=":shipit:"]').attr("alt")).toEqual "shipit"
+        expect($('p img[title=":shipit:"]').attr("src")).toMatch /.*shipit\.png$/
+
+        expect($('p img[title=":smiley:"]').length).toBe 1
+        expect($('p img[title=":smiley:"]').attr("class")).toEqual "emoji"
+        expect($('p img[title=":smiley:"]').attr("alt")).toEqual "smiley"
+        expect($('p img[title=":smiley:"]').attr("src")).toMatch /.*smiley\.png$/
     it "does nothing to unknown emoji", ->
       roaster ":lala:", (err, contents) ->
         expect(err).toBeNull()
@@ -66,7 +99,7 @@
         [err, contents] = callback.mostRecentCall.args

         expect(err).toBeNull()
-        expect(contents).toEqual '
not :trollface:\n
\n
wow that is nice :smiley:
'
+        expect(contents).toEqual '
not :trollface:\n
\n
wow that is nice :smiley:
\n'
   # describe "headers", ->
   #   [toc, result, resultShort] = []


Rename "minimize" to "toggle" for workspace and toc

Because that's what it actually does.

--- scripts/views/layouts/workspace.coffee
+++ scripts/views/layouts/workspace.coffee
@@ -34,12 +34,12 @@
       workspace: '#workspace'

     events:
-      'click #workspace-container > .pickerswitch': 'minimizeWorkspace'
-      'click #sidebar-container > .pickerswitch': 'minimizeToc'
+      'click #workspace-container > .pickerswitch': 'toggleWorkspace'
+      'click #sidebar-container > .pickerswitch': 'toggleToc'

     initialize: () ->
       @workspace.on 'show', =>
         @$('#workspace-container').removeClass('tocminimized').addClass('wsminimized')

-    minimizeWorkspace: () -> @$('#workspace-container').toggleClass('wsminimized')
-    minimizeToc: () -> @$('#workspace-container').toggleClass('tocminimized')
+    toggleWorkspace: () -> @$('#workspace-container').toggleClass('wsminimized')
+    toggleToc: () -> @$('#workspace-container').toggleClass('tocminimized')


profile view: do not display external profile as linked if urlLocation option is missing

--- client/app/Applications/Members.kdapplication/ContentDisplays/externalprofileview.coffee
+++ client/app/Applications/Members.kdapplication/ContentDisplays/externalprofileview.coffee
@@ -34,6 +34,7 @@
     account.fetchStorage "ext|profile|#{provider}", (err, storage)=>
       return warn err  if err
       return           unless storage
+      return           unless urlLocation = @getOption 'urlLocation'

       @setData storage

@@ -42,7 +43,7 @@
       @linked = yes
       @setClass 'linked'
       @setAttributes
-        href   : JsPath.getAt @getData().content, @getOption('urlLocation')
+        href   : JsPath.getAt storage.content, urlLocation
         target : '_blank'

       @setTooltip if KD.isMine(account)
@@ -64,4 +65,4 @@

     """

-    """+    """


mr note fixes

mr note fixes

--- client/landing/app/Applications/Members.kdapplication/ContentDisplays/profileview.coffee
+++ client/landing/app/Applications/Members.kdapplication/ContentDisplays/profileview.coffee
@@ -21,7 +21,7 @@

 class AvatarChangeView extends JView

-  detectFeatures: ->
+  detectFeatures = ->
     isVideoSupported = KDWebcamView.getUserMediaVendor()
     isDNDSupported   = do ->
       tester = document.createElement('div')
@@ -34,7 +34,7 @@
     options.cssClass = "avatar-change-menu"
     super options, data

-    {isVideoSupported, isDNDSupported} = @detectFeatures()
+    {isVideoSupported, isDNDSupported} = detectFeatures()

     @on "viewAppended", =>
       @overlay = new KDOverlayView
@@ -68,19 +68,19 @@
       icon                : yes
       iconOnly            : yes
       iconClass           : "cross"
-      callback            : => @showUploadView()
+      callback            : @bound "showUploadView"

     @photoButton = new KDButtonView
       cssClass            : "clean-gray avatar-button"
       title               : "Take Photo"
-      disabled            : !isVideoSupported
-      callback            : => @showPhotoView()
+      disabled            : not isVideoSupported
+      callback            : @bound "showPhotoView"

     @uploadButton = new KDButtonView
       cssClass            : "clean-gray avatar-button"
-      disabled            : !isDNDSupported
+      disabled            : not isDNDSupported
       title               : "Upload Image"
-      callback            : => @showUploadView()
+      callback            : @bound "showUploadView"

     @gravatarButton = new KDButtonView
       cssClass            : "clean-gray avatar-button"


fix authentication for travis tests

fix authentication for travis tests

--- tests/index_tests.coffee
+++ tests/index_tests.coffee
@@ -70,7 +70,7 @@
                         "description": "This application needs ..."
                 "docType": "Application"
             client.setBasicAuth "home", "token"
-            client.post 'data/', data, (err, res, body) =>
+            client.post 'access/', data, (err, res, body) =>
                 @body = body
                 @err = err
                 @res = res


allow propagation

allow propagation

--- app/assets/javascripts/floating_formato_helper.js.coffee
+++ app/assets/javascripts/floating_formato_helper.js.coffee
@@ -6,7 +6,7 @@
       $form = $("form")
       url = $form.attr "action"
       $.post "#{url}/validate", $form.serialize(), "script"
-      false
+      true

     $(document).on "nested:fieldRemoved", ->
       # let's trigger upon fields removal


mekko: larger container, prevent legend overflow

--- app/assets/javascripts/lib/views/mekko_chart_view.coffee
+++ app/assets/javascripts/lib/views/mekko_chart_view.coffee
@@ -33,10 +33,12 @@
   render_mekko: =>
     $.jqplot @model.get("container"), @results(), @chart_opts()
     $(".jqplot-xaxis").css({"margin-left": -10,"margin-top":0})
-    $(".jqplot-table-legend").css({"top": 340})
+    $(".jqplot-table-legend").css({"top": 320})
     # this hides the labels appearing in the middle of the charts. Looks like a jqplot bug
     # See https://github.com/dennisschoenmakers/etmodel/issues/639
     $(".jqplot-point-label").html(null)
+    # prevent the legend from overlapping the secondary chart
+    @container_node().parent().css('height', 480)

   chart_opts: =>
     out =


move code

move code

--- cf/spell.coffee
+++ cf/spell.coffee
@@ -1,6 +1,5 @@
 $ ->

-  @storage = new LocalStorage()
   $("#question, #answer").hide()
   words = $.getJSON("spellings.json")
   $.when(words).done ((d)->
@@ -14,6 +13,7 @@

   startUp = (data) ->
     $("#question, #answer").show()
+    @storage = new LocalStorage()
     $("#created_at").append(@storage.created_at)
     @current = ""
     @fail = 0


use generic label class for select lists labels

--- src/command-palette-view.coffee
+++ src/command-palette-view.coffee
@@ -43,7 +43,7 @@
       @li class: 'event', 'data-event-name': eventName, =>
         @div eventDescription, class: 'event-description'
         @div class: 'right', =>
-          @div eventName, class: 'event-name'
+          @div eventName, class: 'label'
           for binding in keyBindings[eventName] ? []
             @div binding, class: 'key-binding'
         @div class: 'clear-float'


Legal Notice Layout for small layouts

Legal Notice Layout for small layouts

--- web/scripts/referenceUI.coffee
+++ web/scripts/referenceUI.coffee
@@ -214,7 +214,7 @@
     refContainer = document.createElement("div")

     $(backFade).css({width:'100%',height:'100%',position:'absolute','z-index':'300','background-color':'#000000','opacity':'.5'})
-    $(refContainer).css({width:'40%',height:'40%',left:'30%',top:'30%',position:'absolute','z-index':'301','background-color':'#FFFFFF'})
+    $(refContainer).css({ width:'40%',height:'40%',left:'30%',top:'30%',position:'absolute','z-index':'301','background-color':'#FFFFFF'})

     $("body").prepend(backFade)
     $(backFade).attr({id:'bF'})
@@ -223,12 +223,11 @@
     header = document.createElement("div")
     para = document.createElement("div")

-    $(header).css({"font-size":"26px","position":"absolute","width":"50%","top":"5%","left":"25%","text-align":"center"})
-    $(para).css({"font-size":"14px","position":"absolute","width":"90%","bottom":"12%","left":"5%","text-align":"center"})
-
-
+    $(header).css({"position":"static","overflow":"auto","font-size":"26px","width":"100%","left":"25%","text-align":"center"})
+    $(para).css({"overflow":"auto","max-height":"60%","position":"static"})
+
     header.innerHTML = "Legal Terms and Attributions"
-    para.innerHTML = "Copyright 2013 The Board of Trustees at the University of Illinois
Creative Commons Licenses from openclipart.org are
+    para.innerHTML = "Copyright (C) 2013 The Board of Trustees at the University of Illinois
Creative Commons Licenses from openclipart.org are
     licensed under the creative commons 0 license
     (Spiral Bound book, star icon, cow eat grass, treasure map)

     Doppio Java Virtual Machine
Original Content is licensed under MIT Expat License


Changes Element.attribute() so it returns null in both jQuery and Prototype versions.

--- tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
+++ tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
@@ -295,6 +295,8 @@
       current = @$.attr name
       if arguments.length > 1
         @$.attr name, value
+      if _.isUndefined current
+        current = null
 #elseif prototype
       current = @element.readAttribute name
       if arguments.length > 1


ClampBounds docs

ClampBounds docs

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -14,7 +14,7 @@
   player.I.x = -400

   # update the player so ClampBounds can set
-  # his position back inside the view
+  # his position back inside the viewport.
   player.update()
 </pre></code>


style: fix a typo

style: fix a typo

--- config.tpl.coffee
+++ config.tpl.coffee
@@ -58,7 +58,7 @@
     autoWatch: %AUTO_WATCH%

-    # satart these browsers
+    # start these browsers
     # available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
     browsers: [%BROWSERS%]


stack frames go the natural way, per #166

--- tools/core_viewer.coffee
+++ tools/core_viewer.coffee
@@ -18,7 +18,9 @@
   data = JSON.parse data
   main = $('#main')
   frames_div = $('
', id: 'frames', html: '
Stack Frames
')
-  for frame in data
+  #TODO: rewrite this when we move to coffeescript v1.5.0
+  for frame_idx in [data.length-1..0] by -1
+    frame = data[frame_idx]
     frames_div.append ul = $('
')
     for k,v of frame
       if k in ['stack','locals']


KodingRouter: getDefaultRoute: use /Activity if group has no stack template

For koding default route still is /IDE always, for others if there is stack
template defined for the active group, it goes again to /IDE but if there is no
stack template defined for the current group it goes /Activity directly.

This doesn't effect the routes direct accesses.

--- client/app/lib/kodingrouter.coffee
+++ client/app/lib/kodingrouter.coffee
@@ -82,7 +82,31 @@
       then status_404()
       else status_301 target

-  getDefaultRoute: -> if isLoggedIn() then '/IDE' else '/Home'
+
+  getDefaultRoute: ->
+
+    {groupsController} = kd.singletons
+    currentGroup       = groupsController.getCurrentGroup()
+
+    # For koding default route still is /IDE always, for others if there is
+    # stack template defined for the active group, it goes again to /IDE but if
+    # there is no stack template defined for the current group it goes /Activity
+    # directly.
+    #
+    # This doesn't effect the routes direct accesses. ~ GG
+
+    if isLoggedIn()
+
+      if not currentGroup or currentGroup.slug is 'koding'
+        return '/IDE'
+
+      if not currentGroup?.stackTemplates?.length > 0
+      then return '/Activity'
+      else return '/IDE'
+
+    else
+      return '/Home'
+

   setPageTitle: (title = 'Koding') -> kd.singletons.pageTitle.update title

@@ -167,5 +191,3 @@
       else '/'

     super route, replaceState
-
-


Tests: Fix routes tests.

Tests: Fix routes tests.

--- client/ide/test/routes.test.coffee
+++ client/ide/test/routes.test.coffee
@@ -9,7 +9,7 @@
 mockMachine   = mock.getMockMachine()
 mockWorkspace = mock.getMockWorkspace()
 dataToLoadIDE =
-  machine     : mock.getMockJMachine()
+  machine     : mock.getMockMachine()
   username    : mock.getMockAccount().profile.nickname
   workspace   : mock.getMockWorkspace()
   channelId   : '6075644514008039523'
@@ -337,12 +337,12 @@

     it 'should routeToMachineWorkspace if fetchMachine returns no workspace', ->

+      mock.ideRoutes.getLatestWorkspace.toReturnWorkspace()
       mock.envDataProvider.fetchMachineByLabel.toReturnMachine()
       expect.spyOn routes, 'routeToMachineWorkspace'

       routes.routeToLatestWorkspace()
       expect(routes.routeToMachineWorkspace).toHaveBeenCalledWith mockMachine
-

     it 'should routeToFallback if there is no machine and workspace for the stored data', ->


a little tweak

a little tweak

--- src/command/revoke.iced
+++ src/command/revoke.iced
@@ -79,7 +79,7 @@

   revoke_key : (cb) ->
     args =
-      revoke_primary : 1
+      revoke_primary  : 1
       revocation_type : 0
     await req.post { endpoint : "key/revoke", args }, defer err
     cb err


fix oops

fix oops

--- scripts/about.coffee
+++ scripts/about.coffee
@@ -16,9 +16,8 @@
 module.exports = (robot) ->

   about = (msg) ->
-    robot.logger.debug msg
     msg.send """
-      Hello #{msg.user.name}
+      Hello #{msg.envelope.user.name}

       This one's designation is: mozbot


Tests: Login: Login: Added loginFromSignupModal test.

--- client/test/lib/login/login.coffee
+++ client/test/lib/login/login.coffee
@@ -48,10 +48,12 @@

   loginFromHomepageSignupForm: (browser) ->
+
     user = utils.getUser()
     url  = helpers.getUrl()
-    browser.url(url)
-    browser.maximizeWindow()
+    browser
+      .url(url)
+      .maximizeWindow()

     helpers.attemptEnterEmailAndPasswordOnRegister(browser, user)

@@ -60,3 +62,21 @@
       .end()

+  loginFromSignupModal: (browser) ->
+
+    user = utils.getUser()
+    url  = helpers.getUrl()
+    browser
+      .url(url)
+      .maximizeWindow()
+
+    browser
+      .waitForElementVisible  '[testpath=main-header]', 50000
+      .click                  '#main-header [testpath=login-link]'
+      .waitForElementVisible  '[testpath=login-container]', 50000
+      .click                  '[testpath=login-container] a.register'
+      .setValue               '.main-part [testpath=register-form-email]', user.email
+      .setValue               '.main-part input[name=password]', user.password
+      .click                  '.main-part [testpath=signup-button]'
+      .waitForElementVisible  '[testpath=main-sidebar]', 10000 # Assertion
+      .end()


fix #125, fix #148

fix #125, fix #148

--- client/views/common/day/day.coffee
+++ client/views/common/day/day.coffee
@@ -17,7 +17,7 @@

 	'click #addShift': (e) ->
 		projectId = FlowRouter.getParam('projectId')
-		tagId = FlowRouter.getQueryParam('tagId') || FlowRouter.getQueryParam('showTags').split(',')[0]
+		tagId = FlowRouter.getQueryParam('tagId') || FlowRouter.getQueryParam('showTags').split('_')[0]
 		tagName = ''
 		date = $(e.target).closest('.day-wrapper').attr('date')
 		day = $(e.target).closest('.day-wrapper').attr('day')


Update glsl compilation of union using the changes to intersect and fix one or two bugs

--- src/compile.glsl.coffee
+++ src/compile.glsl.coffee
@@ -109,7 +109,7 @@
     if remainingHalfSpaces == 1
       # Find the axis (from 0 to 5) for the halfSpace node
       for index in [0..5] when state.hs[index] != null
-        state.codes.push (if index > 2 then "#{ro}[#{index}] - #{hs[index]}" else "-#{ro}[#{index - 3}] + #{state.hs[index]}")
+        state.codes.push (if index > 2 then "#{ro}[#{index - 3}] - #{state.hs[index]}" else "-#{ro}[#{index}] + #{state.hs[index]}")
         state.hs[index] = null
         break
       remainingHalfSpaces -= 1
@@ -154,37 +154,39 @@
       if node.nodes.length == 0
         mecha.logInternalError "GLSL Compiler: Union node is empty."
         return
-      node.code = ""
+      codes = []
+      codes.push childNode.code for childNode in node.nodes when childNode.code?

       # Some nodes are only modifiers, so it's necessary to collect their children
       # to apply the correct composite operation
-      collectChildren = (node, children) ->
-        for child in children
-          if child.code?
-            if node.code.length > 0
-              node.code = "min(#{childNode.code}, #{node.code})"
-            else
-              node.code = child.code
-          else switch child.type
+      collectCode = (codes, nodes) ->
+        for node in nodes
+          codes.push node.code if node.code?
+          switch node.type
             when 'translate','mirror','invert'
-              collectChildren node, child.nodes
-      collectChildren node, node.nodes
+              collectCode codes, node.nodes
+      collectCode codes, node.nodes

       # Corner compilation
       ro = flags.glslPrelude[flags.glslPrelude.length-1][0] # Current ray origin
-      if (node.halfSpaces[0] != null or node.halfSpaces[3] != null) and
-          (node.halfSpaces[1] != null or node.halfSpaces[4] != null) and
-          (node.halfSpaces[2] != null or node.halfSpaces[5] != null)
-        cornerSize = [
-          if node.halfSpaces[0] != null then node.halfSpaces[0] else node.halfSpaces[3],
-          if node.halfSpaces[1] != null then node.halfSpaces[1] else node.halfSpaces[4],
-          if node.halfSpaces[2] != null then node.halfSpaces[2] else node.halfSpaces[5]]
-        preludePush flags.glslPrelude, "#{ro} - vec3(#{cornerSize[0]}, #{cornerSize[1]}, #{cornerSize[2]})"
-        dist = preludePop flags.glslPrelude
-        if node.code.length > 0
-          node.code = "min(min(min(#{dist}.x, #{dist}.y), #{dist}.z), #{node.code});"
-        else
-          node.code = "min(min(#{dist}.x, #{dist}.y), #{dist}.z);"
+      cornersState =
+        codes: []
+        hs: node.halfSpaces.shallowClone()
+
+      # Compile the first and a possible second corner
+      compileCorner ro, flags, cornersState
+      compileCorner ro, flags, cornersState
+      codes = codes.concat cornersState.codes
+
+      # Post-condition: All halfspaces must be accounted for
+      for h in cornersState.hs when h != null
+        mecha.logInternalError "GLSL Compiler: Post-condition failed, some half spaces were not processed during corner compilation."
+        break
+
+      # Calculate the maximum distances
+      node.code = codes.shift()
+      for c in codes
+        node.code = "min(#{c}, #{node.code})"
       stack[0].nodes.push node
     intersect: (stack, node, flags) ->
       # Check that composite node is not empty


CLEANUP - better variable name

CLEANUP - better variable name

--- source/Art/Engine/FullScreenApp.coffee
+++ source/Art/Engine/FullScreenApp.coffee
@@ -44,13 +44,13 @@
     ConfigRegistry.configure config
     {fontFamilies} = config
     if isPlainObject fontFamilies
-      waitUntilFontsLoaded = fontFamilies
+      fontsToLoad = fontFamilies
       fontFamilies = Object.keys fontFamilies

     @writeDom merge config, {fontFamilies}
     @getDomReadyPromise()
     .then ->
-      FontLoader.allFontsLoaded waitUntilFontsLoaded if waitUntilFontsLoaded
+      FontLoader.allFontsLoaded fontsToLoad if fontsToLoad

   @writeDom: ({title, styleSheets, scripts, fontFamilies, meta, link, manifest})->


not always json

not always json

--- botart.coffee
+++ botart.coffee
@@ -14,6 +14,7 @@
 http   = require 'http'
 qs     = require 'querystring'
 env    = process.env
+

 #
 # robot brain
@@ -55,7 +56,12 @@
       response.on 'data', (chunk) ->
         data += chunk
       response.on 'end', ->
-        callback JSON.parse(data) if callback
+        if callback
+          try
+            body = JSON.parse(data)
+          catch e
+            body = data
+          callback body
     else
       console.log "#{response.statusCode}: #{path}"
       response.setEncoding('utf8')


CreateImage-node: Use onload/onerror callback APIs

Should fix a problem where sometimes the canvas is not
ready to be used after the .src attribute is set

--- components/CreateImage-node.coffee
+++ components/CreateImage-node.coffee
@@ -48,8 +48,11 @@
         if err
           return onError err
         img = new Image
+        img.onload = () ->
+          onLoad null, img
+        img.onerror = (err) ->
+          onError err, null
         img.src = image
-        onLoad(null, img)

     urlOptions = urlUtil.parse url
     if urlOptions.protocol


extract function

extract function

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -480,9 +480,8 @@
     @buffer(delay, schedule, schedule)

   bufferWithCount: (count) ->
-    @buffer(0,
-            (buffer) -> buffer.flush() if buffer.values.length == count
-    )
+    flushOnCount = (buffer) -> buffer.flush() if buffer.values.length == count
+    @buffer(0, flushOnCount)

   buffer: (delay, onInput = (->), onFlush = (->)) ->
     buffer = {


simplify

simplify

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -895,14 +895,12 @@
 class Source
   constructor: (s, @sync, consume, @subscribe) ->
     queue = []
-    isEnded = false
     @subscribe = s.subscribe if not @subscribe?
-    @markEnded = -> isEnded = true
-    @ended = -> isEnded
+    @markEnded = -> @ended = true
     if consume
       @consume = () -> queue.shift()
       @push  = (x) -> queue.push(x)
-      @mayHave = (c) -> !isEnded || queue.length >= c
+      @mayHave = (c) -> !@ended || queue.length >= c
       @hasAtLeast = (c) -> queue.length >= c
     else
       @consume = () -> queue[0]
@@ -947,7 +945,7 @@
       match = (p) ->
         _.all(p.ixs, (i) -> sources[i.index].hasAtLeast(i.count))
       cannotSync = (source) ->
-        !source.sync or source.ended()
+        !source.sync or source.ended
       cannotMatch = (p) ->
         _.any(p.ixs, (i) -> !sources[i.index].mayHave(i.count))
       part = (source, sourceIndex) -> (unsubAll) ->


[frontend] better logging when empty response is received

--- src/coffee/communication.coffee
+++ src/coffee/communication.coffee
@@ -17,7 +17,8 @@
         try
             module.extension.sendMessage request, (reply) ->
                     if not reply?
-                        module.log.error module.extension.getLastError() if module.extension.getLastError
+                        module.log.error 'Got empty response to', request
+                        module.log.error module.extension.getLastError() if module.extension.getLastError?()?
                         return

                     callback reply.reply if callback?


Fixed bug with HashFields not saving to the database (#148)

--- app/assets/javascripts/application/multi_field.js.coffee
+++ app/assets/javascripts/application/multi_field.js.coffee
@@ -170,14 +170,17 @@
     @options.renderer div, key, value
     key_field = div.find('[rel=key]')
     value_field = div.find('[rel=value]')
-    refreshName = =>
-      new_key = key_field.val()
+    refreshName = (locale) =>
+      new_key = key_field.val() || locale
       if new_key?.length > 0
         value_field.attr 'name', "#{this.name()}[#{new_key}]"
       else
         value_field.removeAttr 'name'
     key_field.keyup refreshName
     key_field.change refreshName
+    key_field.on 'typeahead:change', (evt, locale) =>
+      refreshName(locale)
+
     refreshName()

     remove = $('<a/>').addClass('fa fa-minus-circle').attr('href', '#').appendTo(div)


Add event handling, prevent default behaviour of anchor tags

--- app/assets/javascripts/controllers/submissions.js.coffee
+++ app/assets/javascripts/controllers/submissions.js.coffee
@@ -2,13 +2,27 @@
 window.App.successfulUploads  = [];

 $ ->
+  # Fetches the tree for the given url and places it in the treeview
   fetch_tree_for_path = (url) ->
-    alert("Fetching!")
-    success = (data) -> $("#tree-view").html(data)
-    $.get url, null, success, 'html'
+    internal_fetch = (url) ->
+      $("#tree-view").html("Loading...")
+      success = (data) -> $("#tree-view").html(data)
+      $.get url, null, success, 'html'
+
+    if $("#tree-view table")
+      $("#tree-view table").slideUp("slow", internal_fetch(url))
+    else
+      internal_fetch(url)
+
+
+  # Catch all clicks for node links in the tree view and send the to the tree-fetcher
   $("#tree-view").on("click",
     "#tree-view td.node a",
-    () -> fetch_tree_for_path($(this).data("url")))
+    (event) ->
+      event.preventDefault()
+      fetch_tree_for_path($(this).data("url")))
+
+  # Fetch the first tree
   fetch_tree_for_path("/repositories/test2/trees/master")


Set text to Installed when it succeeds

Set text to Installed when it succeeds

--- lib/package-install-view.coffee
+++ lib/package-install-view.coffee
@@ -28,6 +28,7 @@
           console.error("Installing #{@type} #{@pack.name} failed", error.stack ? error, error.stderr)
         else
           @setStatusIcon('check')
+          @installButton.text('Installed')

     @learnMoreButton.on 'click', =>
       shell.openExternal "https://www.atom.io/packages/#{@pack.name}"


implement UglifyJS processing in the cake compile task

--- library/nucleus/cakefile.coffee
+++ library/nucleus/cakefile.coffee
@@ -31,6 +31,7 @@

 _ = require "lodash"
 {minify} = require "uglify-js"
+{writeFileSync} = require "fs"
 {readdirSyncRecursive} = require "wrench"
 {rmdirSyncRecursive} = require "wrench"
 {spawn} = require "child_process"
@@ -103,19 +104,24 @@
         parameters.unshift "-w" if options.watch or false
         assert watching = "Watching the %s directory".blue
         logger.info watching, library.bold if options.watch
+        opts = mangle: no, compress: no, output: beautify: yes
+        optimize = (p) -> writeFileSync p, minify(p, opts).code
         assert _.isObject compiler = spawn "coffee", parameters
         assert _.isObject compiler.stdout.pipe process.stdout
         assert _.isObject compiler.stderr.pipe process.stderr
         assert _.isObject compiler.on "exit", (status) ->
             failure = "Failed to compile framework library"
             success = "Compiled framework library successfuly"
+            op = "Optimizing JavaScript module %s/%s".yellow
             produce = "Produce compiled artifact %s/%s".cyan
             return logger.error failure.red if status isnt 0
             assert s = (xstats) -> return xstats.isDirectory()
             isDirS = (d) -> (p) -> s fs.lstatSync("#{d}/#{p}")
             assert sources = try readdirSyncRecursive artifacts
             assert sources = _.reject sources, isDirS artifacts
+            o = (source) -> optimize("#{artifacts}/#{source}")
             logger.info produce, artifacts, s for s in sources
+            o s; logger.info op, artifacts, s for s in sources
             logger.info success.green if status is 0

     # This task launches an instance of application where this task


profilelink: update href attribute correctly

--- client/Main/CommonViews/linkviews/profilelinkview.coffee
+++ client/Main/CommonViews/linkviews/profilelinkview.coffee
@@ -31,12 +31,17 @@
       tagName   : 'span'

     @setClass "profile"
+    @updateHref()
+
+
+
+  updateHref: ->
+    nickname = @getData().profile?.nickname
+    @setAttribute "href", "/#{nickname}"  if nickname
+

   render: (fields) ->
-    nickname = @getData().profile?.nickname
-    slug = KD.getGroup()?.slug or 'koding'
-    href = if slug is "koding" then "/#{nickname}" else "/#{slug}/#{nickname}"
-    @setAttribute "href", href  if nickname
+    @updateHref()

     # only admin can see troll users
     if KD.checkFlag "super-admin"


home/myaccount: read correct password values from form

--- client/home/lib/account/homeaccountchangepassword.coffee
+++ client/home/lib/account/homeaccountchangepassword.coffee
@@ -52,10 +52,10 @@
     @changePasswordForm.addSubView @updatePasswordLink

-  update: (formData) ->
+  update: (event) ->

     { JUser } = remote.api
-    { password, confirmPassword, currentPassword } = formData
+    { password, confirmPassword, currentPassword } = @changePasswordForm.getData()
     skipConfirmation = no

     notify_ = (msg) ->


Call wrapped subscribe directly

Call wrapped subscribe directly

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -657,9 +657,11 @@
     assertFunction subscribe
     dispatcher = new Dispatcher(subscribe)
     @subscribeInternal = dispatcher.subscribe
-    @subscribe = UpdateBarrier.wrappedSubscribe(this)
     @hasSubscribers = dispatcher.hasSubscribers
     registerObs(this)
+
+  subscribe: (sink) ->
+    UpdateBarrier.wrappedSubscribe(this, sink)

   delay: (delay) ->
     withDescription(this, "delay", delay, @flatMap (value) ->
@@ -822,8 +824,10 @@
     else
       @subscribeInternal = new PropertyDispatcher(this, subscribe, handler).subscribe

-    @subscribe = UpdateBarrier.wrappedSubscribe(this)
     registerObs(this)
+
+  subscribe: (sink) ->
+    UpdateBarrier.wrappedSubscribe(this, sink)

   sampledBy: (sampler, combinator) ->
     if combinator?
@@ -831,8 +835,8 @@
     else
       lazy = true
       combinator = (f) -> f()
-    thisSource = new Source(this, false, @subscribeInternal, lazy)
-    samplerSource = new Source(sampler, true, sampler.subscribeInternal, lazy)
+    thisSource = new Source(this, false, lazy)
+    samplerSource = new Source(sampler, true, lazy)
     stream = Bacon.when([thisSource, samplerSource], combinator)
     result = if sampler instanceof Property then stream.toProperty() else stream
     withDescription(this, "sampledBy", sampler, combinator, result)
@@ -1411,7 +1415,7 @@

   currentEventId = -> if rootEvent then rootEvent.id else undefined

-  wrappedSubscribe = (obs) -> (sink) ->
+  wrappedSubscribe = (obs, sink) ->
     unsubd = false
     doUnsub = ->
     unsub = ->


refactored to only use one getInCenter method

--- src/Board.coffee
+++ src/Board.coffee
@@ -54,23 +54,11 @@

 	_drawTitle: ->
 		@_drawBlankLine()
-		@_drawTextInCenter config.title
+		console.log config.border[config.colors.border] + @_getLineTextInCenter(@width - 2, config.title, config.colors.title) + config.border[config.colors.border]
 		@_drawBlankLine()

 	_drawBlankLine: ->
 		console.log config.border[config.colors.border] + @_repeatText(@width - 2, ' ') + config.border[config.colors.border]
-
-	_drawTextInCenter: (content) ->
-		halfSpace = (@width - 2 - content.length) / 2
-
-		if halfSpace.toString().indexOf('.') > 0
-			beginningSpace = Math.floor(halfSpace)
-			endSpace       = Math.floor(halfSpace) + 1
-		else
-			beginningSpace = halfSpace
-			endSpace       = halfSpace
-
-		console.log config.border[config.colors.border] + @_repeatText(beginningSpace, ' ') + content[config.colors.title] + @_repeatText(endSpace, ' ') + config.border[config.colors.border]

 	_drawLine: (line) ->
 		unless @data? then return @_drawBlankLine()
@@ -104,12 +92,9 @@
 				text += pad space, '', ' '
 				text += pad '', space, ' '

-		text = config.border[config.colors.border] + text.substring(1, text.length)     # add the beginning border
-		text = text.substring(0, text.length - 1) + config.border[config.colors.border] # add the end border
+		console.log config.border[config.colors.border] + text + config.border[config.colors.border]

-		console.log text
-
-	_getLineTextInCenter: (width, content) ->
+	_getLineTextInCenter: (width, content, color) ->
 		halfSpace = (width - content.length) / 2

 		if halfSpace.toString().indexOf('.') > 0
@@ -119,7 +104,10 @@
 			beginningSpace = halfSpace
 			endSpace       = halfSpace

-		return @_repeatText(beginningSpace, ' ') + content + @_repeatText(endSpace, ' ')
+		if color?
+			return @_repeatText(beginningSpace, ' ') + content[color] + @_repeatText(endSpace, ' ')
+		else
+			return @_repeatText(beginningSpace, ' ') + content + @_repeatText(endSpace, ' ')

 	_repeatText: (num, char) ->
 		new Array(num + 1).join(char) # + 1 accounts for the 0 based array


add daily rates to resolved event api result

--- server/router.coffee
+++ server/router.coffee
@@ -441,41 +441,42 @@
         prevTotal = countryCodeToCount[topLocation.countryCode] or 0
         countryCodeToCount[topLocation.countryCode] = prevTotal + locationToTotals[topLocation.id]

-      if (@request.query.activeCases + "").toLowerCase() == "true"
-        console.time('compute active cases for overall timeseries') if ENABLE_PROFILING
-        overallTimeseries = subIntervalsToActiveCases(
-          maxSubintervalsForTopLocations,
-          dailyDecayRate,
-          dateWindow
-        )
-        console.timeEnd('compute active cases for overall timeseries') if ENABLE_PROFILING
-      else
-        overallTimeseries = _.chain(maxSubintervalsForTopLocations)
-          .groupBy('end')
-          .pairs()
-          .map ([end, group]) -> [new Date(parseInt(end)), group]
-          .sortBy (x) -> x[0]
-          .reduce((sofar, [endDate, group]) ->
-            value = group.reduce(((sofar, cur) -> sofar + cur.rate), 0)
-            if sofar
-              sofar.concat(
-                date: endDate
-                value: value
-              )
-            else
-              [
-                date: new Date(group[0].start)
-                value: value
-              ,
-                date: endDate
-                value: value
-              ]
-          , null)
-          .value()
+      console.time('compute active cases for overall timeseries') if ENABLE_PROFILING
+      overallTimeseries = subIntervalsToActiveCases(
+        maxSubintervalsForTopLocations,
+        dailyDecayRate,
+        dateWindow
+      )
+      console.timeEnd('compute active cases for overall timeseries') if ENABLE_PROFILING
+      dailyRateTimeseries = _.chain(maxSubintervalsForTopLocations)
+        .groupBy('end')
+        .pairs()
+        .map ([end, group]) -> [new Date(parseInt(end)), group]
+        .sortBy (x) -> x[0]
+        .reduce((sofar, [endDate, group]) ->
+          value = group.reduce(((sofar, cur) -> sofar + cur.rate), 0)
+          if sofar
+            sofar.concat(
+              date: endDate
+              value: value
+            )
+          else
+            [
+              date: new Date(group[0].start)
+              value: value
+            ,
+              date: endDate
+              value: value
+            ]
+        , null)
+        .filter ({date, value}) ->
+          date >= new Date(dateWindow.startDate)
+        .value()
       result = {
         eventId: event._id
         eventName: event.eventName
         timeseries: overallTimeseries
+        dailyRateTimeseries: dailyRateTimeseries
       }
       if (@request.query.fullLocations + "").toLowerCase() == "true"
         result.fullLocations = locationTree.toJSON ({value, children}) ->


Remove imports that are no longer included or used

--- server/server.coffee
+++ server/server.coffee
@@ -6,12 +6,10 @@
 bodyParser = require 'body-parser'

 mongoose = require 'mongoose'
-Grid = require 'gridfs-stream'
 express = require 'express'
 compressible = require 'compressible'
 path = require 'path'
 useragent = require 'express-useragent'
-fs = require 'graceful-fs'
 http = require 'http'

 config = require './server-config'


Added PosX, PosY, Width, and Height for the new Element enhancements

--- FluentAutomation.PhantomJS/PhantomDriver.coffee
+++ FluentAutomation.PhantomJS/PhantomDriver.coffee
@@ -58,20 +58,42 @@
 				return results

 			elem = $('SELECTOR')
+
 			if elem.length == 1
-				return { Selector: 'SELECTOR', Html: elem.html(), Attributes: parseAttributes(elem[0]), Value: elem.val(), Text: elem.text(), TagName: elem[0].tagName }
+				result =
+					Selector: 'SELECTOR'
+					Html: elem.html()
+					Attributes: parseAttributes elem[0]
+					Value: elem.val()
+					Text: elem.text()
+					TagName: elem[0].tagName
+					PosX: elem.offset().left
+					PosY: elem.offset().top
+					Width: elem.width()
+					Height: elem.height()
+
 			else if elem.length == 0
-				return null
+				result = null
+
 			else
 				result = []
 				for el in elem
 					$el = $(el)
-					result.push { Selector: 'SELECTOR', Html: $el.html(), Attributes: parseAttributes( el ), Value: $el.val(), Text: $el.text(), TagName: el.tagName }
-				return result
+					result.push
+						Selector: 'SELECTOR'
+						Html: $el.html()
+						Attributes: parseAttributes el
+						Value: $el.val()
+						Text: $el.text()
+						TagName: el.tagName
+						PosX: $el.offset().left
+						PosY: $el.offset().top
+						Width: $el.width()
+						Height: $el.height()
+			return result

 		fnStr = fn.toString().replace(/SELECTOR/g, selector)
 		evalResult = page.evaluate fnStr
-
 		@owner.socket.send JSON.stringify({ Response: "ActionCompleted", Result: evalResult })

 	FindMultiple: (command) ->


Note on XP quirk

Note on XP quirk

--- src/objects/remote.proto.coffee
+++ src/objects/remote.proto.coffee
@@ -25,6 +25,7 @@
   v = ver self
   extract2 = folder cache, v
   .rm true
+  # Error in XP: correct syntax is: TARGETDIR="path/to/msi"
   run 1, true, 'msiexec', '/a', msi(self, true), "TARGETDIR=#{extract2}", '/passive'
   self.dst = dst = folder install2, v
   .rm true


Add fancy scrolling feature

Add fancy scrolling feature

--- shepherd.coffee
+++ shepherd.coffee
@@ -143,18 +143,23 @@
     @on 'destroy', ->
       removeEventListener document.body, event, handler

+  getAttachTo: ->
+    opts = parseShorthand @options.attachTo, ['element', 'on']
+    opts ?= {}
+
+    if typeof opts.element is 'string'
+      opts.element = document.querySelector opts.element
+
+      if not opts.element?
+        throw new Error "Shepherd step's attachTo was not found in the page"
+
+    opts
+
   setupTether: ->
     if not Tether?
       throw new Error "Using the attachment feature of Shepherd requires the Tether library"

-    opts = parseShorthand @options.attachTo, ['element', 'on']
-    opts ?= {}
-
-    if typeof opts.element is 'string'
-      opts.element = document.querySelector opts.element
-
-      if not opts.element?
-        throw new Error "Shepherd step's attachTo was not found in the page"
+    opts = @getAttachTo()

     attachment = ATTACHMENT[opts.on or 'right']
     if not opts.element?
@@ -177,6 +182,10 @@

     @tether?.enable()

+    if @options.scrollTo
+      setTimeout =>
+        @scrollTo()
+
     @trigger 'show'

   hide: =>
@@ -195,6 +204,25 @@
     @hide()

     @trigger 'complete'
+
+  scrollTo: =>
+    {element} = @getAttachTo()
+    return unless element?
+
+    $attachTo = jQuery element
+
+    {top, left} = $attachTo.offset()
+    height = $attachTo.outerHeight()
+
+    offset = $(@el).offset()
+    elTop = offset.top
+    elLeft = offset.left
+    elHeight = $(@el).outerHeight()
+
+    if top < pageYOffset or elTop < pageYOffset
+      jQuery(document.body).scrollTop(Math.min(top, elTop) - 10)
+    else if (top + height) > (pageYOffset + innerHeight) or (elTop + elHeight) > (pageYOffset + innerHeight)
+      jQuery(document.body).scrollTop(Math.max(top + height, elTop + elHeight) - innerHeight + 10)

   destroy: =>
     if @el?
@@ -326,6 +354,7 @@
 tour = new Tour
   defaults:
     classes: 'drop drop-open drop-theme-arrows'
+    scrollTo: true

 tour.addStep 'start',
   title: "Welcome to KaPow!"


Remove overshoot from ROI paths

Remove overshoot from ROI paths

--- show-roi.coffee
+++ show-roi.coffee
@@ -33,8 +33,8 @@

     nestingOutline = classifyPage.subjectViewer.markingSurface.addShape 'path.nesting-area',
       d: """
-        M -10 -10 L #{width + 10} -10 L #{width + 10} #{height + 10} L -10 #{height + 10}
-        L -10 -10
+        M 0 0 L #{width + 0} 0 L #{width + 0} #{height + 0} L 0 #{height + 0}
+        L 0 0

         M #{nestingPoints[0][0] / scaleX}, #{nestingPoints[0][1] / scaleY}
         #{("L #{[x / scaleX, y / scaleY]}" for [x, y] in nestingPoints[1...]).join '\n'}


Use inlined context menu from package.json when available

--- src/context-menu-manager.coffee
+++ src/context-menu-manager.coffee
@@ -7,6 +7,11 @@
 Grim = require 'grim'
 MenuHelpers = require './menu-helpers'
 {validateSelector} = require './selector-validator'
+
+try
+  platformContextMenu = require('../package.json')?._atomMenu?['context-menu']
+catch error
+  platformContextMenu = null

 SpecificityCache = {}

@@ -49,10 +54,13 @@
     atom.keymaps.onDidLoadBundledKeymaps => @loadPlatformItems()

   loadPlatformItems: ->
-    menusDirPath = path.join(@resourcePath, 'menus')
-    platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json'])
-    map = CSON.readFileSync(platformMenuPath)
-    atom.contextMenu.add(map['context-menu'])
+    if platformContextMenu?
+      @add(platformContextMenu)
+    else
+      menusDirPath = path.join(@resourcePath, 'menus')
+      platformMenuPath = fs.resolve(menusDirPath, process.platform, ['cson', 'json'])
+      map = CSON.readFileSync(platformMenuPath)
+      @add(map['context-menu'])

   # Public: Add context menu items scoped by CSS selectors.
   #


:memo: Convert ContextMenuManager docs

:memo: Convert ContextMenuManager docs

--- src/context-menu-manager.coffee
+++ src/context-menu-manager.coffee
@@ -22,15 +22,13 @@
     ]

   # Public: Creates menu definitions from the object specified by the menu
-  # cson API.
+  # JSON API.
   #
-  # name - The path of the file that contains the menu definitions.
-  # object - The 'context-menu' object specified in the menu cson API.
-  # options - An {Object} with the following keys:
-  #   :devMode - Determines whether the entries should only be shown when
-  #              the window is in dev mode.
-  #
-  # Returns nothing.
+  # * `name` The path of the file that contains the menu definitions.
+  # * `object` The 'context-menu' object specified in the menu JSON API.
+  # * `options` An optional {Object} with the following keys:
+  #   * `devMode` Determines whether the entries should only be shown when
+  #               the window is in dev mode.
   add: (name, object, {devMode}={}) ->
     for selector, items of object
       for label, commandOrSubmenu of items
@@ -43,6 +41,8 @@
           menuItem = @buildMenuItem(label, commandOrSubmenu)
           @addBySelector(selector, menuItem, {devMode})

+    undefined
+
   buildMenuItem: (label, command) ->
     if command is '-'
       {type: 'separator'}
@@ -52,12 +52,12 @@
   # Registers a command to be displayed when the relevant item is right
   # clicked.
   #
-  # selector - The css selector for the active element which should include
-  #            the given command in its context menu.
-  # definition - The object containing keys which match the menu template API.
-  # options - An {Object} with the following keys:
-  #   :devMode - Indicates whether this command should only appear while the
-  #              editor is in dev mode.
+  # * `selector` The css selector for the active element which should include
+  #              the given command in its context menu.
+  # * `definition` The object containing keys which match the menu template API.
+  # * `options` An optional {Object} with the following keys:
+  #   * `devMode` Indicates whether this command should only appear while the
+  #               editor is in dev mode.
   addBySelector: (selector, definition, {devMode}={}) ->
     definitions = if devMode then @devModeDefinitions else @definitions
     if not _.findWhere(definitions[selector], definition) or _.isEqual(definition, {type: 'separator'})
@@ -79,7 +79,7 @@
   # active element are listed first. The further down the list you go, the higher
   # up the ancestor hierarchy they match.
   #
-  # element - The DOM element to generate the menu template for.
+  # * `element` The DOM element to generate the menu template for.
   menuTemplateForMostSpecificElement: (element, {devMode}={}) ->
     menuTemplate = @definitionsForElement(element, {devMode})
     if element.parentElement
@@ -109,9 +109,12 @@
       delete template.executeAtBuild

   # Public: Request a context menu to be displayed.
+  #
+  # * `event` A DOM event.
   showForEvent: (event) ->
     @activeElement = event.target
     menuTemplate = @combinedMenuTemplateForElement(event.target)
     return unless menuTemplate?.length > 0
     @executeBuildHandlers(event, menuTemplate)
     remote.getCurrentWindow().emit('context-menu', menuTemplate)
+    undefined


PUBDEV-2204 Allow converting string columns to enum columns.

--- src/ext/modules/routines.coffee
+++ src/ext/modules/routines.coffee
@@ -699,7 +699,7 @@
       switch type
         when 'enum'
           "Convert to numeric"
-        when 'int'
+        when 'int', 'string'
           "Convert to enum"
         else
           undefined


Iphone pinch2

Iphone pinch2

--- site/app.coffee
+++ site/app.coffee
@@ -224,10 +224,10 @@
         $("#button_view_#{name} i").addClass('fa-dot-circle-o')
         @setLocations(locations)
     pinch = (e) =>
-      if e.scale < 1.0
-        zoomOut(1+(1-e.scale))
+      if e.originalEvent.scale < 1.0
+        zoomOut(1+(1-e.originalEvent.scale))
       else
-        zoomIn(e.scale)
+        zoomIn(e.originalEvent.scale)
     $('#button_view_nat').click(clicker('nat', NATIONAL))
     $('#button_view_hhs').click(clicker('hhs', HHS_REGIONS))
     $('#button_view_cen').click(clicker('cen', CENSUS_REGIONS))


updated success callback for Offline.Sync.full method

--- src/backbone_offline.coffee
+++ src/backbone_offline.coffee
@@ -218,7 +218,7 @@
     # 2. load new data
     full: (options = {}) ->
       @ajax 'read', @collection.items, _.extend {}, options,
-        success: (model, response, opts) =>
+        success: (response, status, xhr) =>
           @storage.clear()
           @collection.items.reset([], silent: true)
           @collection.items.create(item, silent: true, local: true, regenerateId: true) for item in response


Scopes the error handler with the component

--- src/client/component.coffee
+++ src/client/component.coffee
@@ -119,6 +119,7 @@
             ds = @datasources[k]
             ds.parse(_.extend({}, @, @options || {}))
             handler = @["on#{_.string.capitalize(_.string.camelize(k))}Error"]
+            handler = _.bind(handler, @) if _.isFunction(handler)
             ctx.addDatasource(k, ds.fetch(), handler).then (res)=>
               @data[k] = res
           componentDeferred = @sandbox.data.when.apply(undefined, promiseArray)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -51,23 +51,23 @@

     I.velocity = I.velocity.scale(I.speed)

-    movement: () ->
-      p = Point(0, 0)
+  movement: () ->
+    p = Point(0, 0)

-      if keydown.left
-        p.x = -1
+    if keydown.left
+      p.x = -1

-      if keydown.right
-        p.x = 1
+    if keydown.right
+      p.x = 1

-      if keydown.up
-        p.y = -1
+    if keydown.up
+      p.y = -1

-      if keydown.down
-        p.y = 1
+    if keydown.down
+      p.y = 1

-      p = p.norm()
+    p = p.norm()

-      I.velocity = p.scale(I.speed)
-      unless p.equal(Point.ZERO)
-        I.facing = p+    I.velocity = p.scale(I.speed)
+    unless p.equal(Point.ZERO)
+      I.facing = p


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -1,5 +1,5 @@
 Controllable = (I={}) ->
-  # Set some default properties
+
   Object.reverseMerge I,
     speed: 1


refactoring testimonials, updating tour page

--- @client/shared.coffee
+++ @client/shared.coffee
@@ -120,7 +120,8 @@
   _.extend offset,
     cx: offset.left + rect.width / 2
     cy: offset.top + rect.height / 2
-
+    right: offset.left + rect.width
+    bottom: offset.top + rect.height

 #### browser
@@ -242,7 +243,6 @@
   if subdomain.name == 'homepage'
     subdomain = fetch("/subdomain/#{proposal.subdomain_id}")
     result = "https://#{subdomain.host_with_port}" + result
-    console.log result

   if TWO_COL() || (!customization('show_crafting_page_first', proposal) || !proposal.active ) \
      || (!customization('discussion_enabled', proposal))


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -886,16 +886,28 @@

     @returns {Color|Number} returns the color object if you pass a new saturation value and returns the saturation otherwise
     ###
-    saturation: (newVal) ->
-      hsl = @toHsl()
-      if newVal?
-        hsl[1] = newVal
-
-        [@r, @g, @b, @a] = hslToRgb(hsl)
-
-        return this
+    saturation: (newVal, mode) ->
+      if mode == 'hsv'
+        hsv = @toHsv()
+        if newVal?
+          hsv[1] = newVal
+
+          [@r, @g, @b, @a] = hsvToRgb(hsv)
+
+          return this
+        else
+          return hsv[1]
+
       else
-        return hsl[1]
+        hsl = @toHsl()
+        if newVal?
+          hsl[1] = newVal
+
+          [@r, @g, @b, @a] = hslToRgb(hsl)
+
+          return this
+        else
+          return hsl[1]

     ###*
     returns the Hex representation of the color. Exclude the leading `#` by passing false.


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -1674,8 +1674,5 @@
   ]

   names.each (element) ->
-    lookup[normalizeKey(element[1])] = parseHex(element[0])
-
-  color = Color('rgba(34,54,32,1)')
-  console.log color.rgba()
+    lookup[normalizeKey(element[1])] = parseHex(element[0])
 )()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -14,7 +14,7 @@
       bits[1]
       bits[2]
       bits[3]
-      bits[4] || 0
+      bits[4] || 1
     ]

   window.Color = (color) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -45,7 +45,7 @@
           other.channels.a = channels.a

       rgba: ->
-        return "rgba(#{channels.r}, #{channels.g}, #{channels.b}, #{channels.a})"
+        return "rgba(#{channels[0]}, #{channels[1]}, #{channels[2]}, #{channels[3]})"

       toString: ->
         return (if channels.a == 1 then toHex([channels.r, channels.g, channels.b]) else self.rgba())


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/color.coffee
+++ src/color.coffee
@@ -14,19 +14,18 @@

   parseHex = (hexString) ->
     hexString = hexString.replace(/#/, '')
+
+    bits = rgbParser.exec(hexString)

-    case hexString.length
-      when 3 then #something
-      when 4 then #something
-      when 6
-        bits = rgbParser.exec(hexString)
+    switch hexString.length
+      when 3, 4 then #something
+      else
         return [
-          bits[1]
-          bits[2]
-          bits[3]
-          1.0
+          parseInt(hexString.substr(0, 2), 16)
+          parseInt(hexString.substr(2, 2), 16)
+          parseInt(hexString.substr(4, 2), 16)
+          if bits[4]? then bits[4] else 1.0
         ]
-      when 8 then #something

   parseRGB = (colorString) ->
     bits = rgbParser.exec(colorString)
@@ -34,7 +33,7 @@
       bits[1]
       bits[2]
       bits[3]
-      if bits[4]? then bits[4] else 1
+      if bits[4]? then bits[4] else 1.0
     ]

   window.Color = (color) ->


gratuitous change?

gratuitous change?

--- src/docco.coffee
+++ src/docco.coffee
@@ -162,8 +162,8 @@
   'docs/' + path.basename(filepath, path.extname(filepath)) + '.html'

 # Ensure that the destination directory exists.
-ensure_directory = (callback) ->
-  exec 'mkdir -p docs', -> callback()
+ensure_directory = (dir, callback) ->
+  exec "mkdir -p #{dir}", -> callback()

 # Micro-templating, originally by John Resig, borrowed by way of
 # [Underscore.js](http://documentcloud.github.com/underscore/).
@@ -196,7 +196,7 @@
 # For each source file passed in as an argument, generate the documentation.
 sources = process.ARGV.sort()
 if sources.length
-  ensure_directory ->
+  ensure_directory 'docs', ->
     fs.writeFile 'docs/docco.css', docco_styles
     files = sources.slice(0)
     next_file = -> generate_documentation files.shift(), next_file if files.length


fetcher: get symbol tables

fetcher: get symbol tables

--- src/fetch.coffee
+++ src/fetch.coffee
@@ -1,16 +1,66 @@
 # fetch files from sfdc

-force = require '../lib/force-0.1.0.min.js'
+promise = require 'node-promise'
+force = require '../lib/force-0.1.0.js'

 class Fetcher
   constructor: (creds, cb) ->
     that = @
+    that.containerName = "f#{new Date().getTime()}"
+    that.containerName = that.containerName.substr 0, 8
     force.connect( creds ).then (conn) ->
       that.conn = conn
       cb()

   getClasses: (cb) ->
-    @conn.query('SELECT Name, Body FROM ApexClass').then cb
+    @conn.query('SELECT Id, Name, Body FROM ApexClass').then cb
+
+  createContainer: ->
+    that = @
+    @conn.tooling.insert('MetadataContainer', {
+      'Name': @containerName
+    }).then (id) -> that.setContainerId id
+
+  setContainerId: (id) ->
+    throw "unable to create!" unless id?
+    console.error id
+    @containerId = id
+    console.error @containerId
+
+  createJunction: (cls) ->
+    console.error @containerId
+    @conn.tooling.insert('ApexClassMember', {
+      'MetadataContainerId': @containerId
+      'ContentEntityId': cls.Id
+      'Body': cls.Body
+    }).then (id) -> throw "unable to create junction" unless id?
+
+  createJunctions: (classes) ->
+#    promise.allOrNone (@createJunction cls for cls in classes)
+    console.error @containerId
+    junctions = []
+    for cls in classes
+      junctions.push @createJunction cls
+    promise.allOrNone junctions
+
+  validateContainer: ->
+    @conn.tooling.deploy @containerId, yes
+
+  queryContainer: ->
+    @conn.tooling.query "SELECT Id, SymbolTable FROM ApexClassMember WHERE MetadataContainerId = '#{@containerId}'"
+
+  deleteContainer: ->
+    @conn.tooling.destroy 'MetadataContainer', @containerId
+
+  getSymbolTables: (cb) ->
+    that = @
+    @getClasses (classes) ->
+      that.createContainer()
+        .then(-> console.error that.containerId; that.createJunctions classes)
+        .then(-> that.validateContainer())
+        .then(-> that.queryContainer())
+        .then (symbolTables) ->
+          that.deleteContainer().then -> cb symbolTables

 module.exports = (creds, cb) ->
   new Fetcher creds, cb


fixed a syntax error

fixed a syntax error


Fix MAM for pusher component

Fix MAM for pusher component

--- src/local/model_postgres.coffee
+++ src/local/model_postgres.coffee
@@ -702,7 +702,7 @@
         db = @db
         if forPusher
             params = []
-            listenercond = ""
+            listenerCond = ""
         else
             params = [listener]
             listenerCond = "AND listener=$1"


add log message

add log message

--- src/alias.coffee
+++ src/alias.coffee
@@ -24,6 +24,7 @@
   config = process.env.HUBOT_GROUP_ALIAS

   if !config
+    console.log "Warning: Configuration HUBOT_GROUP_ALIAS is not defined."
     return

   groups = config.split(';')


Setup watch

Setup watch


Use the instance variable to ensure sort is not executed multiply.

--- bokehjs/src/coffee/models/transforms/interpolator.coffee
+++ bokehjs/src/coffee/models/transforms/interpolator.coffee
@@ -33,7 +33,7 @@
       return

     # Stop processing this if the dirty flag is not set
-    if(_sorted_dirty == false)
+    if(@_sorted_dirty == false)
       return

     data = @get('data')
@@ -60,7 +60,7 @@
       @_x_sorted[k] = list[k].x;
       @_y_sorted[k] = list[k].y;

-    _sorted_dirty = false
+    @_sorted_dirty = false

 module.exports =
   Model: Interpolator


archived periods need to be ignored, otherwise trying to check for validity gets confused because it tries to validing the tasking for the archived period as well

--- src/flux/tasking.coffee
+++ src/flux/tasking.coffee
@@ -31,6 +31,9 @@
   {periods, id} = course

   courseDefaults = _.chain(periods)
+    .reject((period) ->
+      period.is_archived
+    )
     .indexBy((period) ->
       "period#{period.id}"
     )


a mistake in array.coffee: .toArray -> .toArray()

--- src/array.coffee
+++ src/array.coffee
@@ -135,7 +135,7 @@
       if !⍴⍴ @ then return @data[@offset]
       if ⍴(@)[0] is 0 then return ''
       if @stride[0] is 1 then return @data[@offset ... @offset + @shape[0]]
-      @toArray.join ''
+      @toArray().join ''
     else
       a = @toArray()
       for x in a when typeof x isnt 'string' then domainError()