Environments: RulesContainer: Promise implemented for loadItems

--- client/Environments/views/scene/environmentrulecontainer.coffee
+++ client/Environments/views/scene/environmentrulecontainer.coffee
@@ -19,5 +19,6 @@
       }
     ]

-    @addItem rule for rule in dummyRules
-    @emit "DataLoaded"
+    new Promise (resolve, reject)=>
+      @addItem rule for rule in dummyRules
+      resolve()


Remove the fix which has no-sense at all.

--- client/landing/app/MainApp/maincontroller/maincontroller.coffee
+++ client/landing/app/MainApp/maincontroller/maincontroller.coffee
@@ -41,17 +41,6 @@

     appManager.create 'Groups', (groupsController)->
       KD.registerSingleton "groupsController", groupsController
-      groupsController.once 'GroupChanged', =>
-        # temp hot fix for a default vm creation - SY
-        group = groupsController.getCurrentGroup()
-        group.createVM
-          type     : 'user'
-          planCode : 'free'
-        , (err)->
-          unless err
-            KD.getSingleton('vmController').emit 'VMListChanged'
-            log "default vm created"
-

     appManager.create 'Chat', (chatController)->
       KD.registerSingleton "chatController", chatController


small refactoring on window controller

small refactoring on window controller

--- client/landing/app/MainApp/maincontroller/maincontroller.coffee
+++ client/landing/app/MainApp/maincontroller/maincontroller.coffee
@@ -31,6 +31,7 @@
   createSingletons:->

     KD.registerSingleton "mainController",            this
+    KD.registerSingleton "windowController",          new KDWindowController
     KD.registerSingleton "appManager",   appManager = new ApplicationManager
     KD.registerSingleton "kiteController",            new KiteController
     KD.registerSingleton "vmController",              new VirtualizationController


Used @cwd.

Used @cwd.

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -78,9 +78,8 @@
     pythonPath = pythonPath.split sep
     pythonPath = pythonPath.filter(Boolean)

-    editor_path = path.dirname(@editor.getPath())
-    if editor_path and editor_path not in pythonPath
-      pythonPath.push editor_path
+    if @cwd and @cwd not in pythonPath
+      pythonPath.push @cwd

     process_path = process.env.PWD
     if process_path and process_path not in pythonPath


JMachine:fetchOwner: fix position of private instance methods, make it error prone

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -378,6 +378,16 @@
         callback new KodingError "Target does not support machines."

+  fetchOwner: (callback) ->
+
+    owner = user for user in @users when user.owner and user.sudo
+    err   = -> callback new KodingError 'Owner user not found'
+    return err()  unless owner
+
+    JUser.one _id: owner.id, (err, user) ->
+      return err()  if err or not user
+      user.fetchOwnAccount callback
+

   # Shared Methods
   # --------------
@@ -679,14 +689,3 @@

     @shareWith options, (err)->
       callback err
-
-
-  fetchOwner: (callback) ->
-
-    owner = user for user in @users when user.owner and user.sudo
-
-    JUser.one _id: owner.id, (err, user) ->
-
-      return callback 'Owner user not found'  unless user
-
-      user.fetchOwnAccount callback


Always respect current-selection over existing marker

--- lib/mutation-tracker.coffee
+++ lib/mutation-tracker.coffee
@@ -2,7 +2,6 @@
 swrap = require './selection-wrapper'

 # keep mutation snapshot necessary for Operator processing.
-
 # mutation stored by each Selection have following field
 #  marker:
 #    marker to track mutation. marker is created when `setCheckPoint`
@@ -51,15 +50,10 @@
   setCheckPoint: (checkPoint) ->
     for selection in @editor.getSelections()
       unless @mutationsBySelection.has(selection)
-        initialPoint =
-        options = {
-          selection: selection,
-          initialPoint: @saveInitialPointForSelection(selection)
-          createdAt: checkPoint
-          markerLayer: @markerLayer
-        }
+        createdAt = checkPoint
+        initialPoint = @saveInitialPointForSelection(selection)
+        options = {selection, initialPoint, createdAt, @markerLayer}
         @mutationsBySelection.set(selection, new Mutation(options))
-
       mutation = @mutationsBySelection.get(selection)
       mutation.update(checkPoint)

@@ -114,14 +108,13 @@
     @marker = null

   update: (checkPoint) ->
-    # If marker range was empty and we have non-empty seleciton, we re-track that selection
-    # by invalidating old marker.
-    if @marker?.getBufferRange().isEmpty() and not @selection.getBufferRange().isEmpty()
-      @marker.destroy()
+    # Current non-empty selection is prioritized over marker's range.
+    # We ivalidate old marker to re-track from current selection.
+    unless @selection.getBufferRange().isEmpty()
+      @marker?.destroy()
       @marker = null

     @marker ?= @markerLayer.markBufferRange(@selection.getBufferRange(), invalidate: 'never')
-
     @checkPoint[checkPoint] = @marker.getBufferRange()

   getMutationEnd: ->


[FIX] Empty lines are gone

[FIX] Empty lines are gone

--- src/Moon.coffee
+++ src/Moon.coffee
@@ -94,5 +94,4 @@

         else
             Moon.pt._step = -1
-            Moon.pt._callback() if Moon.pt._callback?
-
+            Moon.pt._callback() if Moon.pt._callback?


Added 2D transforms support

Added 2D transforms support

--- src/Node.coffee
+++ src/Node.coffee
@@ -71,7 +71,7 @@
       else
         throw 'DivSugar: Invalid number of arguments'

-    @div.style[DivSugar._cssTransform] = @_transform.toCSSTransform()
+    @div.style[DivSugar._cssTransform] = @_transform._toCSSTransform()
     return @

   getTransform: (mat) ->
@@ -80,7 +80,7 @@

   setTransform: (mat) ->
     @_transform.set mat
-    @div.style[DivSugar._cssTransform] = @_transform.toCSSTransform()
+    @div.style[DivSugar._cssTransform] = @_transform._toCSSTransform()
     return @

   getVisible: DivSugar.Scene.prototype.getVisible
@@ -113,7 +113,7 @@
       throw 'DivSugar: Invalid number of arguments'

     @_transform.translate offsetX, offsetY, offsetZ
-    @div.style[DivSugar._cssTransform] = @_transform.toCSSTransform()
+    @div.style[DivSugar._cssTransform] = @_transform._toCSSTransform()
     return @

   rotate: (rotateX, rotateY, rotateZ) ->
@@ -121,7 +121,7 @@
       throw 'DivSugar: Invalid number of arguments'

     @_transform.rotate rotateX, rotateY, rotateZ
-    @div.style[DivSugar._cssTransform] = @_transform.toCSSTransform()
+    @div.style[DivSugar._cssTransform] = @_transform._toCSSTransform()
     return @

   scale: (scaleX, scaleY, scaleZ) ->
@@ -129,7 +129,7 @@
       throw 'DivSugar: Invalid number of arguments'

     @_transform.scale scaleX, scaleY, scaleZ
-    @div.style[DivSugar._cssTransform] = @_transform.toCSSTransform()
+    @div.style[DivSugar._cssTransform] = @_transform._toCSSTransform()
     return @

   playAnimation: (animation) ->


added console log

added console log

--- tentacle.coffee
+++ tentacle.coffee
@@ -10,6 +10,7 @@
     @tentacleConnection = tentacleConnection

   start: =>
+    console.log 'start called'
     @meshbluConn = Meshblu.createConnection meshbluJSON
     @meshbluConn.on 'ready',  @onMeshbluReady
     @meshbluConn.on 'message', @onMeshbluMessage


Can do

Can do

--- components/blocks/container/client/block_collection_view.coffee
+++ components/blocks/container/client/block_collection_view.coffee
@@ -1,6 +1,6 @@
 Backbone = require 'backbone'
 { defer, each, delay } = require 'underscore'
-{ API_URL } = require('sharify').data
+{ API_URL, CAN } = require('sharify').data
 mediator = require '../../../../lib/mediator.coffee'
 InfiniteView = require '../../../pagination/infinite_view.coffee'
 SkeletonView = require '../../../pagination/skeleton_view.coffee'
@@ -82,6 +82,7 @@
       user: mediator.shared.current_user
       channel: @channel
       isSearching: @isSearching()
+      can: CAN

     defer (=> @postRender())


move arrow for blocks panel

move arrow for blocks panel

--- BackofficeBundle/Resources/public/coffee/page/makeSortable.coffee
+++ BackofficeBundle/Resources/public/coffee/page/makeSortable.coffee
@@ -18,9 +18,10 @@
   return
 makeSortable = (el, duplicate) ->
   $("ul.ui-model-blocks", el).sortable(
-    connectWith: '#content',
-    appendTo: '#content div[role="container"]',
+    connectWith: '#content div[role="container"] ul.ui-model-blocks',
+    appendTo: 'body',
     tolerance: 'pointer',
+    zIndex: 100000,
     helper: (event, obj) ->
       $("

").addClass("ui-model").append obj.clone()
     create: (event, ui)->


Automatically refresh main stream every 60s

--- frontend/src/js/admin/admin.coffee
+++ frontend/src/js/admin/admin.coffee
@@ -137,6 +137,17 @@
         visualizer = new Fontana.Visualizer(container, datasource)
         visualizer.start(settings)

+    # Automatically refresh /all db. If the admin page is not
+    # displayed, the /moderated stream will not refresh.
+    fetchMessages = ->
+        refresh()
+        scheduleFetchMessages()
+
+    scheduleFetchMessages = ->
+        fetchMessagesTimer = setTimeout((=> fetchMessages()), 60000)
+
+    refresh()
+
     HTMLFontana = (settings={})->
         if visualizer
             visualizer.stop()
@@ -147,6 +158,7 @@
     # Prepare our datasource, the messages will disappear soon...
     HTMLFontana.datasource = new Fontana.datasources.HTML(container)
     HTMLFontana.datasource.getMessages()
+    scheduleFetchMessages()

     # Bindings
     $(".settings", controls).click -> toggleSettings.call(this)


Fixed bug where other options would not be available

--- lib/ricksum-provider.coffee
+++ lib/ricksum-provider.coffee
@@ -26,6 +26,7 @@
       quotes = atom.config.get('lorem-ricksum.quotes')

     return {display: prefix, quotes, paragraphs}
+  return {display: undefined, quotes: undefined, paragraphs: undefined}

 makeSuggestion = (text, display) ->
   suggestion =


fixing import

fixing import

--- src/toaster/builder.coffee
+++ src/toaster/builder.coffee
@@ -1,4 +1,4 @@
-#<< toaster/utils/array_util
+#<< toaster/utils/array-util

 fs = require 'fs'
 path = require 'path'


Bug fix

Bug fix

--- lib/relations/one.coffee
+++ lib/relations/one.coffee
@@ -132,9 +132,13 @@
     return callback(null, null) unless model.attributes.id

     # not loaded but we have the id, create a model
-    if key is @ids_accessor and @type is 'belongsTo'
-      model.set(@key, @reverse_model_type.findOrCreate({id: model._orm_lookups[@foreign_key]}))
-      return true
+    if @type is 'belongsTo'
+      if key is @ids_accessor
+        model.set(@key, @reverse_model_type.findOrCreate({id: model._orm_lookups[@foreign_key]}))
+        return true
+      # nothing to fetch
+      else if not (model._orm_lookups and model._orm_lookups[@foreign_key]) and not model.attributes[@key]
+        return true

     # Will only load ids if key is @ids_accessor
     @cursor(model, key).toJSON (err, json) =>
@@ -170,7 +174,7 @@
       if @type is 'belongsTo'
         if model._orm_lookups and (related_id = model._orm_lookups[@foreign_key])
           query.id = related_id
-        else if related_model = model.attributes[@key]
+        else if related_model = related_model = model.attributes[@key]
           query.id = related_model.get('id')
       else
         query[@foreign_key] = model.attributes.id


basic HTML pane implementation

basic HTML pane implementation

--- lib/runtime/plots.coffee
+++ lib/runtime/plots.coffee
@@ -9,6 +9,7 @@
       plot: (x) => @show x
       plotsize: => @plotSize()
       ploturl: (url) => @ploturl url
+      newpane: (id, url, opts) => @newpane(id, url, opts)
     @create()

   create: ->
@@ -38,3 +39,19 @@
     @ensureVisible()
     @pane.show v
     v.addEventListener('console-message', (e) => console.log(e.message))
+
+  newpane: (id, url, opts) ->
+    v = views.render webview
+      class: 'blinkjl',
+      disablewebsecurity: true,
+      src: url,
+      style: 'width: 100%; height: 100%'
+    v.addEventListener('console-message', (e) => console.log(e.message))
+
+    pane = @ink.HTMLPane.fromId(id, {
+      item: v,
+      icon: opts.icon || 'graph',
+      title: opts.title || 'HTMLPane'
+      })
+
+    pane.ensureVisible({split: 'right'})


Reorder left panel

Reorder left panel

--- lib/settings-view.coffee
+++ lib/settings-view.coffee
@@ -58,9 +58,9 @@

     @addCorePanel 'Settings', 'settings', -> new GeneralPanel
     @addCorePanel 'Keybindings', 'keyboard', -> new KeybindingsPanel
+    @addCorePanel 'Packages', 'package', => new InstalledPackagesPanel(@packageManager)
     @addCorePanel 'Themes', 'paintcan', => new ThemesPanel(@packageManager)
-    @addCorePanel 'Find Packages', 'cloud-download', => new PackagesPanel(@packageManager)
-    @addCorePanel 'Manage Packages', 'package', => new InstalledPackagesPanel(@packageManager)
+    @addCorePanel 'Install', 'cloud-download', => new PackagesPanel(@packageManager)
     @addPanel 'Available Updates', null, =>
       new UpdatesPanel(@packageManager)


Add comment/description to tweetActionMessage.

--- src/tweeter-helpers.coffee
+++ src/tweeter-helpers.coffee
@@ -46,7 +46,7 @@
   "Gah! I can't do that: '#{err.message}' (returned a #{err.statusCode} status code)"

 #
-#
+# The human-readable message sent to the chat client about the tweet action.
 #
 tweetActionMessage = (response, action) ->
   "#{response.tweeter()} just #{action}: ' #{response.tweet()} '."


refactor(events): moved every event on rename calendar in a simple function

--- client/app/views/menu_item.coffee
+++ client/app/views/menu_item.coffee
@@ -16,8 +16,8 @@
         'click .dropdown-toggle': 'hideColorPicker'
         'click .calendar-color': 'showColorPicker'
         'change .color-picker': 'setColor'
-
-
+        'blur input.calendar-name': 'onRenameValidation'
+        'keyup input.calendar-name': 'onRenameValidation'

     getRenderData: ->
         label: @model.get 'name'
@@ -64,14 +64,28 @@
         # Gone after succefull color pick, put it back.
         @$('.dropdown-toggle').on 'click', @hideColorPicker

+    #setting rename validation function to handle esc / return key, and blur event
+    onRenameValidation: (event) ->

-    #setting rename validation function to avoid code duplication
-    onRenameValidation: (input, calendarName) ->
+        input = $(event.target)
+        calendarName = @model.get 'name'
         @startSpinner()
+
         # removes the binding to prevent memory leak
-        input.off 'keyup'
-        app.calendars.rename calendarName, input.val(), =>
+        key = event.keyCode or event.charCode
+        if key is 27 # escape key
+            input.remove()
+            # re-appends text element
+            @rawTextElement.insertAfter @$('.badge')
+            # Restores the badge color
+            @buildBadge calendarName
+            # Shows the menu again
+            @$('.dropdown-toggle').show()
             @stopSpinner()
+        #blur and enter have the same effect
+        else if (key is 13 or event.type is 'focusout')
+            app.calendars.rename calendarName, input.val(), =>
+                @stopSpinner()

     onRenameCalendar: ->
         calendarName = @model.get 'name'
@@ -82,8 +96,7 @@
         """
         input = $ template
         # Keeps a reference to the text element so we can re-append it later
-        rawTextElement = @$('.calendar-name').detach()
-        input.insertAfter @$('.badge')
+        @rawTextElement = @$('.calendar-name').detach()

         # hides the menu during edition
         @$('.dropdown-toggle').hide()
@@ -91,36 +104,6 @@
         # focus the input and select its value
         input.focus()
         input[0].setSelectionRange 0, calendarName.length
-
-        # Binds event to actually rename the calendar (enter key and blur)
-        input.blur (event) =>
-            console.log(calendarName)
-            @onRenameValidation input, calendarName
-
-        input.keyup (event) =>
-            key = event.keyCode or event.charCode
-            if key is 13 # enter key
-                @onRenameValidation input, calendarName
-            else
-                @buildBadge colorhash input.val()
-
-        # Close the form and restore original state when user presses "escape"
-        $(document).keyup restore = (event) =>
-            key = event.keyCode or event.charCode
-            if key is 27 # escape key
-                # removes the binding to prevent memory leak
-                $(document).off 'keyup', 'document', restore
-                input.off 'keyup'
-
-                # re-appends text element
-                input.remove()
-                rawTextElement.insertAfter @$('.badge')
-
-                # Restores the badge color
-                @buildBadge calendarName
-
-                # Shows the menu again
-                @$('.dropdown-toggle').show()

     onRemoveCalendar: ->
         calendarName = @model.get 'name'


Streamlined snippets

Streamlined snippets

--- snippets/language-sqf.cson
+++ snippets/language-sqf.cson
@@ -1,6 +1,6 @@
 '.source.sqf':
   # BI Commands - Conditional Structures
-  'If then statement':
+  'If Then statement':
     'prefix': 'if_then'
     'body': """
       if (${1:CONDITION}) then {
@@ -9,7 +9,7 @@
     """
     'description': 'Conditional if statement'
     'descriptionMoreURL': 'https://community.bistudio.com/wiki/if'
-  'If-then-else statement':
+  'If Then Else statement':
     'prefix': 'if_then_else'
     'body': """
       if (${1:CONDITION}) then {
@@ -20,7 +20,7 @@
     """
     'description': 'Conditional if-else statement'
     'descriptionMoreURL': 'https://community.bistudio.com/wiki/else'
-  'If-then-else assignment':
+  'If Then Else assignment':
     'prefix': 'if_then_else_assign'
     'body': """
       ${1:VARIABLE} = if (${2:CONDITION}) then {${3:ASSIGNMENT_TRUE}} else {${4:ASSIGNMENT_FALSE}};
@@ -35,7 +35,7 @@
     """
     'description': 'Conditional switch statement'
     'descriptionMoreURL': 'https://community.bistudio.com/wiki/switch_do'
-  'Case block of switch':
+  'Case block of Switch':
     'prefix': 'case_switch'
     'body': """
       case (${1:VALUE}): {
@@ -44,7 +44,7 @@
     """
     'description': 'Case block inside switch statement'
     'descriptionMoreURL': 'https://community.bistudio.com/wiki/case'
-  'Default block of switch':
+  'Default block of Switch':
     'prefix': 'default_switch'
     'body': """
       default {
@@ -53,6 +53,24 @@
     """
     'description': 'Default block inside switch statement'
     'descriptionMoreURL': 'https://community.bistudio.com/wiki/default'
+  'If ExitWith statement':
+      'prefix': 'if_exitWith'
+      'body': """
+        if (${1:CONDITION) exitwith {
+            ${2://code}
+        };
+      """
+      'description': 'If exitwith'
+      'descriptionMoreURL': 'https://community.bistudio.com/wiki/exitwith'
+  'ExitWith statement':
+    'prefix': 'exitWith'
+    'body': """
+      if (${1:CONDITION) exitwith {
+          ${2://code}
+      };
+    """
+    'description': 'If exitwith'
+    'descriptionMoreURL': 'https://community.bistudio.com/wiki/exitwith'

   # BI Commands - Loops
   'ForEach Loop':
@@ -133,78 +151,12 @@
     """
     'description': 'Function Header per ACE3 guidelines.'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#3-1-function-definitions'
-  # control blocks
-  'For Loop (ARRAY)':
-    'prefix': 'for_array'
-    'body': """
-    for [{${1:[variable]} = 0},{${1:[variable]} < ${2:[condition]}},{ ${1:[variable]} = ${1:[variable]} + ${3:[step]}}] do {
-        ${4:[code]}
-    };
-    """
-    'description': 'For loop (ARRAY)'
-    'descriptionMoreURL': 'https://community.bistudio.com/wiki/for'
-  'For loop (VAR)':
-    'prefix': 'for_var'
-    'body': """
-    for "${1:[variable]}" from ${2:[from]} to ${3:[to]} do {
-        ${4:[code]}
-    };
-    """
-    'description': 'For loop (VAR)'
-    'descriptionMoreURL': 'https://community.bistudio.com/wiki/for'
-  'ForEach Loop':
-    'prefix': 'forEach'
-    'body': """
-    {
-        ${2:[code]}
-    } forEach ${1:[variable]};
-    """
-    'description': 'ForEach loop'
-    'descriptionMoreURL': 'https://community.bistudio.com/wiki/foreach'
-  'If then':
-    'prefix': 'if_then'
-    'body': """
-    if (${1:[variable]}) then {
-        ${2:[code]}
-    };
-    """
-    'description': 'If then'
-    'descriptionMoreURL': 'https://community.bistudio.com/wiki/if'
-  'If then else':
-    'prefix': 'if_then_else'
-    'body': """
-    if (${1:[variable]}) then {
-        ${2:[code]}
-    } else {
-
-    };
-    """
-    'description': 'If then else'
-    'descriptionMoreURL': 'https://community.bistudio.com/wiki/if'
-  'If ExitWith statement':
-      'prefix': 'if_exitWith'
-      'body': """
-      if (${1:[variable]}) exitwith {
-          ${2:[code]}
-      };
-      """
-      'description': 'If exitwith'
-      'descriptionMoreURL': 'https://community.bistudio.com/wiki/exitwith'
-  'ExitWith statement':
-    'prefix': 'exitWith'
-    'body': """
-    if (${1:[variable]}) exitwith {
-        ${2:[code]}
-    };
-    """
-    'description': 'If exitwith'
-    'descriptionMoreURL': 'https://community.bistudio.com/wiki/exitwith'
-
-# Macros
+
+  # CBA/ACE Macros
   'GVAR':
     'prefix': 'GVAR'
     'body': """
-    GVAR(${1:[variable]})
+      GVAR(${1:[variable]})
     """
     'description': 'Expand to PREFIX_MODULE_variable'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -212,7 +164,7 @@
   'QGVAR':
     'prefix': 'QGVAR'
     'body': """
-    QGVAR(${1:[variable]})
+      QGVAR(${1:[variable]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -220,7 +172,7 @@
   'EGVAR':
     'prefix': 'EGVAR'
     'body': """
-    EGVAR(${1:[component]}),${2:[variable]})
+      EGVAR(${1:[component]}),${2:[variable]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -228,7 +180,7 @@
   'QEGVAR':
     'prefix': 'QEGVAR'
     'body': """
-    QEGVAR(${1:[component]}),${2:[variable]})
+      QEGVAR(${1:[component]}),${2:[variable]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -236,7 +188,7 @@
   'FUNC':
     'prefix': 'FUNC'
     'body': """
-    FUNC(${1:[function name]})
+      FUNC(${1:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -244,7 +196,7 @@
   'EFUNC':
     'prefix': 'EFUNC'
     'body': """
-    EFUNC(${1:[component name]}),${2:[function name]})
+      EFUNC(${1:[component name]}),${2:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -252,7 +204,7 @@
   'DFUNC':
     'prefix': 'DFUNC'
     'body': """
-    DFUNC(${1:[function name]})
+      DFUNC(${1:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -260,7 +212,7 @@
   'DEFUNC':
     'prefix': 'DEFUNC'
     'body': """
-    DEFUNC(${1:[component name]}),${2:[function name]})
+      DEFUNC(${1:[component name]}),${2:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -268,7 +220,7 @@
   'QFUNC':
     'prefix': 'QFUNC'
     'body': """
-    QFUNC(${1:[function name]})
+      QFUNC(${1:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -276,7 +228,7 @@
   'QEFUNC':
     'prefix': 'QEFUNC'
     'body': """
-    QEFUNC(${1:[component name]}),${2:[function name]})
+      QEFUNC(${1:[component name]}),${2:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -284,7 +236,7 @@
   'QUOTE':
     'prefix': 'QUOTE'
     'body': """
-    QUOTE(${1:[Content]})
+      QUOTE(${1:[Content]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -292,7 +244,7 @@
   'LSTRING':
     'prefix': 'LSTRING'
     'body': """
-    LSTRING(${1:[String table entry]})
+      LSTRING(${1:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -300,7 +252,7 @@
   'ELSTRING':
     'prefix': 'ELSTRING'
     'body': """
-    ELSTRING(${1:[Component]}),${2:[String table entry]})
+      ELSTRING(${1:[Component]}),${2:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -308,7 +260,7 @@
   'CSTRING':
     'prefix': 'CSTRING'
     'body': """
-    CSTRING(${1:[String table entry]})
+      CSTRING(${1:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -316,7 +268,7 @@
   'ECSTRING':
     'prefix': 'ECSTRING'
     'body': """
-    ELSTRING(${1:[Component]}),${2:[String table entry]})
+      ELSTRING(${1:[Component]}),${2:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -340,11 +292,11 @@
     'description': 'ACE_Settings Entry (without SCALAR values)'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/framework/settings.html'

-# Macros
+  # CBA/ACE Macros
   'GVAR':
     'prefix': 'GVAR'
     'body': """
-    GVAR(${1:[variable]})
+      GVAR(${1:[variable]})
     """
     'description': 'Expand to PREFIX_MODULE_variable'
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -352,7 +304,7 @@
   'QGVAR':
     'prefix': 'QGVAR'
     'body': """
-    QGVAR(${1:[variable]})
+      QGVAR(${1:[variable]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -360,7 +312,7 @@
   'EGVAR':
     'prefix': 'EGVAR'
     'body': """
-    EGVAR(${1:[component]}),${2:[variable]})
+      EGVAR(${1:[component]}),${2:[variable]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -368,7 +320,7 @@
   'QEGVAR':
     'prefix': 'QEGVAR'
     'body': """
-    QEGVAR(${1:[component]}),${2:[variable]})
+      QEGVAR(${1:[component]}),${2:[variable]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -376,7 +328,7 @@
   'FUNC':
     'prefix': 'FUNC'
     'body': """
-    FUNC(${1:[function name]})
+      FUNC(${1:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -384,7 +336,7 @@
   'EFUNC':
     'prefix': 'EFUNC'
     'body': """
-    EFUNC(${1:[component name]}),${2:[function name]})
+      EFUNC(${1:[component name]}),${2:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -392,7 +344,7 @@
   'DFUNC':
     'prefix': 'DFUNC'
     'body': """
-    DFUNC(${1:[function name]})
+      DFUNC(${1:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -400,7 +352,7 @@
   'DEFUNC':
     'prefix': 'DEFUNC'
     'body': """
-    DEFUNC(${1:[component name]}),${2:[function name]})
+      DEFUNC(${1:[component name]}),${2:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -408,7 +360,7 @@
   'QFUNC':
     'prefix': 'QFUNC'
     'body': """
-    QFUNC(${1:[function name]})
+      QFUNC(${1:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -416,7 +368,7 @@
   'QEFUNC':
     'prefix': 'QEFUNC'
     'body': """
-    QEFUNC(${1:[component name]}),${2:[function name]})
+      QEFUNC(${1:[component name]}),${2:[function name]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -424,7 +376,7 @@
   'QUOTE':
     'prefix': 'QUOTE'
     'body': """
-    QUOTE(${1:[Content]})
+      QUOTE(${1:[Content]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -432,7 +384,7 @@
   'LSTRING':
     'prefix': 'LSTRING'
     'body': """
-    LSTRING(${1:[String table entry]})
+      LSTRING(${1:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -440,7 +392,7 @@
   'ELSTRING':
     'prefix': 'ELSTRING'
     'body': """
-    ELSTRING(${1:[Component]}),${2:[String table entry]})
+      ELSTRING(${1:[Component]}),${2:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -448,7 +400,7 @@
   'CSTRING':
     'prefix': 'CSTRING'
     'body': """
-    CSTRING(${1:[String table entry]})
+      CSTRING(${1:[String table entry]})
     """
     'description': ''
     'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
@@ -456,7 +408,7 @@
   'ECSTRING':
     'prefix': 'ECSTRING'
     'body': """
-    ELSTRING(${1:[Component]}),${2:[String table entry]})
-    """
-    'description': ''
-    'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'
+      ELSTRING(${1:[Component]}),${2:[String table entry]})
+    """
+    'description': ''
+    'descriptionMoreURL': 'http://ace3mod.com/wiki/development/coding-guidelines.html#4-2-general-purpose-macros'


Prevent iScrubber to be possibly registered multiple times on the same element.

--- client/js/jquery.iscrubber.coffee
+++ client/js/jquery.iscrubber.coffee
@@ -22,6 +22,9 @@
   this.each ->
     $this = $(this)

+    return if $this.data('iscrubber-enabled')
+    $this.data('iscrubber-enabled', true)
+
     # get elements
     elements = $this.find('li')

@@ -36,7 +39,7 @@
     scrub(elements, options.showItem)

     # bind event when mouse moves over scrubber
-    $this.mousemove (e) ->
+    $this.on 'mousemove.iscrubber', (e) ->
       # get x mouse position
       x = e.pageX - $this.offset().left

@@ -46,6 +49,6 @@
       scrub(elements, index)

     # bind event when mouse leaves scrubber
-    $this.mouseleave ->
+    $this.on 'mouseleave.iscrubber', ->
       scrub(elements, options.showItem) if options.leaveToFirst is true


LivemarkSource: use constant for annotation name

--- lib/source/livemarks.coffee
+++ lib/source/livemarks.coffee
@@ -5,6 +5,6 @@

 class LivemarkSource # implements Source
   getFeeds : () =>
-    new RemoteXmlFeed(feed.annotationValue) for feed in PlacesUtils.annotations.getAnnotationsWithName('livemark/feedURI')
+    new RemoteXmlFeed(feed.annotationValue) for feed in PlacesUtils.annotations.getAnnotationsWithName(PlacesUtils.LMANNO_FEEDURI)

 exports.LivemarkSource = LivemarkSource


Tests: Fix enterExitFullScreenFromIdeHeader test failure.

--- client/test/lib/ide/layout.coffee
+++ client/test/lib/ide/layout.coffee
@@ -139,22 +139,24 @@

   enterExitFullScreenFromIdeHeader: (browser) ->

-    ideHeaderSelector           = '.pane-wrapper .kdsplitview-panel.panel-0 .application-tab-handle-holder'
-    enterExitFullScreenSelector = '.kdsplitview-horizontal .panel-0 .idetabhandle-holder .general-handles .fullscreen-handle'
+    ideHeaderSelector           = '.panel-1 .pane-wrapper .application-tab-handle-holder'
+    enterExitFullScreenSelector = "#{ideHeaderSelector} .general-handles .fullscreen-handle"
     collapsedSidebarSelector    = '.kdview.with-sidebar#kdmaincontainer.collapsed'

     helpers.beginTest(browser)
     helpers.waitForVMRunning(browser)
+    layoutHelpers.waitForSnapshotRestore(browser)

     browser
       .waitForElementVisible     ideHeaderSelector, 20000
       .moveToElement             ideHeaderSelector, 10, 10
       .waitForElementVisible     enterExitFullScreenSelector, 20000
       .click                     enterExitFullScreenSelector
-      .pause                     500 #pause for screen animation to finish
+      .pause                     1500 #pause for screen animation to finish
+      .moveToElement             ideHeaderSelector, 10, 10
+      .pause                     1000
+      .waitForElementVisible     enterExitFullScreenSelector, 20000
       .waitForElementVisible     collapsedSidebarSelector, 20000
-      .moveToElement             ideHeaderSelector, 10, 10
-      .waitForElementVisible     enterExitFullScreenSelector, 20000
       .click                     enterExitFullScreenSelector
       .pause                     500
       .waitForElementNotPresent  collapsedSidebarSelector, 20000


Ignore posts made by same user for duplicate check

For posts made in last 24 hours.

--- resources/assets/coffee/react/beatmap-discussions/new-discussion.coffee
+++ resources/assets/coffee/react/beatmap-discussions/new-discussion.coffee
@@ -185,6 +185,10 @@
       for post in @props.currentDiscussions.timeline
         continue if post.message_type not in ['suggestion', 'problem']
         continue if Math.abs(post.timestamp - @state.timestamp) > 5000
+
+        if post.user_id == @props.currentUser.id
+          continue if moment(post.updated_at).diff(moment(), 'hour') > -24
+
         posts.push(post)

       @cache.nearbyPosts =


Make hx.isArray an alias for Array.isArray

--- modules/util/main/index.coffee
+++ modules/util/main/index.coffee
@@ -177,8 +177,7 @@

 hx.isFunction = (x) -> typeof x == "function"

-#XXX: is this needed? should we just use Array.isArray?
-hx.isArray = (x) -> x instanceof Array
+hx.isArray = Array.isArray

 # returns true if the thing passed in is an object, except for arrays
 # which technically are objects, but in the eyes of this function are not


Fixing CLI tests

Fixing CLI tests

--- test/cli.coffee
+++ test/cli.coffee
@@ -6,25 +6,68 @@
 rel = (name) -> path.join __dirname, name

 command = rel '../bin/axiom'
-args = ['hello', 'world']

 sampleProject = rel '../sample/project2'

+cliRun = (args, cwd) ->
+  cli = spawn command, args, {cwd}
+  output = []
+  ['stdout', 'stderr'].forEach (source) ->
+    cli[source].setEncoding 'utf8'
+    cli[source].on 'data', logger.yellow
+    cli[source].on 'data', (message) -> output.push({source, message})
+
+  return {cli, output}
+
 describe 'cli', ->
-  @timeout 0
+  @timeout 2000
+
+  it "should fail with a help message if missing 'moduleName'", (done) ->
+    {cli, output} = cliRun []
+
+    cli.on 'close', ->
+      output.should.eql [
+        source: 'stdout'
+        message: "Missing required positional argument: 'moduleName'\n"
+       ,
+        source: 'stdout'
+        message: 'Usage: axiom <moduleName> <serviceName> [<--arg> <value> ...]\n\n\n'
+      ]
+      done()
+
+  it "should fail with a help message if missing 'serviceName'", (done) ->
+    {cli, output} = cliRun ['hello']
+
+    cli.on 'close', ->
+      output.should.eql [
+        source: 'stdout'
+        message: "Missing required positional argument: 'serviceName'\n"
+       ,
+        source: 'stdout'
+        message: 'Usage: axiom <moduleName> <serviceName> [<--arg> <value> ...]\n\n\n'
+      ]
+      done()

   it 'should start server', (done) ->
-    cli = spawn command, args, {cwd: sampleProject}
+    args = ['hello', 'world']
+    cwd = rel '../sample/project2'

-    output = []
-    ['stdout', 'stderr'].forEach (source) ->
-      cli[source].setEncoding 'utf8'
-      cli[source].on 'data', logger.yellow
-      cli[source].on 'data', (message) -> output.push({source, message})
+    {cli, output} = cliRun args, cwd

     cli.on 'close', ->
-      console.log {output}
       output.should.eql [
         {source: 'stdout', message: 'Hello, world!\n'}
       ]
       done()
+
+  it "should accept a '--debug' logging flag", (done) ->
+    true.should.be.false
+    done()
+
+  it "should accept an '--error' logging flag", (done) ->
+    true.should.be.false
+    done()
+
+  it "should accept an '--info' logging flag", (done) ->
+    true.should.be.false
+    done()


Immediate abort on update

Immediate abort on update

Sync with generic one.

--- resources/assets/coffee/_classes/account-edit-playstyle.coffee
+++ resources/assets/coffee/_classes/account-edit-playstyle.coffee
@@ -28,6 +28,7 @@
     target = e.currentTarget
     target.dataset.playstyleUpdating = '1'

+    @xhr?.abort()
     @setState 'saving'
     @debouncedUpdate()

@@ -61,7 +62,6 @@
       checkbox = field.getElementsByTagName('input')[0]
       arr.push field.dataset.playstyle if checkbox.checked

-    @xhr?.abort()
     @xhr = $.ajax laroute.route('account.update'),
       method: 'PUT'
       data:


:fire: proxy methods now activateInsert independently handle it #137

--- lib/visual-blockwise.coffee
+++ lib/visual-blockwise.coffee
@@ -104,9 +104,6 @@
   recordable: true
   delegateTo: 'ChangeToLastCharacterOfLine'

-  getCheckpoint: ->
-    @operator.getCheckpoint()
-
   initialize: ->
     @operator = @new(@delegateTo)

@@ -115,9 +112,6 @@
   delegateTo: 'ActivateInsertMode'
   recordable: true
   after: false
-
-  getCheckpoint: ->
-    @operator.getCheckpoint()

   initialize: ->
     @operator = @new(@delegateTo)


prevent event bubbling on escape when results are showing

--- coffee/lib/abstract-chosen.coffee
+++ coffee/lib/abstract-chosen.coffee
@@ -254,6 +254,9 @@
       when 13 # enter
         evt.preventDefault() if @results_showing
         break
+      when 27 # escape
+        evt.preventDefault() if @results_showing
+        break
       when 32 # space
         evt.preventDefault() if @disable_search
         break


TIE Silencer generics

TIE Silencer generics

--- coffeescripts/cards-common.coffee
+++ coffeescripts/cards-common.coffee
@@ -5109,7 +5109,7 @@
             applies_condition: 'Rattled'.canonicalize()
         }
         {
-            name: 'Sienar-Jae???'
+            name: 'Sienar-Jaemus Analyst'
             id: 283
             faction: 'First Order'
             ship: 'TIE Silencer'
@@ -5118,19 +5118,20 @@
                 'System'
                 'Tech'
             ]
-            points: 100
-        }
-        {
-            name: 'First Orde???'
+            points: 26
+        }
+        {
+            name: 'First Order Test Pilot'
             id: 284
             faction: 'First Order'
             ship: 'TIE Silencer'
             skill: 6
             slots: [
+                'Elite'
                 'System'
                 'Tech'
             ]
-            points: 100
+            points: 29
         }
         {
             name: 'Test Pilot "Blackout"'


adding weather JSON at startup

adding weather JSON at startup

--- both/config/_config.coffee
+++ both/config/_config.coffee
@@ -26,4 +26,7 @@

 Meteor.startup ->
 	if Meteor.isClient
+		$.getJSON 'http://api.wunderground.com/api/66cc45223c7fe53f/conditions/q/CA/San_Francisco.json', (data) ->
+		window.weatherData = data.current_observation
 		TAPi18n.setLanguage('en')
+		return


Fetch app record from server or generate a fresh one.

--- app/index.coffee
+++ app/index.coffee
@@ -4,7 +4,9 @@
   ($ "body").append ($ "<div class='rev'>").text "Revision " + REVISION
   init_records "clients"
   init_records "groups"
-  ($ ".db").append RECORDS["app"] = generate_xml_from_schema "app"
+  init_records "app"
+  if not ($ ".db app *").length
+    ($ ".db").append RECORDS["app"] = generate_xml_from_schema "app"
   get_records ["clients", "groups"]
   set_mixins [VIEWS_RECORD, VIEWS_RECORD_DISPLAY, VIEWS_STRUCTURAL, VIEWS_XREF]
   init_menu()


retain some hit info in client response

retain some hit info in client response

--- loadHIT.coffee
+++ loadHIT.coffee
@@ -106,10 +106,6 @@
     ''' TODO get teaching set '''
     callback("Teaching set not ready yet", bj)

-  if obj.condition is 'fast'
-    ''' TODO Prep larger set for fast completion '''
-    callback("Fast set not ready yet", obj)
-
   if obj.condition is 'basic' or 'fast'
     if obj.opts.user == 'PREVIEWUSER'
       candidates = obj.hit.items
@@ -184,7 +180,10 @@
   # Not needed by front end
   delete obj.userItemList
   delete obj.locksCleared
-  delete obj.hit
+  delete obj.hit.items
+  delete obj.hit.setsPerItem
+  delete obj.hit.maxSetSize
+  delete obj.hit.name
   # Easier access on front-end
   # Add item information to taskSet.tasks[] as .meta field
   # This information shouldn't be saved to Mongo, since we already have it


test to ensure `chains` ignore `points`

test to ensure `chains` ignore `points`

--- spec/vfl.coffee
+++ spec/vfl.coffee
@@ -250,6 +250,17 @@
             '#btn1[right] + 8 == ::window[center-x]'
             '::window[center-x] + 8 == #btn2[left]'
           ]
+
+    parse """
+            @h [#btn1]-<::window[center-x]>-[#btn2] gap(8) chain-top chain-width(==); // chains ignore points
+          """
+        ,
+          [
+            '#btn1[right] + 8 == ::window[center-x]'
+            '::window[center-x] + 8 == #btn2[left]'
+            '#btn1[top] == #btn2[top]'
+            '#btn1[width] == #btn2[width]'
+          ]

     parse """
             @h [#btn1]-<"col3"[left]>


Updated the mimosa skeleton config.

Updated the mimosa skeleton config.

--- skeletons/mimosa/DurandalTemplate/mimosa-config.coffee
+++ skeletons/mimosa/DurandalTemplate/mimosa-config.coffee
@@ -1,42 +1,43 @@
-exports.config =
-  modules: ['server', 'require', 'minify', 'live-reload', 'combine', 'mimosa-requirebuild-textplugin-include', 'skeleton']
-
-  combine:[
-    {
-      folder:'Content'
-      output:'Content/styles.css'
-    }
-    {
-      folder:'Scripts'
-      output:'Scripts/vendor.js'
-      order: ['jquery-1.8.3.js', 'knockout-2.2.0.js']
-    }
-  ]
-
-  copy:
-    extensions: ['js', 'css', 'png', 'jpg', 'gif', 'html', 'eot', 'svg', 'ttf', 'woff', 'otf', 'json', 'txt', 'xml', 'xsd']
-
-  watch:
-    sourceDir: 'assets'
-    javascriptDir: 'App'
-
-  server:
-    port: 3000
-    useDefaultServer: true
-
-    views:
-      compileWith: 'html'
-      extension: 'html'
-
-  requireBuildTextPluginInclude:
-    pluginPath: 'text'
-    extensions: ['html']
-
-  require:
-    optimize:
-      overrides:
-        name: 'durandal/amd/almond-custom'
-        inlineText: true
-        stubModules: ['text']
-        paths:
+exports.config =
+  minMimosaVersion:'0.8.7'
+
+  modules: ['server', 'require', 'minify', 'live-reload', 'combine', 'mimosa-requirebuild-textplugin-include', 'skeleton']
+
+  combine:[
+    {
+      folder:'Content'
+      output:'Content/styles.css'
+    }
+    {
+      folder:'Scripts'
+      output:'Scripts/vendor.js'
+      order: ['jquery-1.8.3.js', 'knockout-2.2.0.js']
+    }
+  ]
+
+  copy:
+    extensions: ['js', 'css', 'png', 'jpg', 'jpeg', 'gif', 'htm', 'html', 'eot', 'svg', 'ttf', 'woff', 'otf', 'yaml', 'kml', 'ico', 'htc', 'json', 'txt', 'xml', 'xsd']
+
+  watch:
+    javascriptDir: 'App'
+
+  server:
+    port: 3000
+    useDefaultServer: true
+
+    views:
+      compileWith: 'html'
+      extension: 'html'
+
+  requireBuildTextPluginInclude:
+    pluginPath: 'text'
+    extensions: ['html']
+
+  require:
+    optimize:
+      overrides:
+        name: 'durandal/amd/almond-custom'
+        inlineText: true
+        stubModules: ['text']
+        paths:
           text: 'durandal/amd/text'


Allow callback on window.close

Allow callback on window.close

--- src/views/ui/window.coffee
+++ src/views/ui/window.coffee
@@ -31,10 +31,15 @@

   open: (options) => @view.open options

-  close: (options) => @view.close options
+  close: (options, callback) =>

   destroy: => @trigger 'destroy'
+    if callback
+      @view.addEventListener 'close', ->
+        callback()
+        return

+    @view.close options
   _bindControllerEvents: =>
     @controller?.context ?= @
     super


Disabled test for workaround

Disabled test for workaround

--- spec/spark-dev-spec.coffee
+++ spec/spark-dev-spec.coffee
@@ -363,7 +363,7 @@
         jasmine.unspy atom.workspaceView, 'trigger'
         SettingsHelper.clearCredentials()

-    it 'checks flashing after compiling', ->
+    xit 'checks flashing after compiling', ->
       SettingsHelper.setCredentials 'foo@bar.baz', '0123456789abcdef0123456789abcdef'
       SparkStub.stubSuccess 'compileCode'
       SparkStub.stubSuccess 'downloadBinary'


don’t default property to array

don’t default property to array

--- app/assets/javascripts/components/inline_edit_body_part.js.coffee
+++ app/assets/javascripts/components/inline_edit_body_part.js.coffee
@@ -1,7 +1,11 @@
 ETahi.InlineEditBodyPartComponent = Em.Component.extend
   editing: false
-  snapshot: []
+  snapshot: null
   confirmDelete: false
+
+  _init: (->
+    @set('snapshot', [])
+  ).on('init')

   createSnapshot: (->
     @set('snapshot', Em.copy(@get('block'), true))


Fix specs [#64155952][6e1a11ce4f231a799a9cc95c39a8801e933dcf4c][c7e930180f0295b08a1f19ac05e94e7ba6c2efdb]

--- spec/javascripts/acceptance/admin_users_page.js.coffee
+++ spec/javascripts/acceptance/admin_users_page.js.coffee
@@ -1,38 +1,63 @@
 module 'admin users page',
-  setup: -> Review.reset()
+  setup: ->
+    Review.reset()

-test "displays a table with", ->
+    Ember.run ->
+      Review.User.createRecord(admin: true, id: 'me')
+      Review.User.createRecord(
+        id: 5
+        image_url: "adas1.jpg"
+        name: "mariusz"
+        nickname: "mariuszDusielak"
+        admin: true
+        permissions: [1,2]
+      )
+      Review.Project.createRecord(
+        id: 1
+        name: 'firstP'
+        grade: "grade1"
+        permission: [1]
+      )
+      Review.Project.createRecord(
+        id: 2
+        name: 'SecondP'
+        grade: "grade2"
+        permission: [2]
+      )
+      Review.Permission.createRecord(
+        id: 1
+        user_id: 5
+        project_id: 1
+        allowed: true
+      )
+      Review.Permission.createRecord(
+        id: 2
+        user_id: 5
+        project_id: 2
+        allowed: true
+      )

-  Ember.run ->
-    Review.User.createRecord(admin: true, id: 'me')
+test "displays a table with user", ->
+  visit '/admin/users'
+  andThen ->
+    ok find("tr.user").length == 1, "user"

+test "displays a table with projects", ->
   visit '/admin/users'
+  andThen ->
+    ok find("th.project").length == 2, "projects"

+test "displays a table with permissions", ->
+  visit '/admin/users'
   andThen ->
-    ok find("tr.user").length == Review.User.FIXTURES.length, "users"
-    ok find("th.project").length == Review.Project.FIXTURES.length, "projects"
-    ok find('.permissions').length == 6, "permissions"
+    ok find('.permissions').length == 2, "permissions"

-test "displays links to", ->
+test "displays links to allow access", ->
+  visit '/admin/users'
+  andThen ->
+    ok find("a:contains('Allow')").length == 2, "Allow access"

-  Ember.run ->
-    Review.User.createRecord(admin: true, id: 'me')
-
+test "doesn't show a link to deny access", ->
   visit '/admin/users'
-
   andThen ->
-    ok find("a:contains('Allow')").length == 6, "Allow access"
     ok find("a:contains('Deny')").length == 0, "Deny access"
-
-
-test "click on the allow link", ->
-
-  Ember.run ->
-    Review.User.createRecord(admin: true, id: 'me')
-
-  visit '/admin/users'
-  click "a.allow:first"
-
-  andThen ->
-    ok find("a:contains('Allow')").length == 5, "change count of allow links"
-    ok find("a:contains('Deny')").length == 1, "change count of deny links"


replace gulp.dest with dest for simplicity


Add the getGitHubAuthTokenName fn back in

--- src/atom.coffee
+++ src/atom.coffee
@@ -353,13 +353,16 @@
   getVersion: ->
     app.getVersion()

+  getGitHubAuthTokenName: ->
+    'Atom GitHub API Token'
+
   # Public: Set the the github token in the keychain
   setGitHubAuthToken: (token) ->
-    keytar.replacePassword('Atom GitHub API Token', 'github', token)
+    keytar.replacePassword(@getGitHubAuthTokenName(), 'github', token)

   # Public: Get the github token from the keychain
   getGitHubAuthToken: ->
-    keytar.getPassword('Atom GitHub API Token', 'github')
+    keytar.getPassword(@getGitHubAuthTokenName(), 'github')

   # Public: Get the directory path to Atom's configuration area.
   #


:memo: Tweak markdown in Atom comments

:memo: Tweak markdown in Atom comments

--- src/atom.coffee
+++ src/atom.coffee
@@ -22,18 +22,18 @@
 #
 # An instance of this class is always available as the `atom` global.
 #
-# The `atom` global also contains several useful properties that can be
-# accessed directly from this object:
-#  `atom.config`      - A {Config} instance
-#  `atom.contextMenu` - A {ContextMenuManager} instance
-#  `atom.keymap`      - A {Keymap} instance
-#  `atom.menu`        - A {MenuManager} instance
-#  `atom.rootView`    - A {RootView} instance
-#  `atom.packages     - A {PackageManager} instance
-#  `atom.pasteboard`  - A {Pasteboard} instance
-#  `atom.project`     - A {Project} instance
-#  `atom.syntax`      - A {Syntax} instance
-#  `atom.themes`      - A {ThemeManager} instance
+# ## Useful properties available:
+#
+#  * `atom.config`      - A {Config} instance
+#  * `atom.contextMenu` - A {ContextMenuManager} instance
+#  * `atom.keymap`      - A {Keymap} instance
+#  * `atom.menu`        - A {MenuManager} instance
+#  * `atom.rootView`    - A {RootView} instance
+#  * `atom.packages`    - A {PackageManager} instance
+#  * `atom.pasteboard`  - A {Pasteboard} instance
+#  * `atom.project`     - A {Project} instance
+#  * `atom.syntax`      - A {Syntax} instance
+#  * `atom.themes`      - A {ThemeManager} instance
 module.exports =
 class Atom
   Subscriber.includeInto(this)
@@ -241,12 +241,12 @@
   #
   # ## Example:
   # ```coffeescript
-  #  atom.confirm
-  #    message: 'How you feeling?'
-  #    detailedMessage: 'Be honest.'
-  #    buttons:
-  #      Good: -> window.alert('good to hear')
-  #      Bad: ->  window.alert('bummer')
+  #   atom.confirm
+  #      message: 'How you feeling?'
+  #      detailedMessage: 'Be honest.'
+  #      buttons:
+  #        Good: -> window.alert('good to hear')
+  #        Bad: ->  window.alert('bummer')
   # ```
   #
   # * options:


Build views in Atom environment constructor

--- src/atom.coffee
+++ src/atom.coffee
@@ -177,6 +177,9 @@
     CommandRegistry = require './command-registry'
     @commands = new CommandRegistry

+    ViewRegistry = require './view-registry'
+    @views = new ViewRegistry
+
   reset: ->
     @config.reset()

@@ -213,7 +216,6 @@

     @loadTime = null

-    ViewRegistry = require './view-registry'
     PackageManager = require './package-manager'
     Clipboard = require './clipboard'
     GrammarRegistry = require './grammar-registry'
@@ -235,7 +237,6 @@

     @keymaps.subscribeToFileReadFailure()

-    @views = new ViewRegistry
     @registerViewProviders()
     @packages = new PackageManager({devMode, configDirPath, resourcePath, safeMode})
     @styles = new StyleManager


Fix incorrect use of DataPrefix

Fix incorrect use of DataPrefix

--- src/resources-packaged/ops/javascript/orbeon/xforms/control/LHHA.coffee
+++ src/resources-packaged/ops/javascript/orbeon/xforms/control/LHHA.coffee
@@ -19,7 +19,7 @@

         lhhaEls = hintEl.add(helpEl)

-        if TooltipPopover.isTooltipOrPopover(lhhaEls, TooltipPopover.TooltipOrPopoverSelector)
+        if TooltipPopover.selfOrAncestor(lhhaEls, TooltipPopover.TooltipSelector + ', ' + TooltipPopover.PopoverSelector)
             TooltipPopover.init(controlEl, lhhaEls)
             if ! State.tooltipShownBecauseOfFocus
                 if event.type == 'mouseenter'
@@ -41,19 +41,19 @@
         if ! State.tooltipShownBecauseOfFocus && State.tooltipPopoverShownForControlEl?
             TooltipPopover.hide(State.tooltipPopoverShownForControlEl, event)

+DataPrefix = 'xforms-tooltip-popover-'
+
 # Facade for Bootstrap's Tooltip component
 # - ensures we don't show an already visible tooltip, which would make it "blink"
 TooltipPopover =

-    DataPrefix: 'xforms-tooltip-popover-'
-    Initialized: @DataPrefix + 'initialized'
-    Methods: @DataPrefix + 'methods'
+    Initialized: DataPrefix + 'initialized'
+    Methods: DataPrefix + 'methods'

     TooltipSelector: '.xforms-hint-appearance-tooltip, .xforms-help-appearance-tooltip'
     PopoverSelector: '.xforms-hint-appearance-popover, .xforms-help-appearance-popover'
-    TooltipOrPopoverSelector: '.xforms-hint-appearance-tooltip, .xforms-help-appearance-tooltip, .xforms-hint-appearance-popover, .xforms-help-appearance-popover'

-    isTooltipOrPopover: (lhhaEls, selector) ->
+    selfOrAncestor: (lhhaEls, selector) ->
         lhhaEls.is(selector) or lhhaEls.parents(selector).length > 0

     # Create the underlying Bootstrap tooltip (but don't show it just yet)
@@ -63,14 +63,14 @@
             methods = []
             _.each lhhaEls, (lhhaEl) ->
                 lhhaEl = $(lhhaEl)
-                if TooltipPopover.isTooltipOrPopover(lhhaEl, @TooltipSelector)
+                if TooltipPopover.selfOrAncestor(lhhaEl, @TooltipSelector)
                     controlEl.tooltip
                         placement: 'bottom',
                         trigger: 'manual',
                         title: lhhaEl.text()
                         html: true
                     methods.push('tooltip')
-                if TooltipPopover.isTooltipOrPopover(lhhaEl, @PopoverSelector)
+                if TooltipPopover.selfOrAncestor(lhhaEl, @PopoverSelector)
                     beforeLastColumn = $(controlEl).closest('td').next().is('*')
                     placement = if beforeLastColumn then 'right' else 'left'
                     controlEl.popover


optimize the sass and coffee task for reload speed

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -8,8 +8,19 @@
       vendorPath: 'vendor/'

     watch:
-      files: ['js/**', 'css/**', 'img/**', 'html/**', 'vendor/**']
-      tasks: ['coffee', 'sass', 'concat', 'copy']
+      script:
+        files: 'js/**'
+        tasks: ['coffee', 'concat']
+      style:
+        files: 'css/**'
+        tasks: ['sass', 'concat']
+      otherFiles:
+        files: ['img/**', 'html/**', 'vendor/**']
+        tasks: ['concat', 'copy']
+      config:
+        files: ['gruntfile.coffee', 'bower.json', 'package.json']
+        tasks: ['bower', 'sass', 'coffee', 'clean', 'concat', 'copy']
+

     concat:
       options:
@@ -17,13 +28,26 @@
       js:
         src: [
           'vendor/jquery/jquery.js'
-          'vendor/bootstrap/js/bootstrap.js'
+          'vendor/video.js/js/video.js'
+
+          # MPEG Dash
+          'vendor/dashjs/js/dash.debug.js'
+          'vendor/videojs-contrib-dash/js/videojs-dash.js'
+
+          # HLS
+          'vendor/videojs-contrib-media-sources/js/videojs-media-sources.js'
+          'vendor/videojs-contrib-hls/js/videojs.hls.js'
+
+          # Feature Detection
+          'vendor/radiant-medialyzer/rml.js'
+
           'js/compile/*.js'
         ]
         dest: 'dist/js/application.js'
       css:
         src: [
-          'vendor/bootstrap/css/bootstrap.css'
+          # 'vendor/bootstrap/css/bootstrap.css'
+          'vendor/video.js/css/video-js.css'
           "css/compile/*.css"
         ]
         dest: 'dist/css/application.css'
@@ -43,23 +67,33 @@
       dist: ["dist/**"]

     coffee:
-      compile:
+      main:
         files:
-          'js/compile/main.js': ['js/main.coffee'] # compile and concat into single file
+          'js/compile/main.js': ['js/videojs_dash_resolution.coffee', 'js/main.coffee'] # compile and concat into single file

     sass:
       dist:
         options:
           style: 'expanded'
+          sourcemap: 'none'
         files:
           'css/compile/main.css': 'css/main.scss'
-
     copy:
       fonts:
         expand: true
         cwd: 'vendor/bootstrap/font/'
         src: ['**']
         dest: '<%= meta.distPath %>/fonts/'
+      videoFonts:
+        expand: true
+        cwd: 'vendor/video.js/font/'
+        src: ['**']
+        dest: '<%= meta.distPath %>/fonts/'
+      videojsSwf:
+        expand: true
+        cwd: 'vendor/video.js/swf/'
+        src: ['**']
+        dest: '<%= meta.distPath %>/swf/'
       imgs:
         expand: true
         cwd: 'img/'
@@ -90,4 +124,6 @@
   grunt.loadNpmTasks('grunt-contrib-connect')
   grunt.loadNpmTasks('grunt-contrib-watch')

+  # grunt.loadNpmTasks('grunt-contrib-jshint')
+
   grunt.registerTask('default', ['bower', 'sass', 'coffee', 'clean', 'concat', 'copy', 'connect', 'watch'])


event

event

--- Web.App/app/modules/event/views/session-details-view.coffee
+++ Web.App/app/modules/event/views/session-details-view.coffee
@@ -6,6 +6,7 @@
   template: require './templates/session-details'
   events:
     'click .js-submit': 'onSubmit'
+    'click .js-remove': 'onRemove'
     'change textarea': 'onChange'
     'input textarea': 'onChange'

@@ -36,6 +37,10 @@
     if maxlength > 0 and $(e.currentTarget).val().length > maxlength
       $(e.currentTarget).val($(e.currentTarget).val().substring(0, maxlength));

+  onRemove: (e) ->
+    e.preventDefault()
+    # TODO: remove feedback from api
+
   onSubmit: (e) ->
     e.preventDefault()
     data = Backbone.Syphon.serialize(@)


Fix typo in comments.

Fix typo in comments.

--- src/bang.coffee
+++ src/bang.coffee
@@ -4,7 +4,7 @@
 {exec}  = require "child_process"
 os      = require "os"

-# Bang is program for storing and retrieving text snippets
+# Bang is a program for storing and retrieving text snippets
 # on the command line.
 module.exports = class Bang
   # Initializes Bang's data store.


What contents?

What contents?

--- src/modules/zwadonk/ZwadonkController.coffee
+++ src/modules/zwadonk/ZwadonkController.coffee
@@ -13,6 +13,7 @@
     $scope.showInfo = not $scope.showInfo
     console.log 'Open info panel'
     if event
+      # load contents of the panel
       event.stopPropagation()
       event.preventDefault()
     return


Fix log statement.

Fix log statement.

--- app/assets/javascripts/application/app_controller.js.coffee
+++ app/assets/javascripts/application/app_controller.js.coffee
@@ -52,7 +52,7 @@
     @podsController.updateScope(filterBy, sortBy, index)
     @displayPods()
   displayPods: ->
-    logger.verbose 'AppController#update.start'
+    logger.verbose 'AppController#displayPods'
     @current = 'pods'
     @podsController.display().then (result) =>
       if result.pods.length


Add .ev-select-all to event listener, fixes #109

--- app/assets/javascripts/browse_everything/behavior.js.coffee
+++ app/assets/javascripts/browse_everything/behavior.js.coffee
@@ -287,7 +287,7 @@
         window.setTimeout check_func, 1000
     check_func()

-  $(document).on 'change', 'input:checkbox', (event) ->
+  $(document).on 'change', 'input.ev-select-all', (event) ->
     event.stopPropagation()
     event.preventDefault()
     $.fn.browseEverything.toggleCheckbox(this)


fix setSelectedBufferRanges bug when sels is empty

--- lib/editor-proxy.coffee
+++ lib/editor-proxy.coffee
@@ -22,12 +22,12 @@
 # @param  {Editor} editor Brackets editor instance
 # @return {String}
 normalize = (text, editor) ->
-  editorUtils.normalize text,
+  editorUtils.normalize text,
     indentation: editor.getTabText(),
     newline: '\n'

 # Proprocess text data that should be used as snippet content
-# Currently, Atom’s snippets implementation has the following issues:
+# Currently, Atom’s snippets implementation has the following issues:
 # * supports $N or ${N:placeholder} notation, but not ${N}
 # * multiple $0 are not treated as distinct final tabstops
 preprocessSnippet = (value) ->
@@ -49,7 +49,7 @@
         placeholder = tabStops.processText(placeholder, tabstopOptions)

       if placeholder then "${#{group}:#{placeholder}}" else "$#{group}"
-
+
     escape: (ch) ->
       if ch == '$' then '\\$' else ch

@@ -60,7 +60,7 @@
     @editor = @editorView.getEditor()
     buf = @editor.getBuffer()
     bufRanges = @editor.getSelectedBufferRanges()
-    @_selection =
+    @_selection =
       index: 0
       saved: new Array(bufRanges.length)
       bufferRanges: bufRanges
@@ -83,7 +83,9 @@
       @_setSelectedBufferRanges(@_selection.saved)

   _setSelectedBufferRanges: (sels) ->
-    @editor.setSelectedBufferRanges(sels.filter (s) -> !!s)
+    filteredSels = sels.filter (s) -> !!s
+    if filteredSels.length
+      @editor.setSelectedBufferRanges(filteredSels)

   _saveSelection: (delta) ->
     @_selection.saved[@_selection.index] = @editor.getSelectedBufferRange()
@@ -187,7 +189,7 @@
     # Before inserting snippet we have to reset all available selections
     # to insert snippent right in required place. Otherwise snippet
     # will be inserted for each selection in editor
-
+
     # Right after that we should save first available selection as buffer range
     caret = buf.positionForCharacterIndex(start)
     @editor.setSelectedBufferRange(new Range(caret, caret))


whitespace

whitespace

--- src/bind.coffee
+++ src/bind.coffee
@@ -234,4 +234,4 @@
         return
     }

-    return self+    return self


Delete commented code in gulpfile.coffee


Use React with addons.

Use React with addons.


add before_init

add before_init

--- vendor/assets/javascripts/angular_objectify_resource/base_model.coffee
+++ vendor/assets/javascripts/angular_objectify_resource/base_model.coffee
@@ -17,9 +17,12 @@

     constructor: (resource)->
       angular.extend(@, resource)
+      @before_init()
       @_extend_children()
       @_convert_dates()
       @after_init()
+
+    before_init: ->

     after_init: ->


rounded head

rounded head

--- app/assets/js/renderer.coffee
+++ app/assets/js/renderer.coffee
@@ -19,7 +19,7 @@
     if shape.width? && shape.height?
       ctx.rect(-shape.width/2, -shape.height/2, shape.width, shape.height);
     else if shape.radius?
-      ctx.rect(-shape.radius, -shape.radius, shape.radius, shape.radius);
+      ctx.arc(0, 0, shape.radius, 0, 2 * Math.PI, false);
     ctx.stroke();
     ctx.restore();


make header menus hide when their ul/li's are clicked

--- app/assets/javascripts/tenon/features/header_menu.js.coffee
+++ app/assets/javascripts/tenon/features/header_menu.js.coffee
@@ -9,5 +9,5 @@
     $(e.currentTarget).closest('.header-menu').toggleClass('active')

   hideMenu: (e) =>
-    unless $(e.target).is('.header-menu ul *, .header-menu ul')
-      $('.header-menu').removeClass('active')
+    # unless $(e.target).is('.header-menu ul *, .header-menu ul')
+    $('.header-menu').removeClass('active')


view_partials test the right file

view_partials test the right file

--- cakes/view_partials.coffee
+++ cakes/view_partials.coffee
@@ -26,14 +26,14 @@
 				template.toString().replace('\n','').should.eql 'How are you, {{what}}?'

+			file_template = 'view_partials.hulk'
 			And 'I have a template file that includes that partial', ->
-				file = 'view_partials.hulk'
-				template = fs.readFileSync file
+				template = fs.readFileSync file_template
 				template.toString().replace('\n','').should.eql 'Hello {{what}}! {{> salute}}'

 			When 'I render that template', ->
 				app.get '/', (req,res)->
-					res.render 'express_engine.hulk', {what : 'World'}
+					res.render file_template, {what : 'World'}

 			Then 'it should output the rendered template with partial', (done)->
 				agent = require 'superagent'


fix datatable search (#1848)

fix datatable search (#1848)

--- BackofficeBundle/Resources/public/coffee/dataTable/DataTableView.coffee
+++ BackofficeBundle/Resources/public/coffee/dataTable/DataTableView.coffee
@@ -109,7 +109,8 @@
    * @param {Object} json DataTable data retrieved from server
   ###
   initComplete: (e, settings, json) ->
-    if settings.searching == true
+    api = $(e.target).DataTable()
+    if @settings.searching == true
       headerViewClass = appConfigurationView.getConfiguration(@options.tableId,'showTableHeader')
       new headerViewClass(
         api : api


remember to restore saved jQuery.get function

--- app/coffee/tests/tests.coffee
+++ app/coffee/tests/tests.coffee
@@ -83,3 +83,4 @@
   equal data.move_no, tesuji_charm.move_no, 'move no in request data'
   equal data.row, 0, 'row no in request data'
   equal data.column, 1, 'column no in request data'
+  $.get = original_get


viewer cache buster

viewer cache buster

--- client/app/Applications/Viewer.kdapplication/AppController.coffee
+++ client/app/Applications/Viewer.kdapplication/AppController.coffee
@@ -95,12 +95,12 @@
   openPath:(path)->
     @path = path
     @clean = no
-    @iframe.$().attr 'src', path
-    @viewerHeader.setPath(path)
+    @iframe.$().attr 'src', "#{path}?#{Date.now()}"
+    @viewerHeader.setPath path

   refreshIFrame:->
-    @iframe.$().contents().location.reload(yes)
-    # @iframe.$().attr 'src', @path
+    # @iframe.$().contents().location.reload(yes)
+    @iframe.$().attr 'src', "#{@path}?#{Date.now()}"

   isDocumentClean:->
     @clean


Fix dismissal of modal as another appears

--- client/controllers/incidentReports/suggestedIncidentsModal.coffee
+++ client/controllers/incidentReports/suggestedIncidentsModal.coffee
@@ -227,7 +227,7 @@
   )

 Template.suggestedIncidentsModal.onRendered ->
-  $('#sourceModal').on 'hidden.bs.modal', ->
+  $('#event-source').on 'hidden.bs.modal', ->
     $('body').addClass('modal-open')

 Template.suggestedIncidentsModal.helpers


Use require.resolve to lookup stylesheet path

--- spec/atom-spec.coffee
+++ spec/atom-spec.coffee
@@ -289,9 +289,9 @@
         it "removes the package's stylesheets", ->
           atom.activatePackage('package-with-stylesheets')
           atom.deactivatePackage('package-with-stylesheets')
-          one = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/1.css")
-          two = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/2.less")
-          three = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/3.css")
+          one = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/1.css")
+          two = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/2.less")
+          three = require.resolve("./fixtures/packages/package-with-stylesheets-manifest/stylesheets/3.css")
           expect(stylesheetElementForId(one)).not.toExist()
           expect(stylesheetElementForId(two)).not.toExist()
           expect(stylesheetElementForId(three)).not.toExist()


Fix logic around not tracking rejections to changes

--- services/web/public/coffee/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.coffee
+++ services/web/public/coffee/ide/editor/directives/aceEditor/track-changes/TrackChangesManager.coffee
@@ -67,8 +67,13 @@
 								@nextUpdateMetaData = null
 						else
 							user_id = window.user.id
-
+
+						was_tracking = @changesTracker.track_changes
+						if @dont_track_next_update
+							@changesTracker.track_changes = false
+							@dont_track_next_update = false
 						@applyChange(e, { user_id })
+						@changesTracker.track_changes = was_tracking

 						# TODO: Just for debugging, remove before going live.
 						setTimeout () =>
@@ -122,8 +127,7 @@
 			change = @changesTracker.getChange(change_id)
 			return if !change?
 			@changesTracker.removeChangeId(change_id)
-			is_tracking = @changesTracker.track_changes
-			@changesTracker.track_changes = false
+			@dont_track_next_update = true
 			session = @editor.getSession()
 			if change.op.d?
 				content = change.op.d
@@ -138,9 +142,7 @@
 				session.remove({start, end})
 			else
 				throw new Error("unknown change: #{JSON.stringify(change)}")
-			setTimeout () =>
-				@changesTracker.track_changes = is_tracking
-			, 0
+

 		checkMapping: () ->
 			session = @editor.getSession()


improve coffee-script tests

improve coffee-script tests

The lines removed aren't valid coffeescript (anymore?).
The last line of code wasn't invalid, but not that realistic and we counted wrong. Coffee compiles it to an empty string. (coffeescript 1.10.0)
I also added a source only line, just for fun.

--- spec/languages.coffee
+++ spec/languages.coffee
@@ -5,23 +5,19 @@
       code:
         """
           # a
+          code()
           source.code() # comment

           ### block
           comment # commented comment
           ###
-          source() ### one line block ###
-          ### one line block ### code()
-          ### block ### code() ###
-          ### souce() # comment ### no block ###
-          ###### code() ###### code()
-        """
-      comment: 10
-      source: 6
-      single: 3
-      block: 8
-      total: 11
-      mixed: 6
+        """
+      comment: 5
+      source: 2
+      single: 2
+      block: 3
+      total: 7
+      mixed: 1
       empty: 1
     }
     {


Add test for resolved refs

Add test for resolved refs

--- spec/main-spec.coffee
+++ spec/main-spec.coffee
@@ -34,4 +34,8 @@

               expect(test.data).toHaveSchema schemas[0], refs

+            if test.refs
+              for ref in test.refs
+                expect(Object.keys(refs)).toContain ref
+
             done()


Stop focusing specs on "Pane"

Stop focusing specs on "Pane"

--- spec/pane-spec.coffee
+++ spec/pane-spec.coffee
@@ -3,7 +3,7 @@
 PaneAxis = require '../src/pane-axis'
 PaneContainer = require '../src/pane-container'

-fdescribe "Pane", ->
+describe "Pane", ->
   deserializerDisposable = null

   class Item extends Model


Close tabs per default.

Close tabs per default.

--- app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom/attribute_bar.coffee
@@ -14,7 +14,7 @@
   constructor: ->
     super

-    @secondaryAction = @preferencesGet() || 'stayOnTab'
+    @secondaryAction = @preferencesGet() || 'closeTab'
     if !@overview_id && @secondaryAction is 'closeNextInOverview'
       @secondaryAction = 'closeTab'


Set html as null when changing payment method

We are getting a conflit on JS because of init-partial-js

--- app/assets/javascripts/neighborly/projects/contributions/edit.js.coffee
+++ app/assets/javascripts/neighborly/projects/contributions/edit.js.coffee
@@ -33,7 +33,7 @@

         if $payment.data('path')
           $.get($payment.data('path')).success (data) =>
-            this.$('.payment-method').hide()
+            this.$('.payment-method').html('')
             $payment.html data
             Initjs.initializePartial()
             $payment.show()


'component' uses breadth-first search for modules

--- component.coffee
+++ component.coffee
@@ -68,7 +68,7 @@

 allNodeModules = () ->
   modules = {}
-  t.dfs directories = {path: "."}, (n) ->
+  t.bfs directories = {path: "."}, (n) ->
     if exists join(n.path, "package.json")
       n.json = pkgJson n.path
     if exists join(n.path, "requirejs-config.json")
@@ -84,7 +84,7 @@
 allComponents = () ->
   results = []
   names = () -> component.json.name for component in results
-  t.dfs allNodeModules(), (m) ->
+  t.bfs allNodeModules(), (m) ->
     if m.json and isComponent(null, m.json) and m.json.name not in names()
       results.push(m)
   _.filter results, (m) -> m.path isnt "."
@@ -101,7 +101,7 @@
   dir = argv.staticpath
   return [] if not exists dir
   results = []
-  t.dfs dirTree = {path: "."}, (n) ->
+  t.bfs dirTree = {path: "."}, (n) ->
     if /test[^\/]*\.js$/.test(n.path) and basename(n.path)[0] isnt "."
       results.push(n.path)
     if fs.statSync(join(dir, n.path)).isDirectory()


Rename.

Rename.

--- src/Session/Session.coffee
+++ src/Session/Session.coffee
@@ -16,8 +16,8 @@
     getMasterKey: ->
       @user.masterKey

-    getRootFolder: ->
-      @user.rootFolder
+    getRootFolderId: ->
+      @user.rootFolderId

     isConnected: ->
       @user.login?


removed unused properties on shipments ember controller

--- app/assets/javascripts/trade/controllers/shipments_controller.js.coffee
+++ app/assets/javascripts/trade/controllers/shipments_controller.js.coffee
@@ -20,15 +20,6 @@
     return false unless @get('content.isLoaded')
     @get('content').filterBy('isSaving', true).length > 0
   ).property('content.@each.isSaving')
-
-  unsavedChanges: (->
-    @get('changedRowsCount') > 0
-  ).property('changedRowsCount')
-
-  changedRowsCount: (->
-    return false unless @get('content.isLoaded')
-    @get('content').filterBy('isDirty', true).length
-  ).property('content.@each.isDirty')

   total: ( ->
     @get('content.meta.total')


Fix indentation

Fix indentation

--- chrome/src/bootstrap.coffee
+++ chrome/src/bootstrap.coffee
@@ -1,12 +1,12 @@
-#  This is the bootstrapping code that sets up the scripts to be used in the
+#  This is the bootstrapping code that sets up the scripts to be used in the
 #  Gmailr example Chrome plugin.

 if top.document is document
-    yepnope
-        test: !jQuery?
-        yep: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'
-    yepnope [
-        chrome.extension.getURL "lib/jquery-bbq/jquery.ba-bbq.min.js"
-        chrome.extension.getURL "lib/gmailr.js"
-        chrome.extension.getURL "main.js"
-    ]+  yepnope
+    test: !jQuery?
+    yep: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'
+  yepnope [
+    chrome.extension.getURL "lib/jquery-bbq/jquery.ba-bbq.min.js"
+    chrome.extension.getURL "lib/gmailr.js"
+    chrome.extension.getURL "main.js"
+  ]


mongo import: date fields converted to milliseconds

--- data/imports/aiddata.coffee
+++ data/imports/aiddata.coffee
@@ -306,15 +306,22 @@
     os.mkdir TEMP_DIR
     fd = fs.openSync(AIDDATA_TEMP_FILE, 'w')

+    epochMillis = (field, q) -> "EXTRACT(EPOCH FROM #{q})*1000 AS #{field}"
+
+    dateFields = [
+      epochMillis("date", "COALESCE(commitment_date, start_date, to_timestamp(to_char(year, '9999'), 'YYYY'))"),
+      epochMillis("start_date", "start_date"),
+      epochMillis("commitment_date", "commitment_date"),
+      epochMillis("end_date", "end_date"),
+    ].join(',')
+
     query = pgclient.query "
-      SELECT
-        *,
-        COALESCE(commitment_date, start_date, to_timestamp(to_char(year, '9999'), 'YYYY'))
-          AS date_coalesced
-      FROM
-        aiddata2
-      #{if DEBUG_updateRowsLimit? then 'LIMIT '+DEBUG_updateRowsLimit}
-    "
+        SELECT
+          *, #{dateFields}
+        FROM
+          aiddata2
+        #{if DEBUG_updateRowsLimit? then 'LIMIT '+DEBUG_updateRowsLimit}
+      "
     query.on 'row', (row) ->

       if OMIT_NULL_VALUE_FIELDS_IN_COMMITMENTS_JSON


analytics: send user info from client side to segment

--- client/Main/mixpanel.coffee
+++ client/Main/mixpanel.coffee
@@ -4,22 +4,42 @@
   KD.getSingleton('mainController').on "AccountChanged", (account) ->
     return  unless KD.isLoggedIn() and account and analytics

-    {type, meta, profile} = account
-
+    {_id, meta, profile} = account
     return  unless profile

-    {createdAt} = meta
-    {firstName, lastName, nickname} = profile
+    KD.utils.defer ->
+      KD.remote.api.JUser.fetchUser (err, user)->
+        return  if err or not user

-    # register user to mixpanel
-    analytics.identify nickname, {
-      "$username"     : nickname
-      "$first_name"   : firstName
-      "$last_name"    : lastName
-      "$created"      : createdAt
-      "Status"        : type
-      "Randomizer"    : KD.utils.getRandomNumber 4
-    }
+        {firstName, lastName, nickname} = profile
+        {email, lastLoginDate, status, emailFrequency, foreignAuth, sshKeys} = user
+
+        # only care about existence of 3rd party auth, not the values
+        providers = {}
+        if foreignAuth
+          for own provider, providerInfo of foreignAuth
+            # check if values isn't empty object
+            providers[provider] = yes  if Object.keys(providerInfo).length > 0
+
+        KD.singletons.paymentController.subscriptions (err, subscription)->
+          plan = "error fetching plan" if err
+          args =
+            "$id"          : _id
+            "$username"    : nickname
+            "$first_name"  : firstName
+            "$last_name"   : lastName
+            "$created"     : meta?.createdAt
+            "$email"       : email
+            subscription   : subscription
+            lastLoginDate  : lastLoginDate
+            status         : status
+            emailFrequency :
+              marketing    : emailFrequency?.marketing
+              global       : emailFrequency?.global
+            foreignAuth    : providers      if Object.keys(providers).length > 0
+            sshKeysCount   : sshKeys.length if sshKeys?.length > 0
+
+          analytics.identify nickname, args

 # Access control wrapper around mixpanel object.
 KD.mixpanel = (args...)->


Apply same progress bar logic and styles to machine state modal

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -661,6 +661,11 @@
     machineItem.getBaseKite( no ).disconnect()

     if @machineStateModal
+
+      if not isKoding() and event.status is Stopping
+        event.percentage = 100 - event.percentage
+        @machineStateModal.unsetClass 'full'
+
       @machineStateModal.updateStatus event
     else
       {state}   = machineItem.status
@@ -675,8 +680,12 @@

     { state, container, machineItem, initial } = options

-    container   ?= @getView()
-    modalOptions = { state, container, initial }
+    container            ?= @getView()
+    modalOptions          = { state, container, initial }
+
+    if not isKoding() and state is Stopping
+      modalOptions.cssClass = 'env-machine-state team full'
+
     @machineStateModal = new EnvironmentsMachineStateModal modalOptions, machineItem

     @machineStateModal.once 'KDObjectWillBeDestroyed', => @machineStateModal = null


disable authorship/multi-cursor for now

disable authorship/multi-cursor for now

--- demo/scripts/advanced.coffee
+++ demo/scripts/advanced.coffee
@@ -33,7 +33,7 @@
     console.assert(decomposeDelta.startLength == decomposeDelta.endLength and isEqual, "Editor diversion!", source, target, sourceDelta, targetDelta) if console?
   ).on(Quill.events.SELECTION_CHANGE, (range) ->
     return unless range?
-    target.getModule('multi-cursor').moveCursor(source.id, range.end)
+    # target.getModule('multi-cursor').moveCursor(source.id, range.end)
   )

@@ -43,22 +43,22 @@
   $container = $('.editor-container', $wrapper)
   editor = new Quill($container.get(0), {
     modules:
-      'multi-cursor': true
+      # 'multi-cursor': true
       'toolbar': { container: $('.toolbar-container', $wrapper).get(0) }
       'link-tooltip': true
       'image-tooltip': true
     theme: 'snow'
   })
-  authorship = editor.addModule('authorship', {
-    authorId: editor.id
-    color: getColor(num, true)
-    button: $('.sc-authorship', $wrapper).get(0)
-  })
+  # authorship = editor.addModule('authorship', {
+  #   authorId: editor.id
+  #   color: getColor(num, true)
+  #   button: $('.sc-authorship', $wrapper).get(0)
+  # })
   editors.push(editor)

 listenEditor(editors[0], editors[1])
 listenEditor(editors[1], editors[0])
-editors[0].getModule('authorship').addAuthor(editors[1].id, getColor(editors[1].id, true))
-editors[1].getModule('authorship').addAuthor(editors[0].id, getColor(editors[0].id, true))
-editors[0].getModule('multi-cursor').setCursor(editors[1].id, 0, editors[1].id, getColor(editors[1].id))
-editors[1].getModule('multi-cursor').setCursor(editors[0].id, 0, editors[0].id, getColor(editors[0].id))
+# editors[0].getModule('authorship').addAuthor(editors[1].id, getColor(editors[1].id, true))
+# editors[1].getModule('authorship').addAuthor(editors[0].id, getColor(editors[0].id, true))
+# editors[0].getModule('multi-cursor').setCursor(editors[1].id, 0, editors[1].id, getColor(editors[1].id))
+# editors[1].getModule('multi-cursor').setCursor(editors[0].id, 0, editors[0].id, getColor(editors[0].id))


change logic of displaying noPR builds message

--- app/controllers/builds.coffee
+++ app/controllers/builds.coffee
@@ -22,7 +22,9 @@
   ).property('tab', 'lastObject.number')

   displayPullRequests: (->
-    if @get('tab') == 'pull_requests'
+    if Ember.isEmpty(@get('repo.builds.content'))
+      return false # if there is no build there is no PR
+    else if Ember.isEmpty(@get('repo.pullRequests.content'))
       return true
     else
       return false


Prevent adding user with null id

Prevent adding user with null id

--- resources/assets/coffee/react/beatmap-discussions/user-filter.coffee
+++ resources/assets/coffee/react/beatmap-discussions/user-filter.coffee
@@ -27,9 +27,9 @@

   render: =>
-    options = [allUsers]
-    for own _id, user of @props.users
-      options.push @mapUserProperties(user)
+    options = for own _id, user of @props.users when user.id?
+      @mapUserProperties(user)
+    options.unshift(allUsers)

     selected = if @props.selectedUser?
                  @mapUserProperties(@props.selectedUser)


Fix trying to load the image 'undefined'

--- app/core/mixins/Visual.coffee
+++ app/core/mixins/Visual.coffee
@@ -12,7 +12,7 @@
       normal: 1

     @atlas = new Image()
-    @atlas.src = pathToAtlas
+    @atlas.src = pathToAtlas if pathToAtlas

     @tileSet =
       tilesX: 0


use Errors.InvalidName instead of plain Error object

--- services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
+++ services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
@@ -182,7 +182,7 @@
 	_addDocWithProject: (project, folder_id, docName, docLines, userId, callback = (error, doc, folder_id, path) ->)=>
 		# check if docname is allowed
 		if not SafePath.isCleanFilename docName
-			return callback new Error("invalid element name")
+			return callback new Errors.InvalidNameError("invalid element name")
 		project_id = project._id
 		logger.log project_id: project_id, folder_id: folder_id, doc_name: docName, "adding doc to project with project"
 		confirmFolder project, folder_id, (folder_id)=>
@@ -207,7 +207,7 @@
 	restoreDoc: (project_id, doc_id, name, callback = (error, doc, folder_id) ->) ->
 		# check if docname is allowed (passed in from client so we check it)
 		if not SafePath.isCleanFilename name
-			return callback new Error("invalid element name")
+			return callback new Errors.InvalidNameError("invalid element name")
 		# getDoc will return the deleted doc's lines, but we don't actually remove
 		# the deleted doc, just create a new one from its lines.
 		ProjectEntityHandler.getDoc project_id, doc_id, include_deleted: true, (error, lines) ->
@@ -217,7 +217,7 @@
 	addFileWithoutUpdatingHistory: (project_id, folder_id, fileName, path, userId, callback = (error, fileRef, folder_id, path, fileStoreUrl) ->)->
 		# check if file name is allowed
 		if not SafePath.isCleanFilename fileName
-			return callback new Error("invalid element name")
+			return callback new Errors.InvalidNameError("invalid element name")
 		ProjectGetter.getProject project_id, {rootFolder:true, name:true}, (err, project) ->
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add file"
@@ -362,7 +362,7 @@
 	addFolderWithProject: (project, parentFolder_id, folderName, callback = (err, folder, parentFolder_id)->) ->
 		# check if folder name is allowed
 		if not SafePath.isCleanFilename folderName
-			return callback new Error("invalid element name")
+			return callback new Errors.InvalidNameError("invalid element name")
 		confirmFolder project, parentFolder_id, (parentFolder_id)=>
 			folder = new Folder name: folderName
 			logger.log project: project._id, parentFolder_id:parentFolder_id, folderName:folderName, "adding new folder"
@@ -466,7 +466,7 @@
 	renameEntity: (project_id, entity_id, entityType, newName, userId, callback)->
 		# check if name is allowed
 		if not SafePath.isCleanFilename newName
-			return callback new Error("invalid element name")
+			return callback new Errors.InvalidNameError("invalid element name")
 		logger.log(entity_id: entity_id, project_id: project_id, ('renaming '+entityType))
 		if !entityType?
 			logger.err err: "No entityType set", project_id: project_id, entity_id: entity_id
@@ -613,7 +613,7 @@
 		# original check path.resolve("/", element.name) isnt "/#{element.name}" or element.name.match("/")
 		# check if name is allowed
 		if not SafePath.isCleanFilename element.name
-			e = new Error("invalid element name")
+			e = new Errors.InvalidNameError("invalid element name")
 			logger.err project_id:project._id, folder_id:folder_id, element:element, type:type, "failed trying to insert element as name was invalid"
 			return callback(e)


Clearer names

Clearer names

--- core/app/assets/javascripts/lib/prevent_scroll_propagation.coffee
+++ core/app/assets/javascripts/lib/prevent_scroll_propagation.coffee
@@ -2,8 +2,8 @@

 $.fn.preventScrollPropagation = ->
   @each ->
-    $(this).bind 'mousewheel', (e, d) ->
-      if d > 0 && $(this).scrollTop() <= 0
-        e.preventDefault()
-      else if d < 0 && $(this).scrollTop() >= $(this).get(0).scrollHeight - $(this).innerHeight()
-        e.preventDefault()
+    $(this).bind 'mousewheel', (event, delta) ->
+      if delta > 0 && $(this).scrollTop() <= 0
+        event.preventDefault()
+      else if delta < 0 && $(this).scrollTop() >= $(this).get(0).scrollHeight - $(this).innerHeight()
+        event.preventDefault()


Removed comment

Removed comment

--- core/app/backbone/views/fact_relations/fact_relations_view.coffee
+++ core/app/backbone/views/fact_relations/fact_relations_view.coffee
@@ -49,7 +49,6 @@
     @interactingUserRegion.show new InteractorsView
       collection: @model.getInteractors()

-    # Todo: add to initialize?
     @commentsRegion.show new CommentsListView
       collection: @model.comments()


experimental...

experimental...

--- mos.coffee
+++ mos.coffee
@@ -39,13 +39,13 @@
   .command 'build'
   .description 'Build Mos'
   .action (env, options)->
-    console.log 'Extracting boot record from disk image...'
-    executeCommand 'dd if=disks/mos16.img of=build/boot-record conv=notrunc bs=1 skip=3 count=59'
-    console.log '\nBuilding boot code...'
+    console.log 'Extracting BIOS Parameter Block from disk image...'
+    executeCommand 'dd if=disks/mos16.img of=build/bpb conv=notrunc bs=1 skip=3 count=59'
+    console.log '\nBuilding boot sector...'
     executeCommand 'nasm -f bin source/boot16.asm -o build/boot16'
-    console.log '\nWriting boot record to boot code...'
-    executeCommand 'dd if=build/boot-record of=build/boot16 conv=notrunc bs=1 count=59 seek=3'
-    console.log '\nWriting boot code to disk image...'
+    console.log '\nWriting BIOS Parameter Block to boot sector...'
+    executeCommand 'dd if=build/bpb of=build/boot16 conv=notrunc bs=1 count=59 seek=3'
+    console.log '\nWriting boot sector to disk image...'
     executeCommand 'dd if=build/boot16 of=disks/mos16.img conv=notrunc'

 program


Implemented auto-discovery for pimatic 0.9

--- denon-avr.coffee
+++ denon-avr.coffee
@@ -6,11 +6,25 @@
   net = require 'net'
   _ = env.require 'lodash'
   commons = require('pimatic-plugin-commons')(env)
-  devices = [
-    'denon-avr-presence-sensor'
-    'denon-avr-power-switch'
-    'denon-avr-mute-switch'
-    'denon-avr-master-volume'
+  deviceConfigTemplates = [
+    {
+      "name": "Denon AVR Status",
+      "class": "DenonAvrPresenceSensor",
+      "volumeDecibel": true,
+    },
+    {
+      "name": "Denon AVR Power",
+      "class": "DenonAvrPowerSwitch"
+    },
+    {
+      "name": "Denon AVR Mute",
+      "class": "DenonAvrMuteSwitch"
+    },
+    {
+      "name": "Denon AVR Master Volume",
+      "class": "DenonAvrMasterVolume",
+      "maxAbsoluteVolume": 89.5
+    }
   ]
   commands =
     POWER: /^(PW)([A-Z]+)/
@@ -36,15 +50,32 @@

       # register devices
       deviceConfigDef = require("./device-config-schema")
-      for device in devices
-        # convert kebap-case to camel-case notation with first character capitalized
-        className = device.replace /(^[a-z])|(\-[a-z])/g, ($1) -> $1.toUpperCase().replace('-','')
-        classType = require('./devices/' + device)(env)
+      for device in deviceConfigTemplates
+        className = device.class
+        # convert camel-case classname to kebap-case filename
+        filename = className.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
+        classType = require('./devices/' + filename)(env)
         @_base.debug "Registering device class #{className}"
         @framework.deviceManager.registerDeviceClass(className, {
           configDef: deviceConfigDef[className],
           createCallback: @_callbackHandler(className, classType)
         })
+
+      # auto-discovery
+      @framework.deviceManager.on('discover', (eventData) =>
+        @framework.deviceManager.discoverMessage 'pimatic-denon-avr', 'Searching for AVR controls'
+        for device in deviceConfigTemplates
+          matched = @framework.deviceManager.devicesConfig.some (element, iterator) =>
+            #console.log element.class is device.class, element.class, device.class
+            element.class is device.class
+
+          if not matched
+            process.nextTick @_discoveryCallbackHandler('pimatic-denon-avr', device.name, device)
+      )
+
+    _discoveryCallbackHandler: (pluginName, deviceName, deviceConfig) ->
+      return () =>
+        @framework.deviceManager.discoveredDevice pluginName, deviceName, deviceConfig

     _callbackHandler: (className, classType) ->
       # this closure is required to keep the className and classType context as part of the iteration


Calculator fixes: [#3739033], [#3739040]

[#3739033] -- pi should multiply when against a number.
[#3739040] -- parentheticals should multiply when against a number.

--- javascripts/lib/math.coffee
+++ javascripts/lib/math.coffee
@@ -434,6 +434,7 @@

   class_mixer(_ImplicitMultiplication)

+
   class _OverrideIfOperatorOrAppend
     initialize: (@expression)->
     with: (operator)->


Remove unused PackageView class

Remove unused PackageView class

--- lib/package-view.coffee
+++ lib/package-view.coffee
@@ -1,179 +0,0 @@
-url = require 'url'
-semver = require 'semver'
-packageManager = require './package-manager'
-{$, $$, View} = require 'atom'
-_ = require 'underscore-plus'
-atom.requireWithGlobals 'bootstrap/js/dropdown', jQuery: $
-
-module.exports =
-class PackageView extends View
-  @content: ->
-    @div class: 'bordered panel block package-view', =>
-      @div outlet: 'heading', class: 'panel-heading', =>
-        @span outlet: 'name'
-        @span outlet: 'version', class: 'label'
-        @span outlet: 'update', class: 'label label-info', 'Update Available'
-        @span outlet: 'disabedLabel', class: 'label label-warning', 'Disabled'
-        @div class: 'btn-group pull-right', =>
-          @button outlet: 'defaultAction', class: 'btn btn-small'
-          @button outlet: 'dropdownButton', class: 'btn btn-small dropdown-toggle', 'data-toggle': 'dropdown', =>
-            @span class: 'caret'
-          @ul outlet: 'dropdown', class: 'dropdown-menu', =>
-            @li outlet: 'enableToggle', => @a 'Disable'
-            @li outlet: 'homepage', => @a 'Visit homepage'
-            @li outlet: 'issues', => @a 'Report issue'
-      @div class: 'padded panel-body', =>
-        @div outlet: 'description'
-        @ul class: 'list-group list-group-flush', =>
-          @li outlet: 'readmeArea', class: 'list-item', =>
-            @a 'Show README', outlet: 'readmeLink'
-            @div class: 'readme', outlet: 'readme'
-
-  pack: null
-  metadata: null
-  installed: false
-  disabled: false
-  bundled: false
-  updateAvailable: false
-
-  initialize: (pack, @packageEventEmitter) ->
-    if pack?.metadata?
-      @pack = pack
-      @metadata = @pack.metadata
-    else
-      @metadata = pack
-
-    @updatePackageState()
-
-    @attr('name', @metadata.name)
-    @name.text(@metadata.name)
-    if version = semver.valid(@metadata.version)
-      @version.text(version)
-    else
-      @version.hide()
-
-    if @metadata.descriptionHtml
-      @description.html(@metadata.descriptionHtml)
-    else if @metadata.description
-      @description.text(@metadata.description)
-    else
-      @description.text('No further description available.')
-
-    @readme.hide()
-    if @metadata.readmeHtml
-      @readme.html(@metadata.readmeHtml)
-    else if @metadata.readme
-      @readme.text(@metadata.readme)
-    else
-      @readmeArea.hide()
-
-    @readmeLink.on 'click', =>
-      if @readme.isVisible()
-        @readme.hide()
-        @readmeLink.text('Show README')
-      else
-        @readme.show()
-        @readmeLink.text('Hide README')
-
-    homepage = @metadata.homepage
-    unless homepage
-      if _.isString(@metadata.repository)
-        repoUrl = @metadata.repository
-      else
-        repoUrl = @metadata.repository?.url
-      if repoUrl
-        repoUrl = repoUrl.replace(/.git$/, '')
-        homepage = repoUrl if url.parse(repoUrl).host is 'github.com'
-    if homepage
-      @homepage.find('a').attr('href', homepage)
-    else
-      @homepage.hide()
-
-    if issues = @metadata.bugs?.url
-      @issues.find('a').attr('href', issues)
-    else
-      @issues.hide()
-
-    @defaultAction.on 'click', =>
-      if @installed and @bundled
-        @togglePackageEnablement()
-        return
-
-      @defaultAction.disable()
-      if @installed
-        if @updateAvailable
-          @defaultAction.text('Upgrading\u2026')
-          packageManager.install @metadata, (error) =>
-            @packageEventEmitter.emit('package-upgraded', error, @metadata)
-        else
-          @defaultAction.text('Uninstalling\u2026')
-          packageManager.uninstall @metadata, (error) =>
-            @packageEventEmitter.emit('package-uninstalled', error, @metadata)
-      else
-        @defaultAction.text('Installing\u2026')
-        packageManager.install @metadata, (error) =>
-          @packageEventEmitter.emit('package-installed', error, @metadata)
-
-    @updateDefaultAction()
-
-    @enableToggle.find('a').on 'click', => @togglePackageEnablement()
-
-    @observeConfig 'core.disabledPackages', =>
-      @updatePackageState()
-      @updateDefaultAction()
-      @updateEnabledState()
-
-    @packageEventEmitter.on 'package-installed package-uninstalled package-upgraded', (error, metadata) =>
-      if metadata?.name is @metadata.name
-        @defaultAction.enable()
-        @updatePackageState()
-        @updateDefaultAction()
-
-  togglePackageEnablement: ->
-    if @disabled
-      atom.packages.enablePackage(@metadata.name)
-    else
-      atom.packages.disablePackage(@metadata.name)
-
-  updatePackageState: ->
-    @disabled = atom.packages.isPackageDisabled(@metadata.name)
-    @updateAvailable = false
-    @bundled = false
-    loadedPackage = atom.packages.getLoadedPackage(@metadata.name)
-    packagePath = loadedPackage?.path ? atom.packages.resolvePackagePath(@metadata.name)
-    @installed = packagePath?
-    if @installed
-      @bundled = atom.packages.isBundledPackage(@metadata.name)
-      version = loadedPackage?.metadata.version
-      @updateAvailable = semver.gt(@metadata.version, version)
-
-    if @updateAvailable
-      @update.show()
-    else
-      @update.hide()
-
-  updateEnabledState: ->
-    enableLink = @enableToggle.find('a')
-    if @disabled
-      enableLink.text('Enable')
-      @disabedLabel.show()
-    else
-      enableLink.text('Disable')
-      @disabedLabel.hide()
-
-    @enableToggle.hide() unless @installed
-
-  updateDefaultAction: ->
-    if @installed
-      if @bundled
-        if @disabled
-          @defaultAction.text('Enable')
-        else
-          @defaultAction.text('Disable')
-      else
-        if @updateAvailable
-          @defaultAction.text('Upgrade')
-        else
-          @defaultAction.text('Uninstall')
-    else
-      @defaultAction.text('Install')


Added comments to Tabs.coffee

Added comments to Tabs.coffee

--- src/Tabs.coffee
+++ src/Tabs.coffee
@@ -1,18 +1,27 @@
 ###
-Tabs.coffee
+
+The tabbed interface handler.

 @author Destin Moulton
 @git https://github.com/destinmoulton/cagen
 @license MIT

-Component of Cellular Automata Generator (CAGEN)
+Component of Cellular Automata GENerator (CAGEN)

-Manage the tabs for the various cagen features
+
+Manage the tabs for the various CAGEN features.

 ###

 class Tabs
+
+    #
+    # Setup the local shared variables
+    # @constructor
+    #
     constructor: (VariablesInstance)->
+        @_Vars = VariablesInstance
+
         @_classActive = "active"

         @_idRuleThumbnailsTab = "#tab-rulethumbnails"
@@ -25,8 +34,9 @@
             "dashboard"
             ]

-        @_Vars = VariablesInstance
-
+    #
+    # Start the tabbed interface
+    #
     start:()->
         # Show the rule thumbnails first
         @showRuleThumbnailsTab()
@@ -40,29 +50,44 @@
         # Click the Dashboard tab
         $(@_idDashboardTab).click((event)=>@showDashboardTab())

+    #
+    # Activate a tab via string name
+    #
     activate: (tabName)->
         for tab in @_tabs
             $(@_tabIdPrefix+tab).removeClass(@_classActive)

         $(@_tabIdPrefix+tabName).addClass(@_classActive)

+    #
+    # Setup the instances for the CAGEN features
+    #
     setClassInstances: (RuleThumbnailsInstance, TopRowEditorInstance, DashboardInstance)->
         @_RuleThumbnails = RuleThumbnailsInstance
         @_TopRowEditor = TopRowEditorInstance
         @_Dashboard = DashboardInstance

+    #
+    # Show the Rule Thumbnails tab
+    #
     showRuleThumbnailsTab:() ->
         # Activate the tab
         @activate('rulethumbnails')

         @_RuleThumbnails.show()

+    #
+    # Show the Top Row Editor tab
+    #
     showTopRowEditorTab:() ->
         # Activate the tab
         @activate('toproweditor')

         @_TopRowEditor.run()

+    #
+    # Show the Dashboard tab
+    #
     showDashboardTab:() ->
         # Activate the tab
         @activate('dashboard')


Use `_.each` instead.

Use `_.each` instead.

--- scripts/feed_checker.coffee
+++ scripts/feed_checker.coffee
@@ -51,7 +51,7 @@
     robot.brain.data.feed_check ||= {}
     robot.brain.data.feed_check_user ||= {}
     feed_check_interval = setInterval ->
-      for url, prev of robot.brain.data.feed_check
+      _.each robot.brain.data.feed_check, (prev, url) ->
         robot.logger.debug "checking feed: #{url}"

         next = []