component refactor

component refactor

--- app/assets/javascripts/components/user_profile/header/view.js.coffee
+++ app/assets/javascripts/components/user_profile/header/view.js.coffee
@@ -8,35 +8,8 @@
   render: ->
     name = "#{@props.user.first_name} #{@props.user.last_name}"

-    location = if !_.isBlank(@props.user.city) || !_.isBlank(@props.user.country)
-      (p className: "info__location",
-        (i className: "fa fa-map-marker")
-        (span null, [@props.user.country, @props.user.city].join(', ')))
-
     header_styles = unless _.isBlank(@props.user.cover_url)
       {backgroundImage: "url(#{@props.user.cover_url})"}
-
-    # links
-    website = unless _.isBlank(@props.user.website)
-      (li className: 'contacts__links_item',
-        (a target: '_blank', href: @props.user.website,
-          (i className: 'item__website-icon fa fa-globe')
-          (span null, @props.user.website)))
-
-    twitter = unless _.isBlank(@props.user.twitter_link)
-      (li className: 'contacts__links_item',
-        (a target: '_blank', href: @props.user.twitter_link,
-          (i className: 'fa fa-twitter')))
-
-    facebook = unless _.isBlank(@props.user.fb_link)
-      (li className: 'contacts__links_item',
-        (a target: '_blank', href: @props.user.fb_link,
-          (i className: 'fa fa-facebook')))
-
-    linked_in = unless _.isBlank(@props.user.linkedin_link)
-      (li className: 'contacts__links_item',
-        (a target: '_blank', href: @props.user.linkedin_link,
-          (i className: 'fa fa-linkedin')))

     (div className: "profile-card__header", style: header_styles,
       (div className: "container",
@@ -49,12 +22,12 @@
               (h4 className: "info__name media-heading", name)
               (p className: "info__profession")

-              location
+              @_get_location()

               (div className: "header__edit",
                 (button type: "button", className: "btn_edit btn btn-primary", onClick: @props.onEdit,
                   (i className: "fa fa-pencil")
-                  (span null, 'Edit'))))))
+                  (span null, 'Edit') )))))

         (div className: "col-xs-12 col-md-4 header__contacts",
           (div className: "row",
@@ -76,10 +49,10 @@

             (div className: "clearfix")
             (ul className: "contacts__links",
-              website
-              twitter
-              facebook
-              linked_in)))
+              @_get_website()
+              @_get_twitter()
+              @_get_facebook()
+              @_get_linked_in() )))

         (div className: "clearfix")))

@@ -88,3 +61,35 @@
       (i className: "header__pic media-object fa fa-user")
     else
       (img className: "input__photo_square", src: @props.user.avatar_url)
+
+  _get_location: ->
+    if !_.isBlank(@props.user.city) || !_.isBlank(@props.user.country)
+      (p className: "info__location",
+        (i className: "fa fa-map-marker")
+        (span null, [@props.user.country, @props.user.city].join(', ')))
+
+  # links
+  _get_website: ->
+    unless _.isBlank(@props.user.website)
+      (li className: 'contacts__links_item',
+        (a target: '_blank', href: @props.user.website,
+          (i className: 'item__website-icon fa fa-globe')
+          (span null, @props.user.website)))
+
+  _get_twitter: ->
+    unless _.isBlank(@props.user.twitter_link)
+      (li className: 'contacts__links_item',
+        (a target: '_blank', href: @props.user.twitter_link,
+          (i className: 'fa fa-twitter')))
+
+  _get_facebook: ->
+    unless _.isBlank(@props.user.fb_link)
+      (li className: 'contacts__links_item',
+        (a target: '_blank', href: @props.user.fb_link,
+          (i className: 'fa fa-facebook')))
+
+  _get_linked_in: ->
+    unless _.isBlank(@props.user.linkedin_link)
+      (li className: 'contacts__links_item',
+        (a target: '_blank', href: @props.user.linkedin_link,
+          (i className: 'fa fa-linkedin')))


bugfix in textarea field

bugfix in textarea field

--- app/assets/javascripts/luca/components/fields/text_area_field.coffee
+++ app/assets/javascripts/luca/components/fields/text_area_field.coffee
@@ -1,18 +1,19 @@
 textArea = Luca.register          "Luca.fields.TextAreaField"
 textArea.extends                  "Luca.core.Field"
 textArea.defines
+  autoBindEventHandlers: true
+
   events:
-    "keydown input" : "keydown_handler"
-    "blur input" : "blur_handler"
-    "focus input" : "focus_handler"
+    "blur textarea" : "blur_handler"
+    "focus textarea" : "focus_handler"

   template: 'fields/text_area_field'

   height: "200px"
   width: "90%"
+  keyEventThrottle: 300

   initialize: (@options={})->
-    _.bindAll @, "keydown_handler"

     @input_id ||= _.uniqueId('field')
     @input_name ||= @name
@@ -24,6 +25,13 @@

     Luca.core.Field::initialize.apply @, arguments

+    if @enableKeyEvents is true
+      @keyup_handler = _.debounce(@keyup_handler, @keyEventThrottle || 10)
+
+      console.log "Registering Key Events"
+      @registerEvent("keyup textarea","keyup_handler")
+      @registerEvent("keydown textarea","keyup_handler")
+
   setValue: (value)->
     $( @field() ).val(value)

@@ -31,13 +39,19 @@
     $( @field() ).val()

   field: ()->
-    @input = $("textarea##{ @input_id }", @el)
+    @input = @$("textarea")

-  keydown_handler: (e)->
-    me = my = $( e.currentTarget )
+  keyup_handler: (e)->
+    # TODO: Should ignore certain keyup events
+    # which would not indicate a change
+    @trigger "on:change", @, e
+    @trigger "on:keyup", @, e

   blur_handler: (e)->
-    me = my = $( e.currentTarget )
+    @trigger "on:blur", @, e

   focus_handler: (e)->
-    me = my = $( e.currentTarget )+    @trigger "on:focus", @, e
+
+  change_handler: (e)->
+    @trigger "on:change", @, e


removed some chicken scratch from check_group.js.coffee

--- app/assets/javascripts/states/monitoring/views/check_group.js.coffee
+++ app/assets/javascripts/states/monitoring/views/check_group.js.coffee
@@ -11,7 +11,6 @@
       "click #delete_check": (e) ->
         v = @
         @check.destroy success: (model, response) ->
-          # v.parent.redraw()
         v.transition "mon_view_host", {host: @host}
     }


Fix `log` coloring so that it doesn't color `.log`


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -2,9 +2,10 @@

 App = {}

-
-
 test "should not be destroyed when inside activeBounds", ->
+  App.width = 640
+  App.height = 480
+
   obj = GameObject
     x: 50
     y: 50


Make FileList lists objects instead of arrays.

--- src/fs_utils/file_list.coffee
+++ src/fs_utils/file_list.coffee
@@ -22,9 +22,9 @@
     @assets = []
     @on 'change', @_change
     @on 'unlink', @_unlink
-    @compiling = []
-    @compiled = []
-    @copying = []
+    @compiling = {}
+    @compiled = {}
+    @copying = {}

   getAssetErrors: ->
     invalidAssets = @assets.filter((asset) -> asset.error?)
@@ -69,9 +69,9 @@
         .forEach (file, index) =>
           @files.splice index, 1

-      if @compiling.length is 0 and @copying.length is 0
+      if Object.keys(@compiling).length is 0 and Object.keys(@copying).length is 0
         @emit 'ready'
-        @compiled = []
+        @compiled = {}
       else
         @resetTimer()
     , @RESET_TIME
@@ -89,29 +89,31 @@
       .filter (dependent) =>
         path in dependent.dependencies
       .filter (dependent) =>
-        dependent not in @compiled
+        @compiled[dependent.path]
       .forEach(@compile)

   compile: (file) =>
-    if @compiling.indexOf(file) == -1
-      @compiling.push(file)
+    path = file.path
+    if @compiling[path]
+      @resetTimer()
+    else
+      @compiling[path] = true
       file.compile (error) =>
-        @compiling.splice @compiling.indexOf(file), 1
+        delete @compiling[path]
         @resetTimer()
         return if error?
-        debug "Compiled file '#{file.path}'..."
-        @compiled.push file
-        @compileDependentFiles file.path
-    else
-      @resetTimer()
+        debug "Compiled file '#{path}'..."
+        @compiled[path] = true
+        @compileDependentFiles path

   copy: (asset) =>
-    @copying.push asset
+    path = asset.path
+    @copying[path] = true
     asset.copy (error) =>
-      @copying.splice @copying.indexOf(asset), 1
+      delete @copying[path]
       @resetTimer()
       return if error?
-      debug "Copied asset '#{asset.path}'"
+      debug "Copied asset '#{path}'"

   _add: (path, compiler, linters, isHelper) ->
     isVendor = @is 'vendor', path


home: use generic list component for shared machines

--- client/home/lib/virtualmachines/components/sharedmachineslist.coffee
+++ client/home/lib/virtualmachines/components/sharedmachineslist.coffee
@@ -1,9 +1,10 @@
 kd              = require 'kd'
 React           = require 'kd-react'
+immutable       = require 'immutable'
 EnvironmentFlux = require 'app/flux/environment'
 KDReactorMixin  = require 'app/flux/base/reactormixin'
-immutable       = require 'immutable'
-List            = require './machineslist/list'
+List            = require 'app/components/list'
+MachineItem     = require './machineslist/listitem'

 module.exports = class SharedMachinesListContainer extends React.Component
@@ -16,18 +17,49 @@

   render: ->

-    stacks = immutable.List [
-      immutable.Map {
-        title: 'Shared Machine'
-        machines: @state.machines or immutable.Map({})
-      }
-    ]
-
     <List
       stacks={stacks}
       shouldRenderDetails={no} />

+  numberOfSections: -> 1
+
+
+  numberOfRowsInSection: -> @state.machines.size
+
+
+  renderSectionHeaderAtIndex: -> null
+
+
+  renderRowAtIndex: (sectionIndex, rowIndex) ->
+
+    stack = immutable.Map {
+      title: 'Shared Machine'
+      machines: @state.machines or immutable.Map({})
+    }
+
+    stack.get 'machines'
+      .sort (a, b) -> a.get('label').localeCompare(b.get('label')) # Sorting from a to z
+      .map (machine) ->
+        <MachineItem
+          key={machine.get '_id'} stack={stack} machine={machine}
+          shouldRenderDetails={no} />
+
+
+  renderEmptySectionAtIndex: ->
No shared machines.

+
+
+  render: ->
+
+    <List
+      numberOfSections={@bound 'numberOfSections'}
+      numberOfRowsInSection={@bound 'numberOfRowsInSection'}
+      renderSectionHeaderAtIndex={@bound 'renderSectionHeaderAtIndex'}
+      renderRowAtIndex={@bound 'renderRowAtIndex'}
+      renderEmptySectionAtIndex={@bound 'renderEmptySectionAtIndex'}
+    />
+
+
 SharedMachinesListContainer.include [KDReactorMixin]


Find or fetch on expanded proposal

Find or fetch on expanded proposal

--- angular/core/components/thread_page/proposal_expanded/proposal_expanded.coffee
+++ angular/core/components/thread_page/proposal_expanded/proposal_expanded.coffee
@@ -4,6 +4,7 @@
   templateUrl: 'generated/components/thread_page/proposal_expanded/proposal_expanded.html'
   replace: true
   controller: ($scope, Records, Session, AbilityService, TranslationService) ->
+    Records.proposals.findOrFetchById($scope.proposal.key)
     Records.votes.fetchByProposal($scope.proposal)

     $scope.collapse = ->


Disable codeshare shortcut for now

Disable codeshare shortcut for now

--- client/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
+++ client/app/MainApp/filetree/controllers/findercontextmenucontroller.coffee
@@ -145,9 +145,9 @@
         separator                 : yes
       Refresh                     :
         action                    : 'refresh'
-        separator                 : yes
-      'Create a CodeShare'        :
-        action                    : 'codeShare'
+      #   separator                 : yes
+      # 'Create a CodeShare'        :
+      #   action                    : 'codeShare'

     if fileView.expanded
       delete items.Expand


missed in last commit

missed in last commit

--- chrome/src/scripts/content.coffee
+++ chrome/src/scripts/content.coffee
@@ -24,7 +24,7 @@
 # Create the button
 #
 button = $("""
-
+
   Open in Sublime

 """)


Use UI Hash for the rows

Use UI Hash for the rows

--- core/app/backbone/views/channels/auto_complete_search_channels_view.coffee
+++ core/app/backbone/views/channels/auto_complete_search_channels_view.coffee
@@ -24,6 +24,10 @@
     all_list: '.js-list-all'
     new_list: '.js-list-new'

+    my_row:  '.js-row-my'
+    all_row: '.js-row-all'
+    new_row: '.js-row-new'
+
   onRender: -> @updateRows()

   appendHtml: (collectionView, itemView, index) ->
@@ -42,16 +46,16 @@
     allFilled = @$('.js-list-all li').length > 0
     newFilled = @$('.js-list-new li').length > 0

-    @$('.js-row-my').toggleClass 'auto-complete-search-list-active', myFilled
-    @$('.js-row-all').toggleClass 'auto-complete-search-list-active', allFilled
-    @$('.js-row-new').toggleClass 'auto-complete-search-list-active', newFilled
+    @ui.my_row.toggleClass  'auto-complete-search-list-active', myFilled
+    @ui.all_row.toggleClass 'auto-complete-search-list-active', allFilled
+    @ui.new_row.toggleClass 'auto-complete-search-list-active', newFilled

     @$('.auto-complete-search-list-last-rounded-both').removeClass 'auto-complete-search-list-last-rounded-both'
     @$('.auto-complete-search-list-last-rounded-right').removeClass 'auto-complete-search-list-last-rounded-right'

     if newFilled
-      @$('.js-row-new').addClass 'auto-complete-search-list-last-rounded-both'
+      @ui.new_row.addClass 'auto-complete-search-list-last-rounded-both'
     else if allFilled
-      @$('.js-row-all').addClass 'auto-complete-search-list-last-rounded-right'
+      @ui.all_row.addClass 'auto-complete-search-list-last-rounded-right'
     else
-      @$('.js-row-my').addClass 'auto-complete-search-list-last-rounded-right'
+      @ui.my_row.addClass  'auto-complete-search-list-last-rounded-right'


Login: Handle all type of calling for the app, you can either use router or applicationManager

--- client/Login/AppController.coffee
+++ client/Login/AppController.coffee
@@ -24,16 +24,21 @@

     super options, data

-  handleQuery: (query) ->
+  appIsShown: (params)->
+    @handleRoute "/#{params.label}"

+  handleQuery: (label)->
     {currentPath} = KD.getSingleton 'router'
+    @handleRoute currentPath
+
+  handleRoute: (route)->
     form = 'login'
-
-    s = (exp, tf)-> if currentPath.match exp then form = tf
+    s = (exp, tf)-> if route.match exp then form = tf
     s /\/Login$/       , 'login'
     s /\/Redeem$/      , 'redeem'
     s /\/Register$/    , 'register'
     s /\/Recover$/     , 'recover'
     s /\/ResendToken$/ , 'resendEmail'

-    @getView().animateToForm form+    @utils.defer =>
+      @getView().animateToForm form


register: set correct finish registration route handler

--- client/Login/AppController.coffee
+++ client/Login/AppController.coffee
@@ -90,7 +90,7 @@
       '/:name?/Login/:token?'    : handler (app)-> app.getView().animateToForm 'login'
       '/:name?/Redeem'           : handler (app)-> app.getView().animateToForm 'redeem'
       '/:name?/Register'         : handler (app)-> app.getView().animateToForm 'register'
-      '/:name?/Register/:token?' : handler (app)-> app.getView().animateToForm 'finishRegistration'
+      '/:name?/Register/:token?' : handleFinishRegistration
       '/:name?/Recover'          : handleRecovery
       '/:name?/Reset'            : handler (app)-> app.getView().animateToForm 'reset'
       '/:name?/Reset/:token'     : handleResetRoute


Fixed: handle case where completionDate is not set to prevent UI from crashing

--- client/src/components/task.coffee
+++ client/src/components/task.coffee
@@ -50,8 +50,11 @@
                         input inputProperties

             if @props.isArchivedMode
-                completionDate = Date.create @props.task.completionDate
-                formattedDate = completionDate.format t 'archived date format'
+                if @props.task.completionDate?
+                    completionDate = Date.create @props.task.completionDate
+                    formattedDate = completionDate.format t 'archived date format'
+                else
+                    formattedDate = ''
                 div className: 'todo-completionDate',
                     p null, "#{t 'completed headline'} #{formattedDate}"


Don't go to dashboardRoute until auth is completed

Removed extra routing to dashboardRoute since it was causing the app to redirect to dashboardRoute before the callback was finished (and therefore before the user had even authenticated! Major security flaw to say the least). The callback already handles routing correctly if there is no error, so there was no need for the extra routing.

--- client/views/social/social.coffee
+++ client/views/social/social.coffee
@@ -29,7 +29,5 @@

     loginWithService(options, callback)

-    Router.go AccountsEntry.settings.dashboardRoute
-
 capitalize = (str) ->
   str.charAt(0).toUpperCase() + str.slice(1)


Remove cli permissions pending test

Remove cli permissions pending test

--- lib/cli/cli-permissions.spec.coffee
+++ lib/cli/cli-permissions.spec.coffee
@@ -43,17 +43,6 @@
 					done()
 				func()

-			# TODO: expect(func).to.throw(Error) doesn't catches
-			# the error as it's being thrown inside an async function
-			# (resin.auth.isLoggedIn). A try/catch works, but it still results
-			# in the error being printed in Mocha reporter.
-			xit 'should throw an error if no error handler function', ->
-				func = cliPermissions.user(_.noop)
-				try
-					func()
-				catch error
-					expect(error).to.be.an.instanceof(Error)
-
 		describe 'if logged in', ->

 			beforeEach (done) ->


clipview: added toolbar

clipview: added toolbar

--- coffee/src/views/clip_view.coffee
+++ coffee/src/views/clip_view.coffee
@@ -22,11 +22,36 @@
     min: 0
     max: Infinity

+    # toolbar buttons
+    toolbarButtons: [
+      {id:'Link', icon: 'icon-link', tooltip: 'Link to this Highlight'}
+    ]
+
+
+  initialize: =>
+    super
+
+    buttons = _.map @options.toolbarButtons, (btn) =>
+      btn.className = (btn.className || '') + ' btn-small'
+      btn
+
+    @toolbarView = new athena.lib.ToolbarView
+      eventhub: @eventhub
+      buttons: buttons
+      extraClasses: ['btn-group']
+
+    @toolbarView.on 'all', =>
+      unless /Toolbar:Click:/.test arguments[0]
+        return
+      @trigger 'Clip:' + arguments[0], @
+
+

   render: =>
     super
     @$el.empty()
     @$el.html @template @model
+    @$el.append @toolbarView.render().el
     @reposition()
     @

@@ -45,7 +70,10 @@
     @$el.removeClass('show-note')

-  values: =>
+  values: (newValues) =>
+    @model.timeStart = newValues.start if newValues?.start?
+    @model.timeEnd = newValues.end if newValues?.end?
+
     start: @model.timeStart
     end: @model.timeEnd

@@ -66,6 +94,7 @@

   reposition: =>

+    # reposition horizontally
     params = (decimalDigits) =>
       low: @options.min
       high: @options.max


TIE Silencer dial spoiled.

TIE Silencer dial spoiled.


Further bug fixes and feature refinement

--- collector/scripts/frontend.coffee
+++ collector/scripts/frontend.coffee
@@ -16,7 +16,6 @@

 	changeTitle(document.querySelector(".screen[data-active]"))
 	window.scrollTo 0,1
-	window.scrollTo 0,0

 watchInput = (elm, e) ->
 	if e.target instanceof HTMLInputElement


added last opened folder in the media manager

--- app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js.coffee
+++ app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js.coffee
@@ -5,6 +5,11 @@
   media_link_tab_upload = media_panel.find(".media_file_info_col .nav-tabs .link_media_upload")

   ################ visualize item
+  # loading last opened folder on current page
+  media_panel.ready ->
+    f = $('body').data('last-folder')
+    media_panel.trigger('navigate_to', {folder: f})
+
   # return the data of this file
   file_data = (item)->
     data = item.data('eval-data') || eval("("+item.find(".data_value").val()+")")
@@ -128,7 +133,9 @@
     f = media_panel.attr("data-folder")+"/"+$(this).attr("data-key")
     if $(this).attr("data-key").search('/') >= 0
       f = $(this).attr("data-key")
-    media_panel.trigger("navigate_to", {folder: f.replace(/\/{2,}/g, '/')})
+    f = f.replace(/\/{2,}/g, '/')
+    media_panel.trigger("navigate_to", {folder: f})
+    $('body').attr('data-last-folder', f) # remembers last opened folder on current page
   )
   media_panel.bind("update_breadcrumb", ->
     folder = media_panel.attr("data-folder").replace("//", "/")


Real-time following activity

Real-time following activity

Client receives activity's id, calling bongo to get the full activity data and
displaying it.
Code snippet is displayed as Text for the real time update.
Need to migrate existing following relationships to exchange-to-exchange
bindings.

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -99,9 +99,11 @@

     @createFollowedAndPublicTabs()

-    account.on "FollowedActivityArrived", (activity) =>
-      if activity.constructor.name in @currentFilter
-        @activityListController.followedActivityArrived activity
+    account.on "FollowedActivityArrived", (activityId) =>
+      KD.remote.api.CActivity.one {_id: activityId}, (err, activity) =>
+        if activity.constructor.name in @currentFilter
+          activity.snapshot?.replace /"/g, '"'
+          @activityListController.followedActivityArrived activity

     # INITIAL HEIGHT SET FOR SPLIT
     @utils.wait 1000, =>


Wrap instance method 'on' with 'addGlobalListener' on client

Code that uses 'on' instance method will work again, such as deleting
activity.

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -97,7 +97,7 @@

     @createFollowedAndPublicTabs()

-    account.addGlobalListener "FollowedActivityArrived", ([activity]) =>
+    account.on "FollowedActivityArrived", ([activity]) =>
       if activity.constructor.name in @currentFilter
         @activityListController.followedActivityArrived activity

@@ -381,7 +381,7 @@

     super

-    @fetchFollowings()
+    #@fetchFollowings()

   fetchFollowings:->
     # To filter followings activites we need to fetch followings data
@@ -397,10 +397,6 @@
     id? and id in [activity.originId, activity.anchor?.id]

   isInFollowing:(activity, callback)->
-    # if activity.originId in @_following or activity.anchor?.id in @_following
-    #   return true
-    # else
-
     account = KD.whoami()
     {originId, anchor} = activity
     account.isFollowing originId, 'JAccount', (result) ->
@@ -435,25 +431,6 @@
           @addItem activity, 0
       @ownActivityArrived activity

-    # unless @isMine activity
-    #   if @_state is 'public'
-    #     view = @addHiddenItem activity, 0
-    #     @activityHeader.newActivityArrived()
-    #   else if @_state is 'private'
-    #     @isInFollowing activity, (result) =>
-    #       if result
-    #         view = @addHiddenItem activity, 0
-    #         @activityHeader.newActivityArrived()
-
-      # if (@_state is 'private' and @isInFollowing activity) or @_state is 'public'
-      #   view = @addHiddenItem activity, 0
-      #   @activityHeader.newActivityArrived()
-    # else
-    #   switch activity.constructor
-    #     when KD.remote.api.CFolloweeBucket
-    #       @addItem activity, 0
-    #   @ownActivityArrived activity
-
   addHiddenItem:(activity, index, animation = null)->
     instance = @getListView().addHiddenItem activity, index, animation
     hiddenItems.push instance


Increased user limits for VMs.

Increased user limits for VMs.

--- client/landing/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Groups.kdapplication/AppController.coffee
@@ -639,39 +639,39 @@
                 name                 : "member-vm"
                 defaultValue         : yes
               "Member CPU Limit"     :
-                label                : "CPU Limit per Member"
+                label                : "CPU Limit"
                 itemClass            : KDSelectBox
                 type                 : "select"
                 name                 : "vm-cpu-member"
-                defaultValue         : "1"
+                defaultValue         : "10"
                 selectOptions        : [
-                  { title : "1 CPU unit",    value : "1" }
-                  { title : "2 CPU units",    value : "2" }
-                  { title : "3 CPU units",    value : "3" }
-                  { title : "4 CPU units",    value : "4" }
-                  { title : "5 CPU units",    value : "5" }
+                  { title : "10 CPU units",    value : "10" }
+                  { title : "20 CPU units",    value : "20" }
+                  { title : "30 CPU units",    value : "30" }
+                  { title : "40 CPU units",    value : "40" }
+                  { title : "50 CPU units",    value : "50" }
                 ]
               "Member RAM Limit"     :
-                label                : "RAM Limit per Member"
+                label                : "RAM Limit"
                 itemClass            : KDSelectBox
                 type                 : "select"
                 name                 : "vm-ram-member"
-                defaultValue         : "1"
+                defaultValue         : "10"
                 selectOptions        : [
-                  { title : "1 GB",     value : "1" }
-                  { title : "2 GBs",    value : "2" }
-                  { title : "5 GBs",    value : "5" }
+                  { title : "10 GBs",    value : "10" }
+                  { title : "20 GBs",    value : "20" }
+                  { title : "30 GBs",    value : "30" }
                 ]
               "Member Disk Limit"    :
-                label                : "Disk Limit per Member"
+                label                : "Disk Limit"
                 itemClass            : KDSelectBox
                 type                 : "select"
                 name                 : "vm-disk-member"
-                defaultValue         : "1"
+                defaultValue         : "10"
                 selectOptions        : [
-                  { title : "1 GB",     value : "1" }
-                  { title : "2 GBs",    value : "2" }
-                  { title : "5 GBs",    value : "5" }
+                  { title : "10 GBs",    value : "10" }
+                  { title : "20 GBs",    value : "20" }
+                  { title : "30 GBs",    value : "30" }
                 ]

     modal = new KDModalViewWithForms modalOptions


Removed debugging for section results

Removed debugging for section results

--- public/scripts/backbone-schedule/views/scheduler/result-list.coffee
+++ public/scripts/backbone-schedule/views/scheduler/result-list.coffee
@@ -64,10 +64,8 @@
       @searchResults.get('sections').each (section) =>
         if section.get('rank') >= 0.3
           view = new ResultsSectionView model: section
-          console.log view, section
           @subviews.push view
           @$sections.append view.render().el
-          console.log view.render().el

     teardown: ->


Fixed fat arrow since we use @options.

Fixed fat arrow since we use @options.

--- core/app/backbone/views/fact_relations/auto_complete_fact_relations_view.coffee
+++ core/app/backbone/views/fact_relations/auto_complete_fact_relations_view.coffee
@@ -81,7 +81,7 @@
     @recent_collection.fetch()

   updateRecentCollection: ->
-    models = @recent_collection.filter (model) -> model.id != @options.fact_id
+    models = @recent_collection.filter (model) => model.id != @options.fact_id
     @search_collection.reset models if @model.get('text') == ''

   focus: -> @$el.addClass 'active'


Dont render an empty popular artists list

--- components/commercial_filter/views/popular_artists/popular_artists_view.coffee
+++ components/commercial_filter/views/popular_artists/popular_artists_view.coffee
@@ -8,6 +8,7 @@
     @listenTo @artists, 'reset', @render

   render: ->
+    return unless @artists.models.length > 0
     if @params.get('medium') in ['design', 'jewelry'] or @params.get('page') != 1
       $('.cf-popular_artists').hide()
     else


formatted duration output

formatted duration output

--- queries/_runner.coffee
+++ queries/_runner.coffee
@@ -161,6 +161,6 @@

 async.forEachSeries majors, major_fn, (major_err) ->
   ts_end = new Date
-  console.log "duration: #{ts_end-ts_start}"
+  console.log "duration: #{(ts_end-ts_start)/1000} s"
   console.log "major callback, closing db"
   db.closeConn()


Guard against missing view

Guard against missing view

Closes #527

--- lib/installed-packages-panel.coffee
+++ lib/installed-packages-panel.coffee
@@ -187,9 +187,9 @@
         filterText = "#{pack.name} #{owner}"
         fuzzaldrin.score(filterText, text) > 0

-      for view in allViews
+      for view in allViews when view
         view.find('.package-card').hide().addClass('hidden')
-      for view in activeViews
+      for view in activeViews when view
         view.find('.package-card').show().removeClass('hidden')

     @updateSectionCounts()


removing tws

removing tws

--- components/split/splitview.coffee
+++ components/split/splitview.coffee
@@ -89,13 +89,13 @@

   # CREATE RESIZERS
   _createResizers:->
-
+
     @resizers = for i in [1...@sizes.length]
       @_createResizer i
     @_repositionResizers()

   _createResizer:(index)->
-
+
     @addSubView resizer = new KDSplitResizer
       cssClass : "kdsplitview-resizer #{@getOptions().type}"
       type     : @getOptions().type
@@ -226,7 +226,7 @@

   _resizePanels:->
-
+
     @_sanitizeSizes()

   _repositionPanels:->


Revert "Bind functions to the current value of this"

This reverts commit fe514471597b000c2ae9abb6c1511b1465d57e5f.

--- flow.coffee
+++ flow.coffee
@@ -7,48 +7,48 @@
     @list = $(listSelector)
     @slide = @list.find(@options.slidesSelector).eq(0)

-  show: (slide) =>
+  show: (slide) ->
     if $.isNumeric(slide)
       @_selectSlideByIndex(slide)
     else
       @_selectSlideBySelector(slide)
     @list.find(@options.slidesSelector).hide().filter(@slide).show()

-  next: =>
+  next: ->
     slide = if @slide.next().index() is -1 then 0 else @slide.next()
     @show(slide)

-  prev: =>
+  prev: ->
     slide = if @slide.prev().index() is -1 then @_size() - 1 else @slide.prev()
     @show(slide)

-  first: =>
+  first: ->
     @show(0)

-  last: =>
+  last: ->
     @show(@_size() - 1)

-  prepend: (slideHtml) =>
+  prepend: (slideHtml) ->
     @list.prepend(slideHtml)
     @show(@slide)

-  append: (slideHtml) =>
+  append: (slideHtml) ->
     @list.append(slideHtml)
     @show(@slide)

-  insert: (position, slideHtml) =>
+  insert: (position, slideHtml) ->
     if position is 0
       @list.find(@options.slidesSelector).eq(position).before(slideHtml)
     else
       @list.find(@options.slidesSelector).eq(position - 1).after(slideHtml)
     @show(@slide)

-  replace: (position, slideHtml) =>
+  replace: (position, slideHtml) ->
     slide = if position is @slide.index() then position else @slide
     @list.find(@options.slidesSelector).eq(position).before(slideHtml).remove()
     @show(slide)

-  delete: (position) =>
+  delete: (position) ->
     if position is @slide.index()
       @next()
     @list.find(@options.slidesSelector).eq(position).remove()


Classroom: Added fetchUserClasses method.

--- client/app/Applications/Classroom.kdapplication/AppView.coffee
+++ client/app/Applications/Classroom.kdapplication/AppView.coffee
@@ -6,6 +6,22 @@

     super options, data

+    @appStorage = new AppStorage "Classroom", "1.0"
+
+    @createHeader()
+    @fetchUserClasses()
+
+  fetchUserClasses: ->
+    @appStorage.fetchStorage (storage) =>
+
+      @addSubView @classesView = new ClassroomClassesView
+        delegate : this
+      ,
+        enrolled : @appStorage.getValue "UserClasses"
+
+  createHeader: ->
+    @addSubView @header = new KDView
+      cssClass : "container"
       partial  : """

<classroom />


Prevents diffs render unless the current view is the active view

--- lib/minimap-git-diff-binding.coffee
+++ lib/minimap-git-diff-binding.coffee
@@ -38,6 +38,8 @@

   renderDiffs: =>
     return unless @editorView.getPane()?
+    return unless @editorView is @editorView.getPane().activeView
+
     minimapView = @minimap.minimapForEditorView(@editorView)
     lines = minimapView.find('.lines')[0].childNodes[0].childNodes


Added Game.VELOCITY

Added Game.VELOCITY

--- game.coffee
+++ game.coffee
@@ -7,6 +7,8 @@

   @WIDTH:  200
   @HEIGHT:  300
+
+  @VELOCITY = 0.1

   @listeners = []
   @players = []


updating route for dashboard

updating route for dashboard

--- src/router.cjsx
+++ src/router.cjsx
@@ -67,7 +67,7 @@
                 ignoreScrollBehavior/>
             </Route>
           </Route>
-          <Route path='cc-taskplans/?' name='cc-taskplans' handler={CCDashboard} />
+          <Route path='cc-dashboard/?' name='cc-dashboard' handler={CCDashboard} />

           <Route path='homeworks/new/?' name='createHomework' handler={HomeworkShell} />
           <Route path='homeworks/:id/?' name='editHomework' handler={HomeworkShell} />


Fixed bug in adding comments.

Fixed bug in adding comments.

--- core/app/backbone/views/fact_relations/add_comment_view.coffee
+++ core/app/backbone/views/fact_relations/add_comment_view.coffee
@@ -29,7 +29,7 @@
       'Disagreeing'

   updateModel: ->
-    content = @$('.content').val()
+    content = @$('.js-content').val()
     @model.set {content: content}, silent: true

   setFormContent: (content) -> @model.set content: content


use two spaces for indention instead of 4 spaces


Add version and copyright info

Add version and copyright info

--- src/swag.coffee
+++ src/swag.coffee
@@ -1,3 +1,9 @@
+###
+    Swag v0.0.1 <http://elving.github.com/swag/>
+    Copyright 2012 Elving Rodriguez <http://elving.me/>
+    Available under MIT license <https://raw.github.com/elving/swag/master/LICENSE>
+###
+
 ((exports) ->

     ###


sync: require errors

sync: require errors

--- src/sync.coffee
+++ src/sync.coffee
@@ -6,6 +6,7 @@
 RSM = require('./xmpp/rsm')
 NS = require('./xmpp/ns')
 rsmWalk = require('./rsm_walk')
+errors = require('./errors')

 class Synchronization
     constructor: (@router, @node) ->


Adding a job percentage status indicator to the header

--- src/tegh.coffee
+++ src/tegh.coffee
@@ -77,12 +77,14 @@
     stdin.pause()
     @updateSize()

-    header = @src._header()
+    lHeader = @src._lHeader()
+    rHeader = @src._rHeader()
     c = @cursor

     c.savePosition().goto(0, 0)
     c.black().bg.white()
-    c.write(header.padRight(" ", @width - header.length))
+    c.write(lHeader.padRight(" ", @width - lHeader.length - rHeader.length))
+    c.write(rHeader)
     c.reset().bg.reset()

     c.goto(0, @height+2).show()
@@ -92,6 +94,7 @@

 class Tegh
   commands: require './help'
+  _jobProgress: 0

   constructor: ->
     new ServiceSelector().on "select", @_onServiceSelect
@@ -104,6 +107,7 @@
     @client = new ConstructClient(service.address, port)
       .on("connect", @_onConnect)
       .on("sensor_changed", @_onSensorChanged)
+      .on("job_progress_changed", @_onJobChanged)
       .on("jobs", @_onJobsList)
       .on("job_upload_complete", @_onJobUploadComplete)
       .on("close", @_onClose)
@@ -114,6 +118,10 @@

   _onSensorChanged: (data) =>
     @_sensors[data.name] = data.value
+    @cli.render()
+
+  _onJobChanged: (data) =>
+    @_jobProgress = data
     @cli.render()

   _onClose: =>
@@ -142,14 +150,17 @@
         status = "Error adding job."
       process.stdout.write("\r" + status + "\n")
       @cli.rl.prompt()
+      @cli.render()
       @cli.rl.resume()

-
-  _header: ->
+  _lHeader: ->
     fields = []
     for k, v of @_sensors
       fields.push "#{k.capitalize()}: #{v}\u00B0C"
     fields.join("  ")
+
+  _rHeader: ->
+    "#{@_jobProgress.format(2)}% Complete "

   _append: (s, prefix = "") ->
     stdout.write(prefix + s + "\n")


Updated list of rights available in self context.

--- sli/admin-tools/admin-rails/app/assets/javascripts/custom_roles.js.coffee
+++ sli/admin-tools/admin-rails/app/assets/javascripts/custom_roles.js.coffee
@@ -1,5 +1,5 @@
 defaultRights = ["READ_GENERAL", "WRITE_GENERAL", "READ_RESTRICTED", "WRITE_RESTRICTED", "AGGREGATE_READ", "AGGREGATE_WRITE", "READ_PUBLIC", "WRITE_PUBLIC"]
-selfRights = ["READ_SELF_RESTRICTED", "READ_SELF_GENERAL"]
+selfRights = ["READ_GENERAL", "WRITE_GENERAL", "READ_RESTRICTED", "WRITE_RESTRICTED"]
 ROLE_COL = "td:eq(0)";
 RIGHT_COL = "td:eq(1)";
 SELF_RIGHT_COL = "td:eq(2)";


Handle possible statSync errors

Handle possible statSync errors

--- src/util.coffee
+++ src/util.coffee
@@ -10,7 +10,7 @@
       when dir instanceof File
         return fs.statSync(dir.getPath()).isDirectory()
       when typeof dir is 'string'
-        return fs.statSync(dir).isDirectory()
+        return ((try fs.statSync(dir).isDirectory()) ? false)
       else
         return false


bongo: DRY updating buckets

bongo: DRY updating buckets

--- client/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
+++ client/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
@@ -29,7 +29,7 @@

     KD.getSingleton("groupsController").on "FollowHappened", (info) =>
       {follower, origin} = info
-      @updateBuckets follower, origin
+      @updateFollowerBucket follower, origin

   resetList:->
     @newActivityArrivedList = {}
@@ -158,20 +158,10 @@
   updateNewMemberBucket:(memberAccount)->
     for item in @itemsOrdered
       if item.getData() instanceof NewMemberBucketData
-        data = item.getData()
-        if data.count > 3
-          data.anchors.pop()
-        id = memberAccount.id
-        data.anchors.unshift {bongo_: {constructorName:"ObjectRef"}, constructorName:"JAccount", id:id}
-        data.createdAtTimestamps.push (new Date).toJSON()
-        data.count++
-        item.slideOut =>
-          @removeItem item, data
-          newItem = @addHiddenItem data, 0
-          @utils.wait 500, -> newItem.slideIn()
+        @updateBucket item, "JAccount", memberAccount.id
         break

-  updateBuckets:(follower, followee)->
+  updateFollowerBucket:(follower, followee)->
     for item in @itemsOrdered
       data = item.getData()

@@ -180,19 +170,25 @@

       if data.group[0].constructorName is followee.bongo_.constructorName
         if data.anchor.id is follower.id
-          data.group.unshift {
-            bongo_:
-              constructorName:"ObjectRef"
-            constructorName:followee.bongo_.constructorName, id:followee._id
-          }
-          data.createdAtTimestamps.push (new Date).toJSON()
-          data.count ||= 0
-          data.count++
-          item.slideOut =>
-            @removeItem item, data
-            newItem = @addHiddenItem data, 0
-            @utils.wait 500, -> newItem.slideIn()
+          @updateBucket item, followee.bongo_.constructorName, followee._id
           break
+
+  updateBucket:(item, constructorName, id)->
+    data = item.getData()
+    group = data.group or data.anchors
+    group.unshift {
+      bongo_:
+        constructorName:"ObjectRef"
+      constructorName
+      id
+    }
+    data.createdAtTimestamps.push (new Date).toJSON()
+    data.count ||= 0
+    data.count++
+    item.slideOut =>
+      @removeItem item, data
+      newItem = @addHiddenItem data, 0
+      @utils.wait 500, -> newItem.slideIn()

   fakeItems = []


fixed home login bar buttons request access/invite and join group

--- client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
+++ client/landing/app/Applications/Home.kdapplication/Views/homeloginbar.coffee
@@ -103,7 +103,7 @@
         @login.hide()
         @register.hide()

-      KD.remote.cacheable entryPoint, (err, models)=>
+      KD.remote.cacheable entryPoint.slug, (err, models)=>
         if err then callback err
         else if models?
           [@group] = models
@@ -112,7 +112,7 @@
             @access.hide()
             @join.show()
           else if @group.privacy is "private"
-            KD.remote.api.JMembershipPolicy.byGroupSlug entryPoint, (err, policy)=>
+            KD.remote.api.JMembershipPolicy.byGroupSlug entryPoint.slug, (err, policy)=>
               if err then console.warn err
               else if policy.approvalEnabled
                 @request.hide()


added timeout and logging for tpdsworker queing via http

--- services/web/app/coffee/Features/ThirdPartyDataStore/TpdsUpdateSender.coffee
+++ services/web/app/coffee/Features/ThirdPartyDataStore/TpdsUpdateSender.coffee
@@ -26,10 +26,13 @@
 				method:method
 				job:job
 			method:"post"
+			timeout: (5 * 1000)
 		request opts, (err)->
 			if err?
+				logger.err err:err, "error queuing something in the tpdsworker"
 				callback(err)
 			else
+				logger.log group:group, "successfully queued up job for tpdsworker"
 				callback()

 	_addEntity: (options, callback = (err)->)->


Hiding deprecation warnings

Hiding deprecation warnings

--- app/app.coffee
+++ app/app.coffee
@@ -5,6 +5,18 @@
 `import config from './config/environment'`

 Ember.MODEL_FACTORY_INJECTIONS = true
+
+#overwriting Ember deprecation warnings so we can filter them out easily in the console
+Ember.deprecate = (->
+  already_shown = []
+  (msg, test, opt)->
+    return false if test
+    if already_shown.indexOf(msg) == -1
+      warning = "DEPRECATION: #{msg}"
+      warning += " See: #{opt.url}" if opt.url
+      console.debug warning
+    already_shown.push msg
+)()

 App = Ember.Application.extend
   modulePrefix:    config.modulePrefix


Adds all entry types according to biblatex documentation. Separates required and optional arguments

--- snippets/bibtex-snippets.cson
+++ snippets/bibtex-snippets.cson
@@ -30,7 +30,6 @@
         edition   = {},
         series    = {},
         number    = {},
-        month     = {},
         publisher = {},
         note      = {},
         isbn      = {}
@@ -43,13 +42,76 @@
         author    = {},
         title     = {},
         subtitle  = {},
-        publisher = {},
-        year      = {},
-        volume    = {},
-        series    = {},
-        address   = {},
+        year      = {},
+
         edition   = {},
-        month     = {},
+        volumes   = {},
+        publisher = {},
+        series    = {},
+        number    = {},
+        note      = {},
+        isbn      = {}
+      }
+    """
+  'Inbook':
+    'prefix': 'inbook'
+    'body': """
+      @inbook{${1:link},
+        author    = {},
+        title     = {},
+        booktitle = {},
+        year      = {},
+
+        bookauthor= {},
+        subtitle  = {},
+        volumes   = {},
+        volume    = {},
+        edition   = {},
+        series    = {},
+        number    = {},
+        publisher = {},
+        note      = {},
+        isbn      = {}
+      }
+    """
+  'Book in Book':
+    'prefix': 'bookinbook'
+    'body': """
+      @bookinbook{${1:link},
+        author    = {},
+        title     = {},
+        booktitle = {},
+        year      = {},
+
+        bookauthor= {},
+        subtitle  = {},
+        volumes   = {},
+        volume    = {},
+        edition   = {},
+        series    = {},
+        number    = {},
+        publisher = {},
+        note      = {},
+        isbn      = {}
+      }
+    """
+  'Supplemental material in book':
+    'prefix': 'suppbook'
+    'body': """
+      @suppbook{${1:link},
+        author    = {},
+        title     = {},
+        booktitle = {},
+        year      = {},
+
+        bookauthor= {},
+        subtitle  = {},
+        volumes   = {},
+        volume    = {},
+        edition   = {},
+        series    = {},
+        number    = {},
+        publisher = {},
         note      = {},
         isbn      = {}
       }
@@ -58,206 +120,115 @@
     'prefix': 'booklet'
     'body': """
       @booklet{${1:link},
-        title        = {},
-        author       = {},
+        author       = {},
+        title        = {},
+        year         = {},
+
         howpublished = {},
-        address      = {},
-        month        = {},
-        year         = {},
-        note         = {}
-      }
-    """
-  'Conference':
-    'prefix': 'conference'
-    'body': """
-      @conference{${1:link},
-        author       = {},
-        title        = {},
-        booktitle    = {},
-        year         = {},
-        editor       = {},
-        volume       = {},
-        series       = {},
-        pages        = {},
-        address      = {},
-        month        = {},
-        organization = {},
-        publisher    = {},
-        note         = {}
-      }
-    """
-  'Inbook':
-    'prefix': 'inbook'
-    'body': """
-      @inbook{${1:link},
-        author    = {},
-        title     = {},
-        chapter   = {},
-        pages     = {},
-        publisher = {},
-        year      = {},
-        volume    = {},
-        series    = {},
-        address   = {},
-        edition   = {},
-        month     = {},
-        note      = {}
-      }
-    """
-  'Book in Book':
-    'prefix': 'bookinbook'
-    'body': """
-      @bookinbook{${1:link},
-        author    = {},
-        title     = {},
-        chapter   = {},
-        pages     = {},
-        publisher = {},
-        year      = {},
-        volume    = {},
-        series    = {},
-        address   = {},
-        edition   = {},
-        month     = {},
-        note      = {}
-      }
-    """
-  'Supplemental material in book':
-    'prefix': 'suppbook'
-    'body': """
-      @suppbook{${1:link},
-        author    = {},
-        title     = {},
-        chapter   = {},
-        pages     = {},
-        publisher = {},
-        year      = {},
-        volume    = {},
-        series    = {},
-        address   = {},
-        edition   = {},
-        month     = {},
-        note      = {}
+        titleaddon   = {},
+        url          = {},
+        urldate      = {},
+        note         = {}
       }
     """
   'Collection':
     'prefix': 'collection'
     'body': """
       @collection{${1:link},
+        editor    = {},
+        title     = {},
+        year      = {},
+
+        subtitle  = {},
+        publisher = {},
+        volume    = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
+  'Multi-volume Collection':
+    'prefix': 'mvcollection'
+    'body': """
+      @mvcollection{${1:link},
+        editor    = {},
+        title     = {},
+        year      = {},
+
+        subtitle  = {},
+        publisher = {},
+        volumes   = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
+  'In collection':
+    'prefix': 'incollection'
+    'body': """
+      @incollection{${1:link},
         author    = {},
         title     = {},
         booktitle = {},
-        publisher = {},
-        year      = {},
-        editor    = {},
-        volume    = {},
-        series    = {},
-        chapter   = {},
-        pages     = {},
-        address   = {},
-        edition   = {},
-        month     = {},
-        note      = {}
-      }
-    """
-    'In collection':
-      'prefix': 'incollection'
-      'body': """
-        @incollection{${1:link},
-          editor    = {},
-          title     = {},
-          booktitle = {},
-          publisher = {},
-          year      = {},
-          editor    = {},
-          volume    = {},
-          series    = {},
-          chapter   = {},
-          pages     = {},
-          address   = {},
-          edition   = {},
-          month     = {},
-          note      = {}
-        }
-      """
-    'Multi-volume Collection':
-      'prefix': 'mvcollection'
-      'body': """
-        @mvcollection{${1:link},
-          author    = {},
-          title     = {},
-          booktitle = {},
-          publisher = {},
-          year      = {},
-          editor    = {},
-          volume    = {},
-          series    = {},
-          chapter   = {},
-          pages     = {},
-          address   = {},
-          edition   = {},
-          month     = {},
-          note      = {}
-        }
-      """
-    'Supplemental material in collection':
-      'prefix': 'suppcollection'
-      'body': """
-        @suppcollection{${1:link},
-          author    = {},
-          title     = {},
-          booktitle = {},
-          publisher = {},
-          year      = {},
-          editor    = {},
-          volume    = {},
-          series    = {},
-          chapter   = {},
-          pages     = {},
-          address   = {},
-          edition   = {},
-          month     = {},
-          note      = {}
-        }
-      """
+        year      = {},
+
+        editor    = {},
+        subtitle  = {},
+        publisher = {},
+        volumes   = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
+  'Supplemental material in collection':
+    'prefix': 'suppcollection'
+    'body': """
+      @suppcollection{${1:link},
+        editor    = {},
+        title     = {},
+        year      = {},
+
+        subtitle  = {},
+        publisher = {},
+        volume    = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
   'Manual':
     'prefix':'manual'
     'body': """
       @manual{${1:link},
-        title        = {},
-        author       = {},
-        organization = {},
+        author       = {},
+        title        = {},
+        year         = {},
+
+        organization = {},
+        edition      = {},
+        type         = {},
+        version      = {},
+        publisher    = {},
         address      = {},
-        edition      = {},
-        month        = {},
-        year         = {},
-        note         = {}
-      }
-    """
-    'Thesis':
-      'prefix': 'thesis'
-      'body': """
-        @thesis{${1:link},
-          author  = {},
-          title   = {},
-          school  = {},
-          year    = {},
-          address = {},
-          month   = {},
-          note    = {}
-        }
-      """
-  'Masterthesis':
-    'prefix': 'masterthesis'
-    'body': """
-      @mastersthesis{${1:link},
-        author  = {},
-        title   = {},
-        school  = {},
-        year    = {},
-        address = {},
-        month   = {},
-        note    = {}
+        note         = {},
+        url          = {}
       }
     """
   'Miscellaneous':
@@ -266,9 +237,12 @@
       @misc{${1:link},
         author       = {},
         title        = {},
+        year         = {},
+
+        organization = {},
         howpublished = {},
         month        = {},
-        year         = {},
+        url          = {},
         note         = {}
       }
     """
@@ -278,13 +252,13 @@
       @online{${1:link},
         author       = {},
         title        = {},
+        year         = {},
+        url          = {},
+
         subtitle     = {},
         organization = {},
         month        = {},
-        year         = {},
-        month        = {},
         note         = {},
-        url          = {},
         urldate      = {}
       }
     """
@@ -308,55 +282,47 @@
         editor       = {},
         title        = {},
         year         = {},
+
         series       = {},
         volume       = {},
         number       = {},
         issue        = {},
         date         = {},
+        month        = {},
         note         = {},
         doi          = {}
       }
     """
-  'Supplemental material in Periodical':
+  'Supplemental material in periodical':
     'prefix': 'suppperiodical'
     'body': """
       @suppperiodical{${1:link},
         editor       = {},
         title        = {},
         year         = {},
+
         series       = {},
         volume       = {},
         number       = {},
         issue        = {},
         date         = {},
+        month        = {},
         note         = {},
         doi          = {}
       }
     """
-  'Phd Thesis':
-    'prefix': 'phdthesis'
-    'body': """
-      @phdthesis{${1:link},
-        author  = {},
-        title   = {},
-        school  = {},
-        year    = {},
-        address = {},
-        month   = {},
-        note    = {}
-      }
-    """
   'Proceedings':
     'prefix': 'proceedings'
     'body': """
       @proceedings{${1:link},
         title        = {},
         year         = {},
+
         editor       = {},
         volume       = {},
         series       = {},
-        address      = {},
-        month        = {},
+        month        = {},
+        pages        = {},
         organization = {},
         publisher    = {},
         note         = {}
@@ -368,37 +334,33 @@
       @mvproceedings{${1:link},
         title        = {},
         year         = {},
+
+        editor       = {},
+        volumes      = {},
+        series       = {},
+        month        = {},
+        pages        = {},
+        organization = {},
+        publisher    = {},
+        note         = {}
+      }
+    """
+  'Article in conference proceeding':
+    'prefix': 'inproceedings'
+    'body': """
+      @inproceedings{${1:link},
+        author       = {},
+        title        = {},
+        booktitle    = {},
+        year         = {},
+
         editor       = {},
         volume       = {},
         series       = {},
-        address      = {},
-        month        = {},
+        month        = {},
+        pages        = {},
         organization = {},
         publisher    = {},
-        note         = {}
-      }
-    """
-  'Article in conference proceeding':
-    'prefix': 'inproceedings'
-    'body': """
-      @inproceedings{${1:link},
-        author       = {},
-        title        = {},
-        booktitle    = {},
-        year         = {},
-      }
-    """
-  'Technical Report':
-    'prefix': 'techreport'
-    'body': """
-      @techreport{${1:link},
-        author       = {},
-        title        = {},
-        institution  = {},
-        year         = {},
-        number       = {},
-        address      = {},
-        month        = {},
         note         = {}
       }
     """
@@ -406,90 +368,199 @@
     'prefix': 'reference'
     'body': """
       @reference{${1:link},
+        editor    = {},
+        title     = {},
+        year      = {},
+
+        subtitle  = {},
+        publisher = {},
+        volume    = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
+  'Multi-volume Reference':
+    'prefix': 'mvreference'
+    'body': """
+      @mvreference{${1:link},
+        editor    = {},
+        title     = {},
+        year      = {},
+
+        subtitle  = {},
+        publisher = {},
+        volumes   = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
+  'In Reference':
+    'prefix': 'inreference'
+    'body': """
+      @inreference{${1:link},
         author    = {},
         title     = {},
         booktitle = {},
-        publisher = {},
-        year      = {},
-        editor    = {},
-        volume    = {},
-        series    = {},
-        chapter   = {},
-        pages     = {},
-        address   = {},
-        edition   = {},
-        month     = {},
-        note      = {}
-      }
-    """
-    'Multi-volume Reference':
-      'prefix': 'mvreference'
-      'body': """
-        @mvreference{${1:link},
-          author    = {},
-          title     = {},
-          booktitle = {},
-          publisher = {},
-          year      = {},
-          editor    = {},
-          volume    = {},
-          series    = {},
-          chapter   = {},
-          pages     = {},
-          address   = {},
-          edition   = {},
-          month     = {},
-          note      = {}
-        }
-      """
-    'In Reference':
-      'prefix': 'inreference'
-      'body': """
-        @inreference{${1:link},
-          author    = {},
-          title     = {},
-          booktitle = {},
-          publisher = {},
-          year      = {},
-          editor    = {},
-          volume    = {},
-          series    = {},
-          chapter   = {},
-          pages     = {},
-          address   = {},
-          edition   = {},
-          month     = {},
-          note      = {}
-        }
-      """
-    'Report':
-      'prefix': 'report'
-      'body': """
-        @reference{${1:link},
-          author    = {},
-          title     = {},
-          booktitle = {},
-          publisher = {},
-          year      = {},
-          editor    = {},
-          volume    = {},
-          series    = {},
-          chapter   = {},
-          pages     = {},
-          address   = {},
-          edition   = {},
-          month     = {},
-          note      = {}
-        }
-      """
+        year      = {},
+
+        editor    = {},
+        subtitle  = {},
+        publisher = {},
+        volumes   = {},
+        part      = {},
+        series    = {},
+        number    = {},
+        chapter   = {},
+        pages     = {},
+        note      = {},
+        edition   = {}
+      }
+    """
+  'Report':
+    'prefix': 'report'
+    'body': """
+      @reference{${1:link},
+        author      = {},
+        title       = {},
+        type        = {},
+        institution = {},
+        year        = {},
+
+        chapter     = {},
+        pages       = {},
+        month       = {},
+        note        = {}
+      }
+    """
+  'Thesis':
+    'prefix': 'thesis'
+    'body': """
+      @thesis{${1:link},
+        author      = {},
+        title       = {},
+        type        = {},
+        institution = {},
+        year        = {},
+
+        address     = {},
+        month       = {},
+        note        = {}
+      }
+    """
   'Unpublished':
     'prefix': 'unpublished'
     'body': """
       @unpublished{${1:link},
         author  = {},
         title   = {},
-        note    = {},
+        year    = {},
+
         month   = {},
-        year    = {}
-      }
-    """
+        note    = {}
+      }
+    """
+  'Conference':
+    'prefix': 'conference'
+    'body': """
+      @conference{${1:link},
+        author       = {},
+        title        = {},
+        booktitle    = {},
+        year         = {},
+
+        editor       = {},
+        volume       = {},
+        series       = {},
+        month        = {},
+        pages        = {},
+        organization = {},
+        publisher    = {},
+        note         = {}
+      }
+    """
+  'Electronic resource':
+    'prefix': 'electronic'
+    'body': """
+      @electronic{${1:link},
+        author       = {},
+        title        = {},
+        year         = {},
+        url          = {},
+
+        subtitle     = {},
+        organization = {},
+        month        = {},
+        note         = {},
+        urldate      = {}
+      }
+    """
+  'Masterthesis':
+    'prefix': 'masterthesis'
+    'body': """
+      @mastersthesis{${1:link},
+        author      = {},
+        title       = {},
+        institution = {},
+        year        = {},
+
+        address     = {},
+        month       = {},
+        note        = {}
+      }
+    """
+  'Phd Thesis':
+    'prefix': 'phdthesis'
+    'body': """
+      @phdthesis{${1:link},
+        author      = {},
+        title       = {},
+        institution = {},
+        year        = {},
+
+        address     = {},
+        month       = {},
+        note        = {}
+      }
+    """
+  'Technical Report':
+    'prefix': 'techreport'
+    'body': """
+      @techreport{${1:link},
+        author      = {},
+        title       = {},
+        type        = {},
+        institution = {},
+        year        = {},
+
+        chapter     = {},
+        pages       = {},
+        month       = {},
+        note        = {}
+      }
+    """
+  'Online resource':
+    'prefix': 'www'
+    'body': """
+      @www{${1:link},
+        author       = {},
+        title        = {},
+        year         = {},
+        url          = {},
+
+        subtitle     = {},
+        organization = {},
+        month        = {},
+        note         = {},
+        urldate      = {}
+      }
+    """


extra routes shouldn't live in settings

extra routes shouldn't live in settings

--- app/app.coffee
+++ app/app.coffee
@@ -163,7 +163,7 @@
 reset_user_settings = (settings) ->
   Settings.user_settings.set settings

-exports.init_app = (target) ->
+exports.init_app = (target, options={}) ->
   # TODO warn
   try
     Settings.user_settings.set JSON.parse(localStorage.getItem 'lead_user_settings')
@@ -177,8 +177,8 @@
   if publicUrl?
     `__webpack_public_path__ = publicUrl`

-  extraRoutes = Settings.get('app', 'extraRoutes') or []
-  bodyWrapper = Settings.get 'app', 'bodyWrapper'
+  extraRoutes = options.extraRoutes or []
+  bodyWrapper = options.bodyWrapper

   raw_cell_value = null
   if location.search isnt ''


Use stitchRequire stitch identifier in test helper

--- test/helpers/index.coffee
+++ test/helpers/index.coffee
@@ -8,4 +8,4 @@
   chai: require 'chai'

   require: (path) ->
-    app.require path
+    app.stitchRequire path


Add stars count to show/view output

Add stars count to show/view output

--- src/view.coffee
+++ src/view.coffee
@@ -33,8 +33,8 @@
       if error?
         callback(error)
       else if response.statusCode is 200
-        {metadata, readme, repository, downloads} = body
-        pack = _.extend({}, metadata, {readme, downloads})
+        {metadata, readme, repository, downloads, stargazers_count} = body
+        pack = _.extend({}, metadata, {readme, downloads, stargazers_count})
         callback(null, pack)
       else
         message = body.message ? body.error ? body
@@ -65,6 +65,8 @@
         items.push(pack.description.replace(/\s+/g, ' ')) if pack.description
         if pack.downloads >= 0
           items.push(_.pluralize(pack.downloads, 'download'))
+        if pack.stargazers_count >= 0
+          items.push(_.pluralize(pack.stargazers_count, 'star'))

         tree(items)


TODO for bind method

TODO for bind method

--- src/view.coffee
+++ src/view.coffee
@@ -25,7 +25,6 @@
   # swap content for given element
   # @return null
   swap: () ->
-
     Sirius.Application.adapter.swap(@element, @_result)
     null

@@ -43,4 +42,48 @@
   # clear element content
   clear: () ->
     Sirius.Application.adapter.clear(@element)
-    @+    @
+
+
+  #
+  # when we have:
+  # ### 1 View to View relation with change text
+  #   view1.bind(view2)
+  # if view1 element have onchange event then we use this event
+  # if view1 element does not have onchange event we should use Dom level 3\4 events see #observer.coffee
+  #
+  # ### 2 View to View relation with change attributes in View2
+  #
+  # for view1 we should use Dom level 3\4 events
+  # also we should know which attributes changed (filter), therefore
+  # view1.bind(view2, with: ["id"])
+  # when we change text in view1, then should changes in view2 id attribute
+  #
+  # ### 3 View to View relation change attributes in View1
+  #
+  # view1.bind(view2, from: ["id"])
+  #
+  # when change id in view1, we should change text in view2
+  #
+  # ### 4 Combination of 3 and 4
+  #
+  # ### 5 View Model relation
+  #
+  # ### 6 View to any function relation
+  bind: (klass) ->
+    `var c = function(m){console.log(m);};`
+    if klass && klass.constructor && klass.constructor.name
+      if klass.constructor.name == "View"
+        adapter = Sirius.Application.adapter
+        elements = document.querySelectorAll(klass.element)
+
+        #FIXME optimize this
+        for element in elements
+          # it's for input,textarea, select...
+          if Object.keys(element).indexOf("value") != -1
+            c "value"
+          else
+
+        1
+
+  bind2: () ->


Use filtering on active requests endpoint to 1/3rd the over-the-wire response #80

--- SingularityUI/app/collections/RequestsActive.coffee
+++ SingularityUI/app/collections/RequestsActive.coffee
@@ -5,7 +5,23 @@

     model: Request

-    url: "#{ env.SINGULARITY_BASE }/#{ constants.apiBase }/requests/active"
+    url: ->
+        properties = [
+            # root
+            'id'
+            'name'
+            'schedule'
+            'daemon'
+            'timestamp'
+            'instances'
+
+            # executorData # TODO - consider using metadata for this instead?
+            'executorData.env'
+        ]
+
+        propertiesString = "?property=#{ properties.join('&property=') }"
+
+        "#{ env.SINGULARITY_BASE }/#{ constants.apiBase }/requests/active#{ propertiesString }"

     parse: (requests) ->
         _.each requests, (request, i) =>


Update tests to be more deterministic.

Update tests to be more deterministic.

--- test/server/deploy.coffee
+++ test/server/deploy.coffee
@@ -3,10 +3,14 @@
 crypto = require 'crypto'

 describe 'Api.deploy', ->
-  basedir = path.join __dirname, '..', 'fixtures'
+  basedir = path.join __dirname, '..', 'tmp'
   deploy  = null
   digest  = null
   site    = null
+
+  after ->
+    yield fs.unlink path.join basedir, 'index.html'
+    yield fs.rmdir basedir

   before ->
     site =
@@ -32,6 +36,8 @@
       files: {}

     # create digest for deploy
+    yield fs.mkdir basedir
+    yield fs.writeFile (path.join basedir, 'index.html'), randomToken 999
     files = yield fs.readdir basedir

     for file in files
@@ -46,7 +52,6 @@
       deploy = yield api.deploy.create digest
       deploy.required.should.eql (v for k,v of digest.files)
       deploy.siteId.should.eq digest.siteId
-      deploy.state.should.eq 'uploading'

   describe '.upload', ->
     it 'should upload file required for deploy', ->


Update Editor spec

Update Editor spec

--- spec/editor-spec.coffee
+++ spec/editor-spec.coffee
@@ -16,10 +16,12 @@

   describe "with default options", ->
     beforeEach ->
-      atom.packages.activatePackage('language-javascript', sync: true)
       editor = atom.project.openSync('sample.js', autoIndent: false)
       buffer = editor.buffer
       lineLengths = buffer.getLines().map (line) -> line.length
+
+      waitsForPromise ->
+        atom.packages.activatePackage('language-javascript')

     describe "when the editor is deserialized", ->
       it "restores selections and folds based on markers in the buffer", ->
@@ -2733,19 +2735,26 @@

   describe "when the editor's grammar has an injection selector", ->
     beforeEach ->
-      atom.packages.activatePackage('language-text', sync: true)
-      atom.packages.activatePackage('language-javascript', sync: true)
+
+      waitsForPromise ->
+        atom.packages.activatePackage('language-text')
+
+      waitsForPromise ->
+        atom.packages.activatePackage('language-javascript')

     it "includes the grammar's patterns when the selector matches the current scope in other grammars", ->
-      atom.packages.activatePackage('language-hyperlink', sync: true)
-      grammar = atom.syntax.selectGrammar("text.js")
-      {tokens} = grammar.tokenizeLine("var i; // http://github.com")
-
-      expect(tokens[0].value).toBe "var"
-      expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
-
-      expect(tokens[6].value).toBe "http://github.com"
-      expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
+      waitsForPromise ->
+        atom.packages.activatePackage('language-hyperlink')
+
+      runs ->
+        grammar = atom.syntax.selectGrammar("text.js")
+        {tokens} = grammar.tokenizeLine("var i; // http://github.com")
+
+        expect(tokens[0].value).toBe "var"
+        expect(tokens[0].scopes).toEqual ["source.js", "storage.modifier.js"]
+
+        expect(tokens[6].value).toBe "http://github.com"
+        expect(tokens[6].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]

     describe "when the grammar is added", ->
       it "retokenizes existing buffers that contain tokens that match the injection selector", ->
@@ -2756,11 +2765,13 @@
         expect(tokens[1].value).toBe " http://github.com"
         expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]

-        atom.packages.activatePackage('language-hyperlink', sync: true)
-
-        {tokens} = editor.lineForScreenRow(0)
-        expect(tokens[2].value).toBe "http://github.com"
-        expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]
+        waitsForPromise ->
+          atom.packages.activatePackage('language-hyperlink')
+
+        runs ->
+          {tokens} = editor.lineForScreenRow(0)
+          expect(tokens[2].value).toBe "http://github.com"
+          expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "markup.underline.link.http.hyperlink"]

     describe "when the grammar is updated", ->
       it "retokenizes existing buffers that contain tokens that match the injection selector", ->
@@ -2771,14 +2782,17 @@
         expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
         expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]

-        atom.packages.activatePackage('package-with-injection-selector', sync: true)
+
+        atom.packages.activatePackage('package-with-injection-selector')

         {tokens} = editor.lineForScreenRow(0)
         expect(tokens[1].value).toBe " SELECT * FROM OCTOCATS"
         expect(tokens[1].scopes).toEqual ["source.js", "comment.line.double-slash.js"]

-        atom.packages.activatePackage('language-sql', sync: true)
-
-        {tokens} = editor.lineForScreenRow(0)
-        expect(tokens[2].value).toBe "SELECT"
-        expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]
+        waitsForPromise ->
+          atom.packages.activatePackage('language-sql')
+
+        runs ->
+          {tokens} = editor.lineForScreenRow(0)
+          expect(tokens[2].value).toBe "SELECT"
+          expect(tokens[2].scopes).toEqual ["source.js", "comment.line.double-slash.js", "keyword.other.DML.sql"]


Send expected results from connection

Send expected results from connection

--- spec/mochacompat.coffee
+++ spec/mochacompat.coffee
@@ -21,12 +21,13 @@
   mochacompat.setup options, (err, state, httpServer) ->
     return callback err if err
     def = runtimeDefinition options
+    client = null
     fbpClient(def)
       .then((c) ->
         client = c
         return client.connect()
       )
-      .then((() -> callback()), callback)
+      .then((() -> callback(null, client, def, state, httpServer)), callback)
     return
   return

@@ -35,9 +36,9 @@
   onUpdate = (s) ->
     state = s
   ru.connect (err) ->
-    return done err if err
+    return callback err if err
     runner.getComponentSuites ru, (err, suites) ->
-      return done err if err
+      return callback err if err
       runner.runAll ru, suites, onUpdate, (err) ->
         return callback err, state


Enable editor.useShadowDOM in all specs

Enable editor.useShadowDOM in all specs

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -106,6 +106,7 @@
   config.set "editor.autoIndent", false
   config.set "core.disabledPackages", ["package-that-throws-an-exception",
     "package-with-broken-package-json", "package-with-broken-keymap"]
+  config.set "editor.useShadowDOM", true
   config.load.reset()
   config.save.reset()


:lipstick: PP

:lipstick: PP

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -73,12 +73,12 @@
 _keystroke = (keys, {element}) ->
   if keys is 'escape'
     keydown keys, {element}
-    return
-  for key in keys.split('')
-    if key.match(/[A-Z]/)
-      keydown key, {shift: true, element}
-    else
-      keydown key, {element}
+  else
+    for key in keys.split('')
+      if key.match(/[A-Z]/)
+        keydown key, {shift: true, element}
+      else
+        keydown key, {element}

 normalModeInputKeydown = (key, options={}) ->
   theEditor = options.editor ? E
@@ -91,19 +91,22 @@
   atom.commands.dispatch(inputEditor, 'core:confirm')

 toArray = (obj, cond=null) ->
-  if _.isArray(cond ? obj)
-    obj
-  else
-    [obj]
+  if _.isArray(cond ? obj) then obj else [obj]

 getVim = (vimState) ->
   editor: vimState.editor
   editorElement: vimState.editorElement

   set: (o={}) ->
-    @editor.setText(o.text) if o.text?
-    @editor.setCursorScreenPosition o.cursor if o.cursor?
-    @editor.setCursorBufferPosition o.cursorBuffer if o.cursorBuffer?
+    if o.text?
+      @editor.setText(o.text)
+
+    if o.cursor?
+      @editor.setCursorScreenPosition o.cursor
+
+    if o.cursorBuffer?
+      @editor.setCursorBufferPosition o.cursorBuffer
+
     if o.addCursor?
       for point in toArray(o.addCursor, o.addCursor[0])
         @editor.addCursorAtBufferPosition point
@@ -115,7 +118,9 @@
       else
         vimState.register.set '"', text: o.register

-    @editor.setSelectedBufferRange o.selectedBufferRange if o.selectedBufferRange?
+    if o.selectedBufferRange?
+      @editor.setSelectedBufferRange o.selectedBufferRange
+
     if o.spy?
       # e.g.
       # spyOn(editor, 'getURI').andReturn('/Users/atom/known_value.txt')
@@ -176,9 +181,11 @@
     if o.selectedBufferRangeStartRow?
       {start} = @editor.getSelectedBufferRange()
       expect(start.row).toEqual o.selectedBufferRangeStartRow
+
     if o.selectedBufferRangeEndRow?
       {end} = @editor.getSelectedBufferRange()
       expect(end.row).toEqual o.selectedBufferRangeEndRow
+
     if o.selectionIsReversed?
       expect(@editor.getLastSelection().isReversed()).toBe(o.selectionIsReversed)

@@ -194,6 +201,7 @@

     if o.mode?
       expect(vimState.mode).toEqual o.mode
+
     if o.submode?
       expect(vimState.submode).toEqual o.submode

@@ -201,6 +209,7 @@
       for klass in toArray(o.classListContains)
         expect(@editorElement.classList.contains(klass)).toBe(true)
         expect(@editorElement.classList.contains(klass)).toBe(true)
+
     if o.classListNotContains?
       for klass in toArray(o.classListNotContains)
         expect(@editorElement.classList.contains(klass)).toBe(false)
@@ -208,7 +217,7 @@

   keystroke: (keys, {element}={}) ->
     # keys must be String or Array
-    # Not support Object for keys intentionally to avoid ambiguity.
+    # Not support Object for keys to avoid ambiguity.
     element ?= @editorElement
     mocked = null
     if _.isString(keys)
@@ -222,26 +231,25 @@
       if _.isString(k)
         _keystroke(k, {element})
       else
-        if k.platform?
-          mockPlatform(element, k.platform)
-          mocked = true
-        else if k.char?
-          chars =
-            if k.char in ['', 'escape']
-              toArray(k.char)
-            else
-              k.char.split('')
-          for c in chars
-            options = {@editor}
-            options.shift = true if c.match(/[A-Z]/)
-            normalModeInputKeydown c, options
-        else if k.chars? then submitNormalModeInputText k.chars, {@editor}
-        else if k.ctrl? then keydown k.ctrl, {ctrl: true, element}
-        else if k.raw? then keydown k.raw, {raw: true, element}
-        else if k.cmd? then atom.commands.dispatch(k.cmd.target, k.cmd.name)
+        switch
+          when k.platform?
+            mockPlatform(element, k.platform)
+            mocked = true
+          when k.char?
+            chars =
+              if k.char in ['', 'escape']
+                toArray(k.char)
+              else
+                k.char.split('')
+            for c in chars
+              options = {@editor}
+              options.shift = true if c.match(/[A-Z]/)
+              normalModeInputKeydown c, options
+          when k.chars? then submitNormalModeInputText k.chars, {@editor}
+          when k.ctrl?  then keydown k.ctrl, {ctrl: true, element}
+          when k.raw?   then keydown k.raw, {raw: true, element}
+          when k.cmd?   then atom.commands.dispatch(k.cmd.target, k.cmd.name)
     if mocked
       unmockPlatform(element)

-module.exports = {
-  getVimState,
-}
+module.exports = {getVimState}


Refactor helper.

Refactor helper.

--- spec/spec_helper.coffee
+++ spec/spec_helper.coffee
@@ -1,17 +1,15 @@
-vows           = exports.vows   = require 'vows'
-assert         = exports.assert = require 'assert'
-tobi           = require 'tobi'
-app            = require('../config/app').app
-browser        = tobi.createBrowser(8000, 'localhost')
-defaultHeaders = { 'Content-Type': 'application/json' }
+app = require('../config/app').app

-exports.assertStatus = (code) ->
-  (response, $) ->
-    response.should.have.status(code)
+exports.vows   = require 'vows'
+exports.assert = require 'assert'

-exports.client =
-  get: (path) ->
-    () ->
-      browser.get(path, { headers: defaultHeaders }, this.callback)
+exports.zombie         = require 'zombie'
+exports.zombie.browser = new exports.zombie.Browser
+  debug:      false
+  runScripts: false

-app.listen 8000
+exports.tobi         = require 'tobi'
+exports.tobi.browser = exports.tobi.createBrowser app
+
+exports.headers             = {}
+exports.headers.jsonHeaders = { 'Content-Type': 'application/json' }


Fix indent.

Fix indent.

--- spec/spec_helper.coffee
+++ spec/spec_helper.coffee
@@ -7,6 +7,6 @@
     resp.status = status = options.errorStatus
     callback = options.error
   if Backbone.VERSION == '0.9.10'
-      callback(model, resp, options)
+    callback(model, resp, options)
   else
-      callback(resp, status, {})
+    callback(resp, status, {})


Adds filter to only show the attributes given in the array

A function (Array.compact) was added in my case and the function body was displayed in the table.

--- subtotal.coffee
+++ subtotal.coffee
@@ -197,7 +197,7 @@
         buildRowHeaderHeaders = (thead, rowHeaderHeaders, rowAttrs, colAttrs) ->
             tr = document.createElement("tr")
             rowHeaderHeaders.hh = []
-            for i, rowAttr of rowAttrs
+            for own i, rowAttr of rowAttrs
                 textContent = rowAttr
                 if i < rowAttrs.length-1
                     textContent = " " + arrowExpanded + " " + rowAttr


Doesn't load electron

Doesn't load electron

--- test/app.coffee
+++ test/app.coffee
@@ -1,6 +1,5 @@
 timeTracker = angular.module('timeTracker', [
   'analytics',
   'chrome',
-  'electron',
   'pascalprecht.translate'
 ])


fix(tests): Fix tests - reassignment stats

--- test/integration/product-import.spec.coffee
+++ test/integration/product-import.spec.coffee
@@ -561,8 +561,8 @@
           succeeded: 0,
           retries: 0,
           errors: 1,
-          processedSkus: []
-          failedSkus: [ 'sku4', 'sku3' ]
+          processedSkus: ['sku4', 'sku3']
+          failedSkus: ['sku4', 'sku3']
         })
         done()
       .catch (err) =>


cleanup

cleanup

--- js/src/crypto/RsaKeyGenerator.coffee
+++ js/src/crypto/RsaKeyGenerator.coffee
@@ -15,7 +15,7 @@
   class RsaKeyGenerator

     @generateKeypair: ->
-      params = {bits: RSA_KEY_SIZE, e: EXPONENT}
+      params = { bits: RSA_KEY_SIZE, e: EXPONENT }
       log.info('generating keypair', params)
       return Forge.rsa.generateKeyPair(params)


Allow UI a bit more time to update results

--- spec/browser/EditGraph.coffee
+++ spec/browser/EditGraph.coffee
@@ -99,11 +99,13 @@
       chai.expect(context).to.exist
       results = context.shadowRoot.querySelector 'noflo-search-library-results'
       chai.expect(results).to.exist
-      getelement = results.shadowRoot.querySelector 'li'
-      chai.expect(getelement).to.exist
-      Syn.click getelement
       setTimeout ->
-        nodes = graph.shadowRoot.querySelectorAll 'g.nodes g.node'
-        chai.expect(nodes.length).to.equal 1
-        done()
-      , 3000
+        getelement = results.shadowRoot.querySelector 'li'
+        chai.expect(getelement).to.exist
+        Syn.click getelement
+        setTimeout ->
+          nodes = graph.shadowRoot.querySelectorAll 'g.nodes g.node'
+          chai.expect(nodes.length).to.equal 1
+          done()
+        , 3000
+      , 10


Update multiply_elements.coffee

Update multiply_elements.coffee

Filled in blank file

--- spec/multiply_elements.coffee
+++ spec/multiply_elements.coffee
@@ -0,0 +1,29 @@
+noflo = require 'noflo'
+
+exports.getComponent = ->
+  c = new noflo.Component
+
+  c.inPorts.add 'func', (event, payload) ->
+    return unless event is 'data'
+    # Do something with the packet, then
+    c.outPorts.out.send payload
+  c.inPorts.add 'type', (event, payload) ->
+    return unless event is 'data'
+    # Do something with the packet, then
+    c.outPorts.out.send payload
+  c.inPorts.add 'state', (event, payload) ->
+    return unless event is 'data'
+    # Do something with the packet, then
+    c.outPorts.out.send payload
+  c.inPorts.add 'multiplier', (event, payload) ->
+    return unless event is 'data'
+    # Do something with the packet, then
+    c.outPorts.out.send payload
+  c.inPorts.add 'in', (event, payload) ->
+    return unless event is 'data'
+    # Do something with the packet, then
+    c.outPorts.out.send payload
+
+  c.outPorts.add 'product'
+
+  c


pull applescript out into a function

pull applescript out into a function

--- routes/index.coffee
+++ routes/index.coffee
@@ -1,6 +1,18 @@
 express = require("express")
 router = express.Router()
 applescript = require("applescript")
+
+# Navigation functions
+goToSlide = (direction) ->
+  script = """
+    tell application "Microsoft PowerPoint"
+      go to #{direction} slide (slide show view of slide show window 1)
+    end tell
+  """
+  applescript.execString script, (err, rtn) ->
+    # Something went wrong!
+    console.log err  if err
+    return

 # GET home page.
 router.get "/", (req, res) ->
@@ -11,13 +23,8 @@

 # GET next slide.
 router.get "/next", (req, res) ->
-  script = "tell application \"Microsoft PowerPoint\" to go to next slide (slide show view of slide show window 1)"
-  applescript.execString script, (err, rtn) ->
-
-    # Something went wrong!
-    console.log err  if err
-    return
-
+  goToSlide('next')
+
   res.render "index",
     title: "PowerPoint Server NEXT SLIDE"


hide tooltips

hide tooltips

--- client/ironTable.coffee
+++ client/ironTable.coffee
@@ -46,6 +46,7 @@
   "click .iron-table-delete-record": (e, tmpl) ->
     e.preventDefault()
     #e.stopImmediatePropagation()
+    $('.iron-table-delete-record').tooltip('hide')

     if not currentController = getCurrentIronTableController()
       CoffeeAlerts.error("Internal Error: Could not get controller")
@@ -59,6 +60,7 @@
   "click .iron-table-edit-record": (e, tmpl) ->
     e.preventDefault()
     #e.stopImmediatePropagation()
+    $('.iron-table-edit-record').tooltip('hide')

     if not currentController = getCurrentIronTableController()
       CoffeeAlerts.error("Internal Error: Could not get controller")


Clean up code.

Clean up code.

--- deferred.coffee
+++ deferred.coffee
@@ -68,25 +68,3 @@
 exports.ListenerList = ListenerList
 exports.Promise      = Promise
 exports.Deferred     = Deferred
-
-#delay = (ms, task) ->
-#  setTimeout task, ms
-#
-#task1 = ->
-#  d = new Deferred()
-#  delay 1000, ->
-#    console.log "task1!!"
-#    d.resolve()
-#  d.promise()
-#
-#task2 = ->
-#  d = new Deferred()
-#  delay 1000, ->
-#    console.log "task2!!"
-#    d.resolve()
-#  d.promise()
-#
-#task3 = ->
-#  console.log "task3!!"
-#
-#task1().done(task2)


fix typo of auth key

fix typo of auth key

--- app/scripts/controllers/main.coffee
+++ app/scripts/controllers/main.coffee
@@ -106,7 +106,7 @@
         msg = if payload.message.user then "[#{payload.message.user}] #{payload.message.text}" else "[unknown] #{payload.message}"
         $scope.$apply -> $scope.messages.unshift msg

-      PubNub.ngHistory { channel: $scope.selectedChannel, auth_key: $scope.data.authKey, count:500 }
+      PubNub.ngHistory { channel: $scope.selectedChannel, auth_key: $scope.authKey, count:500 }

     ### When controller initializes, subscribe to retrieve channels from "control channel" ###
     PubNub.ngSubscribe { channel: $scope.controlChannel }


using Object.defineProperty instead of __defineMethods__

--- atom/renderer/api/lib/remote.coffee
+++ atom/renderer/api/lib/remote.coffee
@@ -69,15 +69,18 @@
                   ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_CALL', meta.id, member.name, wrapArgs(arguments)
                   return metaToValue ret
           else
-            ret.__defineSetter__ member.name, (value) ->
-              # Set member data.
-              ipc.sendSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
-              value
+            Object.defineProperty ret, member.name,
+              enumerable: true,
+              configurable: false,
+              set: (value) ->
+                # Set member data.
+                ipc.sendSync 'ATOM_BROWSER_MEMBER_SET', meta.id, member.name, value
+                value

-            ret.__defineGetter__ member.name, ->
-              # Get member data.
-              ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
-              metaToValue ret
+              get: ->
+                # Get member data.
+                ret = ipc.sendSync 'ATOM_BROWSER_MEMBER_GET', meta.id, member.name
+                metaToValue ret

       # Track delegate object's life time, and tell the browser to clean up
       # when the object is GCed.


comment out broken length check

comment out broken length check

--- services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
+++ services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
@@ -648,9 +648,9 @@

 	checkValidElementName: (folder, name, callback = (err) ->) ->
-		# check if the path would be too long
-		if not SafePath.isAllowedLength "#{folder}/#{name}"
-			return callback new Error.InvalidNameError("path too long")
+		# # # check if the path would be too long
+		# # if not SafePath.isAllowedLength "#{folder}/#{name}"
+		# # 	return callback new Error.InvalidNameError("path too long")
 		# check if the name is already taken by a doc, file or
 		# folder. If so, return an error "file already exists".
 		err = new Errors.InvalidNameError("file already exists")


Scene: Add set_objects_auto_update_matrix()

--- engine/scene.coffee
+++ engine/scene.coffee
@@ -236,6 +236,18 @@
             ob._update_matrices()
         return

+    set_objects_auto_update_matrix: (objects, auto_update) ->
+        static_ = not auto_update
+        for ob in objects
+            ob.static = static_
+        # TODO for performance: do this only once? push and pop objects?
+        count = 0
+        for ob in @children when not ob.static
+            count++
+        @auto_updated_children.length = count
+        @_children_are_ordered = false
+        return
+
     destroy: ->
         for ob in @children[...]
             @remove_object ob, false
@@ -278,21 +290,26 @@
         options = {}
         if typeof items[items.length-1] == 'object'
             options = items.pop()
+
         {visible, physics, all} =
             @_ensure_items items, ['visible', 'physics', 'all']

         objects = []
+
         for ob in @children
             ob_being_loaded = null
             if all or (visible and ob.visible)
                 ob_being_loaded = ob
                 objects.push ob
+
             if physics
                 phy_mesh = ob.body.get_physics_mesh()
                 if phy_mesh? and phy_mesh != ob_being_loaded \
                         and not phy_mesh.data?
                     objects.push phy_mesh
+
         promise = fetch_objects(objects, options).then(=>@)
+
         if physics
             # TODO: Handle case without webpack
             if @context.webpack_flags?.include_bullet


tests for node_modules import

tests for node_modules import

--- tests/test_builder.coffee
+++ tests/test_builder.coffee
@@ -797,13 +797,13 @@
         mock(yaml.safeLoad("""
             testimonial:
                 lib:
-                    a.js:
+                    a.js: |
                         var b = require("b");
                 node_modules:
                     b:
-                        index.js:
+                        index.js: |
                             var c = require("./c");
-                        c.js:
+                        c.js: |
                             module.exports = 1;
                 spa.yaml: |
                     pretty: true
@@ -844,6 +844,88 @@
             url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/index.js")

         expect(manifest.modules[2]).to.have.properties
+            id: -> @that.equals("a")
+            deps: -> @that.deep.equals
+                "b": "b"
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/lib/a.js")
+
+
+describe 'Building modules with dependency from node_modules (import from the deep)', ->
+    beforeEach ->
+        mock(yaml.safeLoad("""
+            testimonial:
+                lib:
+                    a.js: |
+                        var b = require("b");
+                node_modules:
+                    b:
+                        index.js: |
+                            var c = require("c");
+                        node_modules:
+                            c:
+                                index.js: |
+                                    var d = require("d");
+                                node_modules:
+                                    d:
+                                        index.js: |
+                                            var e = require("e");
+                    e:
+                        index.js: |
+                            module.exports = 1;
+                spa.yaml: |
+                    pretty: true
+                    root: "/testimonial/"
+                    hosting:
+                        "./(**/*.*)": "http://127.0.0.1:8010/$1"
+                    extensions:
+                        - .js
+                    excludes:
+                        - "./node_modules/**"
+                    manifest: "manifest.json"
+                    grab: true
+                    default_loader: junk
+            """))
+
+    it 'should successfully build', ->
+        builder = spa.Builder.from_config("/testimonial/spa.yaml")
+
+        builder.build()
+        expect(fs.existsSync("/testimonial/manifest.json")).to.be.true
+        manifest = JSON.parse(fs.readFileSync("/testimonial/manifest.json", encoding: "utf8"))
+
+        expect(manifest)
+            .to.have.property('modules')
+            .to.be.an("Array").with.length(5)
+
+        expect(manifest.modules[0]).to.have.properties
+            id: -> @that.equals("e")
+            deps: -> @that.deep.equals({})
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/node_modules/e/index.js")
+
+        expect(manifest.modules[1]).to.have.properties
+            id: -> @that.equals("d")
+            deps: -> @that.deep.equals
+                "e": "e"
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/node_modules/c/node_modules/d/index.js")
+
+        expect(manifest.modules[2]).to.have.properties
+            id: -> @that.equals("c")
+            deps: -> @that.deep.equals
+                "d": "d"
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/node_modules/c/index.js")
+
+        expect(manifest.modules[3]).to.have.properties
+            id: -> @that.equals("b")
+            deps: -> @that.deep.equals
+                "c": "c"
+            type: -> @that.equals("cjs")
+            url: -> @that.equals("http://127.0.0.1:8010/node_modules/b/index.js")
+
+        expect(manifest.modules[4]).to.have.properties
             id: -> @that.equals("a")
             deps: -> @that.deep.equals
                 "b": "b"


only Intercom(boot) once - Intercom(update) thereafter

--- client/code/router/main.coffee
+++ client/code/router/main.coffee
@@ -49,7 +49,11 @@
     _gaq.push ['_trackPageview', "/#{path}"]
     if 'real' of window.user and window.intercomUserHash != ''
       @getIntercomSettings (intercomSettings) ->
-        window.Intercom 'boot', intercomSettings
+        if window.intercomBooted?
+          window.Intercom 'update', intercomSettings
+        else
+          window.Intercom 'boot', intercomSettings
+          window.intercomBooted = true

   getIntercomSettings: (cb) ->
     # :TODO: It feels wrong fetching the user models *again* here


Notify Young Witch bane card that the game is starting when the card is added

--- cards.coffee
+++ cards.coffee
@@ -1350,6 +1350,8 @@

     # Add the bane to the supply
     state.supply[bane] = bane.startingSupply(state)
+    # Notify the new card that the game is starting
+    bane.startGameEffect(state)
     state.log("Young Witch Bane card is #{bane}")

   playEffect: (state) ->


Link dialog url

Link dialog url

--- app/assets/javascripts/ckeditor/plugins/effective_regions/plugin.js.coffee
+++ app/assets/javascripts/ckeditor/plugins/effective_regions/plugin.js.coffee
@@ -1,7 +1,5 @@
 SaveAll = {
   instanceData: (instance) ->
-    instance.resetDirty()
-
     snippets = {} # This is the Data we're going to post to the server
     snippet_ids = [] # This keeps track html classes we need to later replace

@@ -30,14 +28,8 @@

   exec: (editor) ->
     # Show a checkmark on the Save button
-    try
-      button = $("##{this.uiItems[0]._.id}").find('.cke_button__save_icon')
-
-      button.addClass('saving')
-      setTimeout(
-        -> button.removeClass('saving')
-        2000
-      )
+    button = $("##{this.uiItems[0]._.id}").find('.cke_button__save_icon')
+    try button.addClass('saving')

     url = window.location.protocol + '//' + window.location.host + '/edit' + window.location.pathname

@@ -55,9 +47,17 @@
       dataType: 'json'
       data: { effective_regions: regionData, effective_menus: menuData }
       async: false
-      complete: (response) ->
+      complete: (response) =>
+        instance.resetDirty() for name, instance of CKEDITOR.instances
+
         data = response['responseJSON'] || {}
         $('.effective-menu').effectiveMenuEditor('saveComplete', data['effective_menus'])
+
+        setTimeout(
+          -> button.removeClass('saving')
+          200
+        )
+
         location.reload(true) if data['refresh'] == true
 }


fixed country dropdown to only include countries

--- app/assets/javascripts/trade/controllers/geo_entities_controller.js.coffee
+++ app/assets/javascripts/trade/controllers/geo_entities_controller.js.coffee
@@ -8,4 +8,4 @@

   load: ->
     unless @get('loaded')
-      @set('content', Trade.GeoEntity.find())+      @set('content', Trade.GeoEntity.find({geo_entity_type: 'COUNTRY'}))


webapp/course: skip grading does not write a grade file, except when there is a grad in peer grading mode

--- src/smc-webapp/course/actions.coffee
+++ src/smc-webapp/course/actions.coffee
@@ -934,6 +934,12 @@
             return finish("no assignment")
         student_name = store.get_student_name(student)
         student_project_id = student.get('project_id')
+
+        # if skip_grading is true, this means there *might* no be a "grade" given,
+        # but instead some grading inside the files or an external tool is used.
+        # therefore, only create the grade file if this is false.
+        skip_grading = assignment.get('skip_grading') ? false
+
         if not student_project_id?
             # nothing to do
             @clear_activity(id)
@@ -948,10 +954,18 @@
             src_path += '/' + student.get('student_id')
             async.series([
                 (cb) =>
+                    if skip_grading and not peer_graded
+                        cb(); return
                     # write their grade to a file
-                    content = "Your grade on this assignment:\n\n    #{grade}"
+                    content = "Your grade on this assignment:"
+                    if grade?   # likely undefined when skip_grading true & peer_graded true
+                        content = "\n\n    #{grade}"
                     if peer_graded
-                        content += "\n\n\nPEER GRADED:\n\nYour assignment was peer graded by other students.\nYou can find the comments they made in the folders below."
+                        content += """
+                                   \n\n\nPEER GRADED:\n
+                                   Your assignment was peer graded by other students.
+                                   You can find the comments they made in the folders below.
+                                   """
                     webapp_client.write_text_file_to_project
                         project_id : store.get('course_project_id')
                         path       : src_path + '/GRADE.txt'


fixed that deleting projects with no upgrades was completely broken by https://github.com/sagemathinc/smc/pull/1077

--- src/smc-webapp/project_settings.cjsx
+++ src/smc-webapp/project_settings.cjsx
@@ -510,7 +510,7 @@
     # account_id : String
     # project    : immutable.Map
     user_has_applied_upgrades : (account_id, project) ->
-         project.getIn(['users', account_id, 'upgrades']).some (val) => val > 0
+         project.getIn(['users', account_id, 'upgrades'])?.some (val) => val > 0

     delete_message : ->
         if @props.project.get('deleted')


Less backbone methods to make this work w Exos.

--- src/chaplin/dispatcher.coffee
+++ src/chaplin/dispatcher.coffee
@@ -112,8 +112,8 @@

     # Save the new controller and its parameters.
     @currentController = controller
-    @currentParams = _.clone params
-    @currentQuery = _.clone options.query
+    @currentParams = _.extend {}, params
+    @currentQuery = _.extend {}, options.query

     # Call the controller action with params and options.
     controller[route.action] params, route, options