activity feed: minor refactoring

activity feed: minor refactoring

--- client/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/app/Applications/Activity.kdapplication/AppController.coffee
@@ -47,7 +47,8 @@
     status = @getSingleton "status"
     status.on "reconnected", (reason)=>
       if reason is "internetDownForLongTime"
-        @reset()
+        @resetAll()
+        @populateActivity()
       else
         @fetchSomeActivities()

@@ -60,16 +61,12 @@
       ac = @getSingleton('activityController')
       ac.once "ActivityListControllerReady", @populateActivity.bind @

-  reset:->
-    @resetList()
-    @listController.resetList()
-    @populateActivity()
-
-  resetList:->
+  resetAll:->

     delete @lastTo
     delete @lastFrom

+    @listController.resetList()
     @listController.removeAllItems()

   setFilter:(type) -> @currentFilter = if type? then [type] else activityTypes
@@ -100,8 +97,7 @@
           controller.followedActivityArrived activities.first

     @getView().innerNav.on "NavItemReceivedClick", (data)=>
-      @resetList()
-      @listController.resetList()
+      @resetAll()
       @setFilter data.type
       @populateActivity()


stop GroupView from throwing a TypeError about missing twipsy

--- client/app/Applications/Groups.kdapplication/Views/groupview.coffee
+++ client/app/Applications/Groups.kdapplication/Views/groupview.coffee
@@ -11,8 +11,8 @@
       bind        : "error"
       error       : =>
         @thumb.$().attr "src", "/images/default.app.thumb.png"
-      attributes  :
-        src       : @getData().avatar or "http://lorempixel.com/60/60/?#{@utils.getRandomNumber()}}"
+      # attributes  :
+      #   src       : @getData().avatar or "http://lorempixel.com/60/60/?#{@utils.getRandomNumber()}}"

     @joinButton = new JoinButton
       style           : if data.member then "join follow-btn following-topic" else "join follow-btn"


Use koding.com instead of beta.koding to fix filetree view feature

--- client/app/MainApp/filetree/controllers/findertreecontroller.coffee
+++ client/app/MainApp/filetree/controllers/findertreecontroller.coffee
@@ -126,7 +126,7 @@
   previewFile:(nodeView, event)->

     file = nodeView.getData()
-    publicPath = file.path.replace /.*\/(.*\.beta.koding.com)\/website\/(.*)/, 'http://$1/$2'
+    publicPath = file.path.replace /.*\/(.*\.koding.com)\/website\/(.*)/, 'http://$1/$2'
     if publicPath is file.path
       {nickname} = KD.whoami().profile
       appManager.notify "File must be under: /#{nickname}/Sites/#{nickname}.#{location.hostname}/website/"


teams: join: username tab's redundant content removed

--- client/landing/site.landing/coffee/team/tabs/teamusernametab.coffee
+++ client/landing/site.landing/coffee/team/tabs/teamusernametab.coffee
@@ -4,30 +4,17 @@

 module.exports = class TeamUsernameTab extends KDTabPaneView

-  kallback = (formData) ->
-
-    { storeNewTeamData, createTeam, joinTeam, getTeamData } = KD.utils
-    { join } = getTeamData().signup
-
-    if join
-      storeNewTeamData 'join', formData
-      joinTeam()
-    else do ->
-      storeNewTeamData 'username', formData
-      createTeam success : -> KD.singletons.router.handleRoute '/Team/Stacks'
-
-
   constructor:(options = {}, data)->

     super options, data
-
-    teamData = KD.utils.getTeamData()
-    { @alreadyMember } = teamData.signup

     @createSubViews()

   createSubViews: ->
+
+    teamData = KD.utils.getTeamData()
+    { @alreadyMember } = teamData.signup

     @addSubView new MainHeaderView
       cssClass : 'team'
@@ -46,7 +33,7 @@
         tagName : 'h5'
         partial : 'please enter your Koding password'

-      wrapper.addSubView @form = new TeamLoginAndCreateTabForm { callback : kallback }
+      wrapper.addSubView @form = new TeamLoginAndCreateTabForm callback : @bound 'createTeam'

     else

@@ -59,7 +46,7 @@
         partial : '...or login with your existing Koding account.'

       wrapper.addSubView @form = new TeamUsernameTabForm
-        callback : @bound 'createTeam'
+        callback    : @bound 'createTeam'

   show: ->
@@ -67,7 +54,6 @@
     teamData = KD.utils.getTeamData()
     { alreadyMember } = teamData.signup
     if alreadyMember isnt @alreadyMember
-      @alreadyMember = alreadyMember
       @form = null
       @destroySubViews()
       @createSubViews()
@@ -85,7 +71,10 @@
       return new KDNotificationView title : "Sorry, your group domain and your username can not be the same!"

     KD.utils.usernameCheck username,
-      success : -> kallback formData
+      success : ->
+        KD.utils.storeNewTeamData 'username', formData
+        KD.utils.createTeam success : -> KD.singletons.router.handleRoute '/Team/Stacks'
+
       error   : ({responseJSON}) =>

         {forbidden, kodingUser} = responseJSON


More standard ES5 shims

More standard ES5 shims

--- src/tools/es5.coffee
+++ src/tools/es5.coffee
@@ -9,14 +9,14 @@
 Object.keys ||= (obj)->
   k for k, v of obj

-Array::forEach ||= (fn)->
-  fn z, i for z, i in @
-  return
-
 Array::indexOf ||= (el)->
   for n, i in @
     return i if el == n
   -1

+Array::forEach ||= (fn)->
+  fn z, i, @ for z, i in @
+  return
+
 Array::filter ||= (fn)->
-  z for z, i in @ when fn z, i
+  z for z, i in @ when fn z, i, @


require moment-timezone after moment

require moment-timezone after moment

Twix doesn't like to be set on moment-timezone

--- tutor/src/components/course-calendar/month.cjsx
+++ tutor/src/components/course-calendar/month.cjsx
@@ -1,7 +1,8 @@
 React = require 'react'
 ReactDOM = require 'react-dom'
 BS = require 'react-bootstrap'
-moment = require 'moment-timezone'
+moment = require 'moment'
+require 'moment-timezone'
 twix = require 'twix'
 _ = require 'underscore'
 classnames = require 'classnames'


important changes to ModelBackedView

important changes to ModelBackedView

now, ModelBackedView will use a `attributes` array property, which will
contain the properties that will be used on the form.
You can use `bindAttributesTo` property to specify the source (by
default, it will be the view’s model).
You can use `getFormData` to get an object with the attributes
specified for the form.
the `defineComputedPropertiesForAttributes` method will define the
attributes (and bindings to it’s source) on the fly when the view is
created

--- app/assets/javascripts/classes/model_backed_view.js.coffee
+++ app/assets/javascripts/classes/model_backed_view.js.coffee
@@ -1,8 +1,14 @@
 Bandango.ModelBackedView = Ember.View.extend
+  # defaults
   raw_errors: {}
   errors: {}
+  tagName: "form"
+  attributes: []
+  bindAttributesTo: "model"

-  tagName: "form"
+  init: ->
+    @_super()
+    @defineComputedPropertiesForAttributes()

   errors_messages: (->
     messages = []
@@ -19,10 +25,22 @@
     if not @get("model") or @get("model").get("isNew") then "Crear" else "Actualizar"
   ).property("model")

+  getFormData: ->
+    @getProperties @get("attributes")
+
+  defineComputedPropertiesForAttributes: ->
+    if bindTo = @get("bindAttributesTo")
+      for attribute in @get("attributes")
+        Ember.defineProperty @, attribute, (->
+          @get(bindTo).get(arguments[0])
+        ).property()
+    null
+
   emptyErrors: ->
     @setProperties
       errors: {}
       raw_errors: {}
+    null

   setErrors: (the_errors) ->
     errors = {}
@@ -31,3 +49,4 @@
     @setProperties
       errors: errors
       raw_errors: the_errors
+    null


Clean up counts display for #44

Clean up counts display for #44

--- show-counts.coffee
+++ show-counts.coffee
@@ -3,7 +3,7 @@

 classifyPage = currentProject.classifyPages[0]
 {subjectViewer, decisionTree} = classifyPage
-markingSurface = subjectViewer.markingSurface
+{markingSurface} = subjectViewer
 decisionTreeEl = $(decisionTree.el)

 window.dt = decisionTree
@@ -13,19 +13,24 @@

 badges = {}

+getCount = (value) ->
+  (mark for {mark} in markingSurface.tools when mark.value is value).length
+
 decisionTreeEl.on decisionTree.LOAD_TASK, ({originalEvent: detail: {task}}) ->
   if task.type is 'drawing'
     labels = decisionTreeEl.find '[data-task-type="drawing"] .readymade-choice-label'
-    for choice, i in task.choices
-      badges[choice.value] = $('0')
-      badges[choice.value].insertAfter labels[i]
+    for {value}, i in task.choices
+      count = getCount value
+      badges[value]?.remove()
+      badges[value] = $("#{count}")
+      badges[value].insertAfter labels[i]

 markingSurface.on 'marking-surface:add-tool', (tool) ->
-  count = parseFloat(badges[tool.mark.value].html()) + 1
+  count = getCount tool.mark.value
   badges[tool.mark.value].html count
   badges[tool.mark.value].attr 'data-count', count

 markingSurface.on 'marking-surface:remove-tool', (tool) ->
-  count = parseFloat(badges[tool.mark.value].html()) - 1
+  count = getCount tool.mark.value
   badges[tool.mark.value].html count
   badges[tool.mark.value].attr 'data-count', count


draw tourism=guest_house

draw tourism=guest_house

--- src/ui/symbol.coffee
+++ src/ui/symbol.coffee
@@ -118,6 +118,7 @@

 app.symbol.chalet = app.symbol.alpine_hut
 app.symbol.hotel = app.symbol.alpine_hut
+app.symbol.guest_house = app.symbol.alpine_hut

 app.symbol.basic_hut = (selection) ->


add option to synchronize tabs

add option to synchronize tabs

--- lib/edit-in-new-tab.coffee
+++ lib/edit-in-new-tab.coffee
@@ -2,45 +2,52 @@

 module.exports = EditInNewTab =
   config:
-    ignoreScope:
-      title: "Ignore Scope"
-      description: "Don't set the current scope in target tab"
+    synchronizeChanges:
+      title: "Synchronize Changes"
+      description: "Writes changes in the new tab back to the origin"
       type: "boolean"
       default: false
       order: 1
+    ignoreScope:
+      title: "Ignore Scope"
+      description: "Doesn't apply the origin's grammar on the new tab"
+      type: "boolean"
+      default: false
+      order: 2
     outputFormat:
       title: "Output Format"
       type: 'object'
+      order: 3
       properties:
         select:
           title: "Select"
           description: "Selects the newly added text"
           type: "boolean"
           default: false
-          order: 2
+          order: 1
         autoIndent:
           title: "Auto-indent"
           description: "Indents all inserted text appropriately"
           type: "boolean"
           default: true
-          order: 3
+          order: 2
         autoIndentNewline:
           title: "Auto-indent New Line"
-          description: "Indent newline appropriately"
+          description: "Indent new line appropriately"
+          type: "boolean"
+          default: true
+          order: 3
+        autoDecreaseIndent:
+          title: "Auto-decrease Indent"
+          description: "Decreases indent level appropriately (for example, when a closing bracket is inserted)"
           type: "boolean"
           default: true
           order: 4
-        autoDecreaseIndent:
-          title: "Auto-decreate Indent"
-          description: "Decreases indent level appropriately (for example, when a closing bracket is inserted)"
-          type: "boolean"
-          default: true
-          order: 5
         normalizeLineEndings:
           title: "Normalize Line Endings"
           type: "boolean"
           default: true
-          order: 6
+          order: 5
   subscriptions: null

   activate: (state) ->
@@ -57,17 +64,19 @@
   editInNewTab: (cutSelection) ->
     return unless editor = atom.workspace.getActiveTextEditor()

-    selection = editor.getLastSelection()
+    parentEditor = editor.id
+    parentSelection = editor.getLastSelection()

     target =
       scope: editor.getGrammar().scopeName
-      text: selection.getText()
+      text: parentSelection.getText()

     unless target.text.length > 0
       return atom.beep()

+    # Move to new Tab?
     if cutSelection is true
-      selection.delete()
+      parentSelection.delete()

     atom.workspace.open()
       .then (newTab) ->
@@ -79,7 +88,18 @@
           normalizeLineEndings: atom.config.get('edit-in-new-tab.outputFormat.normalizeLineEndings')

         newTab.insertText(target.text, options)
+
         unless atom.config.get('edit-in-new-tab.ignoreScope') is true
           newTab.setGrammar(atom.grammars.grammarForScopeName(target.scope))
+
+        if atom.config.get('edit-in-new-tab.synchronizeChanges') is true and cutSelection is false
+          childEditor = atom.workspace.getActiveTextEditor().id
+
+          atom.workspace.observeTextEditors (editor) =>
+            return unless editor.id is childEditor
+
+            editor.onDidStopChanging =>
+              parentSelection.insertText(editor.getText(), { select: true })
+
       .catch (error) ->
         atom.notifications.addError(error, dismissable: true)


Removing comment

Removing comment

--- src/client/special_event_handler.coffee
+++ src/client/special_event_handler.coffee
@@ -39,7 +39,6 @@
                          clientEvent.target.__nodeID,
                          'value',
                          clientEvent.target.value)
-            # Do some special processing for files here
         @socket.emit('processEvent', remoteEvent, id)

     keyup : (rEvent, event, id) =>


Optionally pass LARA information back to client for logging [#151493445] passes the following information (if known) - run state URL - document store document ID - document store document URL

--- src/code/providers/lara-provider.coffee
+++ src/code/providers/lara-provider.coffee
@@ -62,6 +62,9 @@
     else
       false

+  logLaraData: (laraData) ->
+    @options.logLaraData laraData if @options.logLaraData
+
   # don't show in provider open/save dialogs
   filterTabComponent: (capability, defaultComponent) ->
     null
@@ -97,7 +100,12 @@
         accessKey: accessKey
       context: @

-      success: (data) ->
+      success: (data) =>
+        @logLaraData {
+          operation: 'open'
+          documentID: metadata.providerData?.recordid
+          documentUrl: url
+        }
         content = cloudContentFactory.createEnvelopedCloudContent data

         # for documents loaded by id or other means (besides name),
@@ -270,7 +278,12 @@
             url: url,
             dataType: 'json'
           })
-          .done (createResponse, status, jqXHR) ->
+          .done (createResponse, status, jqXHR) =>
+            @logLaraData {
+              operation: 'clone'
+              documentID: docStore.recordid
+              documentUrl: url
+            }
             processCreateResponse createResponse
             callback null
           .fail (jqXHR, status, error) ->
@@ -383,7 +396,12 @@
         xhrFields:
           withCredentials: true
       })
-      .done (data, status, jqXHR) ->
+      .done (data, status, jqXHR) =>
+        @logLaraData {
+          operation: 'open'
+          runStateUrl: openSavedParams.url
+          documentID: openSavedParams.source
+        }
         processInitialRunState openSavedParams.url, openSavedParams.source, openSavedParams.readOnlyKey, data
       .fail (jqXHR, status, error) ->
         callback "Could not open the specified document because an error occurred [getState]"


Log resourceError

Log resourceError

--- lib/mocha-phantomjs.coffee
+++ lib/mocha-phantomjs.coffee
@@ -41,6 +41,8 @@
     @page.addCookie(cookie) for cookie in @config.cookies or []
     @page.viewportSize = @config.viewportSize if @config.viewportSize
     @page.onConsoleMessage = (msg) -> system.stdout.writeLine(msg)
+    @page.onResourceError  = (msg) ->
+      system.stdout.writeLine(JSON.stringify(msg))
     @page.onError = (msg, traces) =>
       return if @page.evaluate -> window.onerror?
       for {line, file}, index in traces


Move stack trace helpers into deprecation block

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -7,7 +7,6 @@
 {Emitter, Disposable, CompositeDisposable} = require 'event-kit'
 Grim = require 'grim'
 fs = require 'fs-plus'
-StackTraceParser = require 'stacktrace-parser'
 Model = require './model'
 TextEditor = require './text-editor'
 PaneContainer = require './pane-container'
@@ -495,34 +494,6 @@
   getOpeners: ->
     @openers

-  getCallingPackageName: ->
-    error = new Error
-    Error.captureStackTrace(error)
-    stack = StackTraceParser.parse(error.stack)
-
-    packagePaths = @getPackagePathsByPackageName()
-
-    for i in [0...stack.length]
-      stackFramePath = stack[i].file
-
-      # Empty when it was run from the dev console
-      return unless stackFramePath
-
-      for packageName, packagePath of packagePaths
-        continue if stackFramePath is 'node.js'
-        relativePath = path.relative(packagePath, stackFramePath)
-        return packageName unless /^\.\./.test(relativePath)
-    return
-
-  getPackagePathsByPackageName: ->
-    packagePathsByPackageName = {}
-    for pack in atom.packages.getLoadedPackages()
-      packagePath = pack.path
-      if packagePath.indexOf('.atom/dev/packages') > -1 or packagePath.indexOf('.atom/packages') > -1
-        packagePath = fs.realpathSync(packagePath)
-      packagePathsByPackageName[pack.name] = packagePath
-    packagePathsByPackageName
-
   ###
   Section: Pane Items
   ###
@@ -907,6 +878,36 @@
       Grim.deprecate "Use ::getActivePane() instead of the ::activePane property"
       @getActivePane()

+  StackTraceParser = require 'stacktrace-parser'
+
+  Workspace::getCallingPackageName = ->
+    error = new Error
+    Error.captureStackTrace(error)
+    stack = StackTraceParser.parse(error.stack)
+
+    packagePaths = @getPackagePathsByPackageName()
+
+    for i in [0...stack.length]
+      stackFramePath = stack[i].file
+
+      # Empty when it was run from the dev console
+      return unless stackFramePath
+
+      for packageName, packagePath of packagePaths
+        continue if stackFramePath is 'node.js'
+        relativePath = path.relative(packagePath, stackFramePath)
+        return packageName unless /^\.\./.test(relativePath)
+    return
+
+  Workspace::getPackagePathsByPackageName = ->
+    packagePathsByPackageName = {}
+    for pack in atom.packages.getLoadedPackages()
+      packagePath = pack.path
+      if packagePath.indexOf('.atom/dev/packages') > -1 or packagePath.indexOf('.atom/packages') > -1
+        packagePath = fs.realpathSync(packagePath)
+      packagePathsByPackageName[pack.name] = packagePath
+    packagePathsByPackageName
+
   Workspace::eachEditor = (callback) ->
     deprecate("Use Workspace::observeTextEditors instead")


Remove errant log

Remove errant log

--- lib/package-manager.coffee
+++ lib/package-manager.coffee
@@ -17,8 +17,6 @@
   constructor: ->
     @packagePromises = []
     @packageLister = new PackageLister
-    @packageLister.getPackages (err, packages) ->
-      console.log packages

   runCommand: (args, callback) ->
     command = atom.packages.getApmPath()


:bug: Wait for updated package to load and then try to activate

This is a fix for issue #532 - Package cards in Updates panel don't change state when updates are done installing.

Before this commit, updating a package that had activation commands would cause the package card to display the loading state forever.

The cause of the issue was that the update process was waiting for the updated package to activate. This was a problem because calling `activatePackage` will only immediately activate a package that doesn't have any activationCommands.

The proposed fix is to wait for the package to load and then attempt to activate the package without waiting.

--- lib/package-manager.coffee
+++ lib/package-manager.coffee
@@ -274,12 +274,13 @@
     exit = (code, stdout, stderr) =>
       if code is 0
         @clearOutdatedCache()
-        activation = if activateOnSuccess
-          atom.packages.activatePackage(name)
-        else
-          atom.packages.loadPackage(name)
-
-        Promise.resolve(activation).then =>
+
+        loadedPackage = atom.packages.loadPackage(name)
+
+        Promise.resolve(loadedPackage).then =>
+          if activateOnSuccess
+            atom.packages.activatePackage(name)
+
           callback?()
           @emitPackageEvent 'updated', pack
       else


:bug: Fix lack of index change in PredictionList

--- lib/prediction-list.coffee
+++ lib/prediction-list.coffee
@@ -42,7 +42,7 @@
       when amount > 0 then 'next'
       else 'prev'

-    index = @_index + amount
+    index = @_index += amount

     unless 0 <= index < @_predictions.length
       # Wrap the value around.


DataTable: Added 'padded' support.

DataTable: Added 'padded' support.

--- src/elements/DataTable/DataTable.coffee
+++ src/elements/DataTable/DataTable.coffee
@@ -47,6 +47,9 @@
 				mandatory: true
 				check: (v) ->
 					v >= 0
+			padded:
+				check: Boolean
+				default: false

 	readOpts: ->
 		super()
@@ -258,6 +261,7 @@
 		@listView = new CUI.ListView
 			class: "cui-lv--has-datafields"
 			selectableRows: @_new_rows != "none"
+			padded: @_padded
 			onSelect: =>
 				@updateButtons()
 			onDeselect: =>


Construct remote API shims immediately

Construct remote API shims immediately

--- index.coffee
+++ index.coffee
@@ -68,8 +68,8 @@
     unless @useWebsockets
       @once 'ready', =>
         process.nextTick @bound 'xhrHandshake'
-    process.nextTick =>
-      @api = @createRemoteApiShims @apiDescriptor
+
+    @api = @createRemoteApiShims @apiDescriptor

     if @mq?
       @eventBus = new EventBus @mq


fix a bug

fix a bug

--- index.coffee
+++ index.coffee
@@ -1,9 +1,11 @@
 assign = require 'object-assign'

-hexo.config.html_minifier = assign {
-  exclude: []
-}, hexo.config.html_minifier
+module.exports = ->
+  hexo = this
+  hexo.config.html_minifier = assign {
+    exclude: []
+  }, hexo.config.html_minifier

-priority = html_minifier.priority or 10000
+  priority = html_minifier.priority or 10000

-hexo.extend.filter.register 'after_generate', require('./lib/filter'), priority+  hexo.extend.filter.register 'after_generate', require('./lib/filter'), priority


Update Github username

Update Github username

--- index.coffee
+++ index.coffee
@@ -3,7 +3,7 @@

 request = request.defaults
   headers:
-    'User-Agent': 'baconscript/github-issues'
+    'User-Agent': 'r24y/github-issues'

 GH_REGEX = /^(https:\/\/|git@)github\.com(\/|:)([-\w]+)\/([-\w]+)(\.git)?$/


Use long option

Use long option

--- index.coffee
+++ index.coffee
@@ -48,7 +48,7 @@
       args = [
         '--releasify'
         nupkgPath
-        '-g'
+        '--loadingGif'
         loadingGif
       ]
       grunt.util.spawn {cmd, args}, (error, result, code) -> done(error)


clean up script

clean up script

--- index.coffee
+++ index.coffee
@@ -2,14 +2,16 @@
 Twitter = require 'simple-twitter'
 config = require './config'
 crypto = require 'crypto'
+
 twitter = new Twitter(config.twitter.consumerKey,config.twitter.consumerSecret,config.twitter.token,config.twitter.tokenSecret)
+
 params =
 	qs:
 		api_key:config.key
 	url : 'http://realtime.mbta.com/developer/api/v1/alerts'
 	json:true

-dcb = (err)->
+defaultCallback = (err)->
 	console.log(err) if err

 cleanForTweet=(msg)->
@@ -18,11 +20,11 @@
 	msg = msg+' #mbta'
 	msg.replace /\b\w+?\b Line/g,(a)->
 		'#'+a.replace(/\ /,"")
+	msg

-tweet = (msg,cb=dcb)->
+tweet = (msg,cb=defaultCallback)->
 	twitter.post('statuses/update',{status:cleanForTweet(msg)},cb)

-i = 0
 eachAlert = (v)->
 	v['_id']=v['alert_id'].toString()
 	nParams =
@@ -31,19 +33,19 @@
 	request nParams,(e,r,b)->
 		if r.statusCode == 200
 			v._rev = b._rev
-			fcb = dcb
+			callback = defaultCallback
 		else
-			fcb = (e,r,b)->
+			callback = (e,r,b)->
 				if r.statusCode == 201
 					console.log 'tweeting ',v.header_text
 					tweet v.header_text
 		nParams.method='put'
 		nParams.body=v
-		request nParams,fcb
+		request nParams,callback
 		true
 	true

-lastHash = 1
+lastHash = false

 dumbCache = (alerts,cb)->
 	hash = crypto.createHash 'sha512'
@@ -52,6 +54,9 @@
 	unless lastHash == newHash
 		lastHash=newHash
 		cb alerts
+	true
+
+i = 0

 start = ()->
 	console.log 'run number #', ++i
@@ -64,10 +69,5 @@
 		true
 	true

-
-
-
 start()
 timer=setInterval(start,60000)
-
-


added missing token status controls to passwordrecovery@validate

--- workers/social/lib/social/models/passwordrecovery.coffee
+++ workers/social/lib/social/models/passwordrecovery.coffee
@@ -155,11 +155,14 @@
     @one {token}, (err, certificate)->
       return callback err  if err

-      unless certificate
+      if not certificate or (certificate?.status is 'invalidated')
         return callback { message: 'Invalid token.', short: 'invalid_token' }

       if certificate.status is 'redeemed'
         return callback { message: 'Already redeemed', short: 'redeemed_token' }
+
+      if certificate.status is 'expired'
+        return callback { message: 'The token has expired.', short: 'expired_token' }

       if certificate.getAt('expiresAt') < new Date
         certificate.expire (err)->


add port to log

add port to log

--- server/app.coffee
+++ server/app.coffee
@@ -156,6 +156,6 @@
 port = process.env.PORT | 3000

 http.createServer(app).listen port, () ->
-    console.log 'server waiting for requests...'
+    console.log 'server waiting for requests...', port

 module.exports = app


job status check

job status check

--- server/job.coffee
+++ server/job.coffee
@@ -605,7 +605,11 @@
       cluster: job_result.terms('_cid')
   res.limits = {} # may not be worth reporting on limit index in new structure
   job_limit.each 'NOT last:*', (lm) -> res.limits[lm.group ? lm._id] = {date:lm.created_date,limit:lm.limit}
-  job_job.each 'NOT done:true', {_source:['count','processed']}, (j) -> res.jobs.waiting += (j.count - (j.processed ? 0))
+  job_job.each 'NOT done:true', {_source:['count','processed']}, (j) ->
+    console.log j
+    console.log (j.count - (j.processed ? 0))
+    res.jobs.waiting += (j.count - (j.processed ? 0))
+    console.log res.jobs.waiting
   return res

 API.job.orphans = (remove=false,types=['process','result']) ->


make it better

make it better


Fix java version

Fix java version

--- actions/java.coffee
+++ actions/java.coffee
@@ -54,8 +54,9 @@
     stdout = '' if err
     installed_version = stdout.trim().split('\n').pop()
     if installed_version
-      installed_version = /jdk(.*)/.exec(installed_version)[1].replace('_', '')
-      version = version.replace('_', '')
+      installed_version = /jdk(.*)/.exec(installed_version)[1]
+      installed_version = installed_version.replace('_', '').replace('0', '')
+      version = version.replace('_', '').replace('0', '')
       unless semver.gt version, installed_version
         return next null, ctx.PASS
     action = if url.parse(location).protocol is 'http:' then 'download' else 'upload'


Use native api to avoid `$` operators

Use native api to avoid `$` operators

--- lib/transient-emacs.coffee
+++ lib/transient-emacs.coffee
@@ -1,5 +1,5 @@
 {Range,Pane} = require 'atom'
-{$,$$} = require 'space-pen'
+{$$} = require 'space-pen'
 _ = require 'underscore-plus'
 KillRing = require './kill-ring'
 DOMListener = require 'dom-listener'
@@ -37,13 +37,12 @@
       'emacs:backspace': => return @backspace()

     addEditorEventListner = (editor) =>
-      editorView = $(atom.views.getView(editor))
       @eventListeners.push editor.onDidChangeCursorPosition (e)=>
         @killring?.seal() if @isUserCommand
         @deactivateISearch() if @isUserCommand
-        editorView.removeClass "transient-marked"
       listener = new DOMListener(atom.views.getView(editor))
       @eventListeners.push listener.add 'atom-text-editor', 'click', (e)->
+        (atom.views.getView editor).classList.remove("transient-marked")

     atom.workspace.getTextEditors().forEach addEditorEventListner
     @addTextEditorListener = atom.workspace.onDidAddTextEditor (event) ->
@@ -121,8 +120,7 @@

   activateIsearch: (forward)->
     editor = atom.workspace.getActiveTextEditor()
-    editorView = atom.views.getView editor
-    $(editorView).addClass "searching"
+    (atom.views.getView editor).classList.add "searching"
     @isforward = forward
     @isearchWord = @isearchLast if @isearchTile? and not @isearchWord
     @searchNext @isearchWord
@@ -134,8 +132,7 @@
       @isearchLast = @isearchWord
       @isearchWord = ""
       editor = atom.workspace.getActiveTextEditor()
-      editorView = atom.views.getView editor
-      $(editorView).removeClass "searching"
+      (atom.views.getView editor).classList.remove "searching"
       return true

   updateStatusbar: (word,found)->
@@ -205,8 +202,7 @@
   setMark: ->
     editor = @getEditor()
     return unless editor
-    editorView = atom.views.getView editor
-    $(editorView).toggleClass "transient-marked"
+    (atom.views.getView editor).classList.toggle "transient-marked"
     cursor.clearSelection() for cursor in editor.getCursors()

   killRegionOrBackwardWord: ->
@@ -218,8 +214,7 @@
       @killRegion()

   pushRegeonToKillring: (editor) ->
-    editorView = atom.views.getView editor
-    $(editorView).removeClass "transient-marked"
+    (atom.views.getView editor).classList.remove "transient-marked"
     texts = (s.getText() for s in editor.getSelections())
     @killring.push texts
     @killring.seal()


Use correct type from data layer

Use correct type from data layer

--- src/main/assets/javascripts/simple.coffee
+++ src/main/assets/javascripts/simple.coffee
@@ -26,7 +26,7 @@
     $('div.message[data-type="YOU"]').fadeIn('fast')

 addFeedItem = (time_diff, map, v) ->
-  html = "

+  html = "

#{time_diff}

#{v.title}


remove dead filter code

remove dead filter code

--- app/assets/javascripts/admin/bulk_product_update.js.coffee
+++ app/assets/javascripts/admin/bulk_product_update.js.coffee
@@ -13,7 +13,6 @@
     {id: 100, name: t('js.admin.orders.index.per_page', results: 100)}
   ]

-  productFilters = ['producerFilter', 'categoryFilter', 'query', 'sorting', 'importDateFilter']
   $scope.q = {
     producerFilter: ""
     categoryFilter: ""
@@ -42,13 +41,6 @@
   $scope.changePage = (newPage) ->
     $scope.page = newPage
     $scope.fetchProducts()
-
-  generateFilter = ->
-    filters = {}
-    for filter in productFilters
-      filters[filter] = $scope[filter] if $scope[filter]
-
-    filters

   $scope.fetchProducts = ->
     removeClearedValues()


Messages#show - Fix js error being thrown when clicking on 'Overview' or 'Inspect' tab header

--- app/assets/javascripts/admin/views/messages/show.js.coffee
+++ app/assets/javascripts/admin/views/messages/show.js.coffee
@@ -9,5 +9,6 @@

   showSubView: (e) ->
     templateName = $(e.currentTarget).data('template')
-    @$el.find('#detail-view').html JST["admin/templates/messages/_#{templateName}"](model: @model)
+    if templateName?
+      @$el.find('#detail-view').html JST["admin/templates/messages/_#{templateName}"](model: @model)
 )


Make alvin happy.

Make alvin happy.


Added comment to make regex use clearer

Added comment to make regex use clearer

--- app/assets/javascripts/lib/forms/input_validator.js.coffee
+++ app/assets/javascripts/lib/forms/input_validator.js.coffee
@@ -15,6 +15,7 @@
       "#{@_replace(ErrorMessages[@name], @args)} #{@label}"

     _initialize: ->
+      # check for validation rules that have parameters and split them up, e.g. min(3)
       if match = @validator.match(/(.+)\((.+)\)/)
         @name = match[1]
         @args = match[2]


Cleanup DueDateOverride.coffee a bit

Cleanup DueDateOverride.coffee a bit

Refs: SIS-2715

Test Plan: QA will review the functionality in the final commit.

Change-Id: Ib7e5a5f0b2207005797b0e5e5f45299178a12e85
Reviewed-on: https://gerrit.instructure.com/103030
Tested-by: Jenkins
Reviewed-by: Nick Houle <972e9d73d0c431cb094492b619fbc612b5441e91@instructure.com>
Product-Review: Stewie aka Nicholas Stewart <bec99285d8f1953757afca2af84365b0776c1eb4@instructure.com>
QA-Review: Stewie aka Nicholas Stewart <bec99285d8f1953757afca2af84365b0776c1eb4@instructure.com>

--- app/coffeescripts/views/assignments/DueDateOverride.coffee
+++ app/coffeescripts/views/assignments/DueDateOverride.coffee
@@ -11,11 +11,23 @@
   'jsx/due_dates/StudentGroupStore'
   'compiled/api/gradingPeriodsApi'
   'timezone'
-], ($, Backbone, _, React, ReactDOM, template, DateValidator, I18n, DueDates, StudentGroupStore, GradingPeriodsAPI, tz) ->
+], (
+  $,
+  Backbone,
+  _,
+  React,
+  ReactDOM,
+  DueDateOverride,
+  DateValidator,
+  I18n,
+  DueDates,
+  StudentGroupStore,
+  GradingPeriodsAPI,
+  tz) ->

   class DueDateOverrideView extends Backbone.View

-    template: template
+    template: DueDateOverride

     # =================
     #   ui interaction


JAccount: Don't log errors if not needed

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -666,7 +666,7 @@
                   "sent-hil", "kiwigeraint", "cihangirsavas", "leventyalcin" ]

   userIsExempt: (callback)->
-    console.log @isExempt, this
+    # console.log @isExempt, this
     callback null, @isExempt

   # returns troll users ids
@@ -937,7 +937,7 @@
       return callback new KodingError "Attempt to remove unauthorized storage"

     @fetchStorage { 'data.name' : name }, (err, storage)=>
-      console.log err, storage
+      console.error err, storage  if err
       return callback err  if err
       unless storage
         return callback new KodingError "No such storage"


removed unused methods

removed unused methods

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -95,8 +95,6 @@
           (signature String, Function)
         fetchBlockedUsers:
           (signature Object, Function)
-        fetchCachedUserCount:
-          (signature Function)

       instance:
         modify:
@@ -108,14 +106,8 @@
         unfollow: [
           (signature Function)
         ]
-        fetchTopics:
-          (signature Object, Object, Function)
         fetchAppStorage:
           (signature Object, Function)
-        addTags: [
-          (signature Object, Function)
-          (signature Object, Object, Function)
-        ]
         setEmailPreferences:
           (signature Object, Function)
         fetchRole:
@@ -484,14 +476,6 @@

   @renderHomepage: require '../render/profile.coffee'

-  @fetchCachedUserCount: (callback)->
-    if (Date.now() - @lastUserCountFetchTime)/1000 < 60
-      return callback null, @cachedUserCount
-    JAccount.count type:'registered', (err, count)=>
-      return callback err if err
-      @lastUserCountFetchTime = Date.now()
-      @cachedUserCount = count
-      callback null, count

   fetchHomepageView:(options, callback)->
     {account} = options
@@ -903,20 +887,6 @@

   getPrivateChannelName:-> "private-#{@getAt('pro file.nickname')}-private"

-  fetchTopics: secure (client, query, page, callback)->
-    query       =
-      targetId  : @getId()
-      as        : 'follower'
-      sourceName: 'JTag'
-    Relationship.some query, page, (err, docs)->
-      if err then callback err
-      else
-        {group} = client.context
-        ids = (rel.sourceId for rel in docs)
-        selector = _id: $in: ids
-        selector.group = group if group isnt 'koding'
-        JTag.all selector, (err, tags)->
-          callback err, tags

   modify: secure (client, fields, callback) ->

@@ -1217,11 +1187,6 @@

       group.fetchMyRoles client, kallback

-  oldAddTags = @::addTags
-  addTags: secure (client, tags, options, callback)->
-    client.context.group = 'koding'
-    oldAddTags.call this, client, tags, options, callback
-
   ## NEWER IMPLEMENATION: Fetch ids from graph db, get items from document db.

   unlinkOauth: secure (client, provider, callback)->


workers: minor changes to call end point

--- workers/social/lib/social/models/payment.coffee
+++ workers/social/lib/social/models/payment.coffee
@@ -153,17 +153,10 @@

     return callback new KodingError 'No such group'  unless group

-    if group.slug is 'koding' or KONFIG.environment is 'default'
-      return callback null, { planTitle: 'unlimited' }
-
-    url = "#{socialProxyUrl}/payments/group/invoices?group_id=#{group._id}"
-    get url, {}, (err, subscription) ->
-      return callback err  if err
-
-      # unless isSubscriptionOk group, subscription
-      #   return callback new KodingError 'Trial period exceeded'
-
-      callback null, sanitizeSubscription subscription
+    data = { groupId: group._id }
+
+    url = "#{socialProxyUrl}/payments/group/invoices/#{data.groupId}"
+    get url, data, callback

   @fetchGroupInvoices$ = secure (client, callback) ->


Assign default event action properties

Assign default event action properties

--- workers/social/lib/social/models/tracker.coffee
+++ workers/social/lib/social/models/tracker.coffee
@@ -3,6 +3,8 @@
 { secure, signature } = bongo

 { argv } = require 'optimist'
+
+_ = require 'lodash'

 KONFIG        = require('koding-config-manager').load("main.#{argv.c}")
 { socialapi } = KONFIG
@@ -42,6 +44,8 @@
     INVITED_CREATE_TEAM  : 'was invited to create a team'
     SENT_FEEDBACK        : 'sent feedback'

+  @properties = {}
+

   @identifyAndTrack = (username, event, eventProperties = {}) ->
     @identify username
@@ -75,6 +79,8 @@

   @track = (username, event, options = {}) ->
+    _.extend options, @properties[event.subject]
+
     # use `forcedRecipient` for both username and email
     if forcedRecipient
       username = forcedRecipient


Migrate fs.traverseTree to use Node's fs

--- src/stdlib/fs.coffee
+++ src/stdlib/fs.coffee
@@ -121,7 +121,20 @@
     $native.getAllFilePathsAsync(rootPath, callback)

   traverseTree: (rootPath, onFile, onDirectory) ->
-    $native.traverseTree(rootPath, onFile, onDirectory)
+    return unless nodeFs.existsSync(rootPath) and nodeFs.statSync(rootPath).isDirectory()
+
+    traverse = (rootPath, prefix, onFile, onDirectory) =>
+      prefix  = "#{prefix}/" if prefix
+      for file in nodeFs.readdirSync(rootPath)
+        relativePath = "#{prefix}#{file}"
+        absolutePath = @join(rootPath, file)
+        stats = nodeFs.statSync(absolutePath)
+        if stats.isDirectory()
+          traverse(absolutePath, relativePath, onFile, onDirectory) if onDirectory(relativePath)
+        else if stats.isFile()
+          onFile(relativePath)
+
+    traverse(rootPath, '', onFile, onDirectory)

   lastModified: (path) ->
     $native.lastModified(path)


Code tidy: Move listen event with other listeners

--- vendor/assets/javascripts/progressive_render.js.coffee
+++ vendor/assets/javascripts/progressive_render.js.coffee
@@ -6,6 +6,7 @@
 setup_listener = ->
   $(document).on 'progressive_render:end', load_missing_content
   $(document).on 'ajax:end', load_missing_content
+  $(document).on 'turbolinks:load', load_missing_content if window.Turbolinks

 load_missing_content = ->
   $('[data-progressive-render-placeholder=true]').each ->
@@ -18,5 +19,3 @@
     $.ajax url: $this.data('progressive-render-path'), cache: false, success: (response) ->
       $this.html(response);
       $(document).trigger('progressive_render:end')
-
-  $(document).on 'turbolinks:load', load_missing_content if window.Turbolinks


Configure atom

Configure atom

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,10 +1,11 @@
 "*":
   editor:
     showIndentGuide: true
-    fontFamily: "Menlo"
+    fontFamily: "Ubuntu Mono"
     invisibles: {}
-    fontSize: 15
     softWrapAtPreferredLineLength: true
+    fontSize: 10
+    preferredLineLength: 100
   core:
     ignoredNames: [
       ".bundle"
@@ -14,16 +15,14 @@
       "tmp"
       "vendor"
     ]
-    themes: [
-      "unity-ui"
-      "glacier-syntax"
-    ]
     hideGitIgnoredFiles: true
     disabledPackages: [
       "background-tips"
       "exception-reporting"
       "metrics"
     ]
+    autoHideMenuBar: true
+    projectHome: "/home/alex/code"
   "spell-check":
     grammars: [
       "text.plain"
@@ -34,3 +33,17 @@
     showOnStartup: false
   "release-notes":
     viewedVersion: "0.89.0"
+  minimap:
+    plugins:
+      "highlight-selected": true
+  "one-dark-ui":
+    fontSize: 8
+    layoutMode: "Compact"
+  jshint:
+    validateOnlyOnSave: true
+  linter:
+    showErrorTabLine: true
+    showErrorPanel: false
+  "atom-beautify":
+    _analyticsUserId: "6300169d-c83f-4585-80a9-fde53a8f5b25"
+  "tree-view": {}


bump atom config

bump atom config

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,34 +1,35 @@
-'editor':
-  'showIndentGuide': true
-  'fontFamily': 'Menlo'
-  'fontSize': 15
-  'invisibles': {}
-'core':
-  'ignoredNames': [
-    '.bundle'
-    '.git'
-    'log'
-    'repositories'
-    'tmp'
-    'vendor'
-  ]
-  'themes': [
-    'unity-ui'
-    'glacier-syntax'
-  ]
-  'hideGitIgnoredFiles': true
-  'disabledPackages': [
-    'background-tips'
-    'exception-reporting'
-    'metrics'
-  ]
-'spell-check':
-  'grammars': [
-    'text.plain'
-    'source.gfm'
-    'text.git-commit'
-  ]
-'welcome':
-  'showOnStartup': false
-'release-notes':
-  'viewedVersion': '0.89.0'
+'global':
+  'editor':
+    'showIndentGuide': true
+    'fontFamily': 'Menlo'
+    'fontSize': 15
+  'core':
+    'ignoredNames': [
+      '.bundle'
+      '.git'
+      'log'
+      'repositories'
+      'tmp'
+      'vendor'
+    ]
+    'themes': [
+      'unity-ui'
+      'glacier-syntax'
+    ]
+    'hideGitIgnoredFiles': true
+    'disabledPackages': [
+      'background-tips'
+      'exception-reporting'
+      'metrics'
+    ]
+  'spell-check':
+    'grammars': [
+      'text.plain'
+      'source.gfm'
+      'text.git-commit'
+    ]
+  'welcome':
+    'showOnStartup': false
+  'release-notes':
+    'viewedVersion': '0.89.0'
+  'go-plus': {}


Atom config updates

Atom config updates

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -1,4 +1,13 @@
 "*":
+<<<<<<< 14d6e7c8dc12556ee2aab81c81696ca8d662f2eb
+=======
+  editor:
+    showIndentGuide: true
+    fontFamily: "Menlo"
+    invisibles: {}
+    softWrapAtPreferredLineLength: true
+    fontSize: 15
+>>>>>>> Atom config updates
   core:
     disabledPackages: [
       "background-tips"
@@ -41,5 +50,11 @@
     ]
   tabs:
     usePreviewTabs: true
+<<<<<<< 14d6e7c8dc12556ee2aab81c81696ca8d662f2eb
   welcome:
     showOnStartup: false
+=======
+  "atom-beautify":
+    analytics: false
+    _analyticsUserId: "XXX"
+>>>>>>> Atom config updates


atom config bump

atom config bump

--- atom.symlink/config.cson
+++ atom.symlink/config.cson
@@ -3,6 +3,7 @@
     'showIndentGuide': true
     'fontFamily': 'Menlo'
     'fontSize': 15
+    'invisibles': {}
   'core':
     'ignoredNames': [
       '.bundle'
@@ -32,4 +33,3 @@
     'showOnStartup': false
   'release-notes':
     'viewedVersion': '0.89.0'
-  'go-plus': {}


Removed Subscription add from non disposables

--- lib/codekit-commands.coffee
+++ lib/codekit-commands.coffee
@@ -1,91 +1,93 @@
 applescript = require('../inc/node-applescript/applescript');
 $ = require('../inc/jquery-2.1.4.min.js');
-{CompositeDisposable} = require 'atom'
+{Disposable, CompositeDisposable} = require 'atom'

 module.exports =
-  config:
-    autoPause:
-      title: 'Auto Pause Codekit Filewatching'
-      description: 'Auto pause/unpause Codekit file watching when Atom window is/isn\'t in focus'
-      type: 'boolean'
-      default: true
-    autoStart:
-      title: 'Auto Start Codekit'
-      description: 'Auto start Codekit when Atom window is opened'
-      type: 'boolean'
-      default: true
-    autoQuit:
-      title: 'Auto Quit Codekit'
-      description: 'Auto quit Codekit when Atom window is closed'
-      type: 'boolean'
-      default: true
-    autoSwitch:
-      title: 'Auto Switch Codekit Project'
-      description: 'Auto switch Codekit project on file change'
-      type: 'boolean'
-      default: true
+	config:
+		autoPause:
+			title: 'Auto Pause Codekit Filewatching'
+			description: 'Auto pause/unpause Codekit file watching when Atom window is/isn\'t in focus'
+			type: 'boolean'
+			default: true
+		autoStart:
+			title: 'Auto Start Codekit'
+			description: 'Auto start Codekit when Atom window is opened'
+			type: 'boolean'
+			default: true
+		autoQuit:
+			title: 'Auto Quit Codekit'
+			description: 'Auto quit Codekit when Atom window is closed'
+			type: 'boolean'
+			default: true
+		autoSwitch:
+			title: 'Auto Switch Codekit Project'
+			description: 'Auto switch Codekit project on file change'
+			type: 'boolean'
+			default: true

-  subscriptions: null
+	subscriptions: null

-  activate: ->
-    @startCodekit()
-    @subscriptions = new CompositeDisposable
-    @subscriptions.add atom.commands.add 'atom-workspace', 'codekit-commands:previewProject': => @previewProject()
-    @subscriptions.add atom.commands.add 'atom-workspace', 'codekit-commands:refreshProject': => @refreshProject()
-    @subscriptions.add atom.commands.add '.project-root > .header', 'codekit-commands:addProject': => @addProject()
-    @subscriptions.add atom.workspace.onDidChangeActivePaneItem (callback) => @autoSwitchProject(callback)
-    @subscriptions.add $(window).on 'load', => @startCodekit()
-    @subscriptions.add $(window).on 'unload', => @quitCodekit()
-    @subscriptions.add $(window).on 'blur', => @pauseProject()
-    @subscriptions.add $(window).on 'focus', => @unpauseProject()
+	activate: ->
+		@subscriptions = new CompositeDisposable
+		@subscriptions.add atom.commands.add 'atom-workspace', 'codekit-commands:previewProject': => @previewProject()
+		@subscriptions.add atom.commands.add 'atom-workspace', 'codekit-commands:refreshProject': => @refreshProject()
+		@subscriptions.add atom.commands.add '.project-root > .header', 'codekit-commands:addProject': => @addProject()
+		@subscriptions.add atom.workspace.onDidChangeActivePaneItem (callback) => @autoSwitchProject(callback)
+		$(window).on 'load', => @startCodekit()
+		$(window).on 'unload', => @quitCodekit()
+		$(window).on 'blur', => @pauseProject()
+		$(window).on 'focus', => @unpauseProject()

-  deactivate: ->
-    @subscriptions.dispose()
+		@startCodekit()

-  startCodekit: ->
-    if atom.config.get('codekit-commands.autoStart')
-      @switchProject(atom.workspace.getActivePaneItem())
-      script = 'tell application "CodeKit" to launch'
-      applescript.execString(script)
+	startCodekit: ->
+		if atom.config.get('codekit-commands.autoStart')
+			@switchProject(atom.workspace.getActivePaneItem())
+			script = 'tell application "CodeKit" to launch'
+			applescript.execString(script)

-  quitCodekit: ->
-    if atom.config.get('codekit-commands.autoQuit')
-      script = 'tell application "CodeKit" to quit'
-      applescript.execString(script)
+	quitCodekit: ->
+		if atom.config.get('codekit-commands.autoQuit')
+			script = 'tell application "CodeKit" to quit'
+			applescript.execString(script)

-  previewProject: ->
-    script = 'tell application \"CodeKit\" to preview in browser'
-    applescript.execString(script)
+	previewProject: ->
+		@switchProject(atom.workspace.getActivePaneItem())
+		script = 'tell application \"CodeKit\" to preview in browser'
+		applescript.execString(script)

-  refreshProject: ->
-    @switchProject(atom.workspace.getActivePaneItem())
-    script = 'tell application \"CodeKit\" to refresh browsers'
-    applescript.execString(script)
+	refreshProject: ->
+		@switchProject(atom.workspace.getActivePaneItem())
+		script = 'tell application \"CodeKit\" to refresh browsers'
+		applescript.execString(script)

-  addProject: ->
-    treeView = atom.packages.getLoadedPackage('tree-view');
-    treeView = require(treeView.mainModulePath);
-    packageObj = treeView.serialize();
-    script = "tell application \"CodeKit\" to add project at path \"#{packageObj.selectedPath}\""
-    applescript.execString(script)
+	addProject: ->
+		treeView = atom.packages.getLoadedPackage('tree-view');
+		treeView = require(treeView.mainModulePath);
+		packageObj = treeView.serialize();
+		script = "tell application \"CodeKit\" to add project at path \"#{packageObj.selectedPath}\""
+		applescript.execString(script)

-  switchProject: (newPanel) ->
-    if newPanel
-      if newPanel.buffer
-        if newPanel.buffer.file
-          script = "tell application \"CodeKit\" to select project containing path \"#{newPanel.buffer.file.path}\""
-          applescript.execString(script)
+	switchProject: (newPanel) ->
+		if newPanel
+			if newPanel.buffer
+				if newPanel.buffer.file
+					script = "tell application \"CodeKit\" to select project containing path \"#{newPanel.buffer.file.path}\""
+					applescript.execString(script)

-  autoSwitchProject: (newPanel) ->
-    if atom.config.get('codekit-commands.autoSwitch')
-      @switchProject(newPanel)
+	autoSwitchProject: (newPanel) ->
+		if atom.config.get('codekit-commands.autoSwitch')
+			@switchProject(newPanel)

-  pauseProject: ->
-    if atom.config.get('codekit-commands.autoPause')
-      script = "tell application \"CodeKit\" to pause file watching"
-      applescript.execString(script)
+	pauseProject: ->
+		if atom.config.get('codekit-commands.autoPause')
+			script = "tell application \"CodeKit\" to pause file watching"
+			applescript.execString(script)

-  unpauseProject: ->
-    if atom.config.get('codekit-commands.autoPause')
-      script = "tell application \"CodeKit\" to unpause file watching"
-      applescript.execString(script)
+	unpauseProject: ->
+		if atom.config.get('codekit-commands.autoPause')
+			script = "tell application \"CodeKit\" to unpause file watching"
+			applescript.execString(script)
+
+	deactivate: ->
+		@subscriptions.dispose()


+ clone, create to Value class * [bug] Type.clone should clone type

--- src/type-info.coffee
+++ src/type-info.coffee
@@ -52,6 +52,9 @@
       @$type.validate(aValue, checkValidity) if checkValidity isnt false
       @_assign aValue
     return @
+  create: (aValue, aOptions)->
+    @$type.createValue aValue, aOptions
+  clone: @::create
   toString: ->String(@value)
   valueOf: ->@value
   toObject: (aOptions)->
@@ -165,12 +168,13 @@
   isValid: (aValue) ->
     @validate(aValue, false)
   createValue: (aValue, aOptions)->
-    aOptions = @mergeOptions(aOptions)
-    #aOptions.name = @name unless aOptions.name
-    vType = createObject @Class, aOptions
+    if aOptions
+      aOptions = @mergeOptions(aOptions)
+      vType = createObject @Class, aOptions
+    else
+      vType = @
     Value aValue, vType
   create: @::createValue
-  clone: (aOptions)->@create(null, aOptions)
   createType: (aOptions)->
     delete aOptions.value if aOptions
     createObject @Class, aOptions
@@ -178,6 +182,7 @@
     aOptions = @mergeOptions(aOptions)
     aOptions.name = @name unless aOptions.name
     @createType aOptions
+  clone: @::cloneType
   # Get aType class from the encoded string.
   fromString: (aString, aOptions)->
     aString = @encoding.decode aString, aOptions if @encoding
@@ -222,5 +227,3 @@
         else
           result.value = value
     result
-
-


set `-webkit-transform` after `transform`

--- src/ui/canvas.coffee
+++ src/ui/canvas.coffee
@@ -113,8 +113,8 @@
       trZoom[1] - map.trBase[1] * scDelta + (scDelta - 1) * map.height / 2
     ]
     transform = "translate3d(#{trDelta[0]}px,#{trDelta[1]}px,0px) scale(#{scDelta})"
+    backLayer.attr('style',         "transform: #{transform}")
     backLayer.attr('style', "-webkit-transform: #{transform}")
-    backLayer.attr('style',         "transform: #{transform}")

   map.centerAt = (pos, new_sc) ->
     updateProjection(new_sc, [0, 0])


include projection as stream

include projection as stream

--- src/ui/canvas.coffee
+++ src/ui/canvas.coffee
@@ -28,14 +28,13 @@
   simplify = d3.geo.transform(
     point: (x, y, z) ->
       if z? and z >= f0 / map.sc / 300
-        [a, b] = projection([x, y])
-        return @stream.point(a, b)
+        return @stream.point(x, y)
   )

   clip = d3.geo.clipExtent()

   map.path = d3.geo.path()
-      .projection(stream: (s) -> simplify.stream(clip.stream(s)))
+      .projection(stream: (s) -> simplify.stream(projection.stream(clip.stream(s))))

   svg = d3.select('body').append('svg')


little improvements

little improvements

--- core/KDWindowController.coffee
+++ core/KDWindowController.coffee
@@ -81,7 +81,7 @@
     , yes

     document.body.addEventListener 'mousemove', (e)=>
-      @redirectMouseMoveEvent e
+      @redirectMouseMoveEvent e if @dragView
     , yes

     # unless window.location.hostname is 'localhost'
@@ -137,7 +137,6 @@
   redirectMouseMoveEvent:(event)->

     view = @dragView
-    return unless @dragView

     {pageX, pageY}   = event
     {startX, startY} = view.dragState


fixing indentation

fixing indentation

--- src/scripts/models/contents/node.coffee
+++ src/scripts/models/contents/node.coffee
@@ -238,6 +238,6 @@
     getAbstractForOpenGraph: () ->
       abstract = @getAbstract()
       if abstract isnt null and abstract isnt undefined
-       return abstract.replace(/(<([^>]+)>)/ig,'')
-      else
-       return 'An OpenStax College book'
+        return abstract.replace(/(<([^>]+)>)/ig,'')
+      else
+        return 'An OpenStax College book'


Fix for keyboard event 'this' value.

Fix for keyboard event 'this' value.

--- src/server/browser/jsdom_patches.coffee
+++ src/server/browser/jsdom_patches.coffee
@@ -116,7 +116,7 @@
         @locale   = null

         # Set up getters/setters for keys that are properties.
-        ['ctrlKey', 'shiftKey', 'altKey', 'metaKey'].forEach (key) ->
+        ['ctrlKey', 'shiftKey', 'altKey', 'metaKey'].forEach (key) =>
             prop = "_#{key}"
             this[prop] = false
             # TODO: put these on proto


naming

naming

--- src/util/spec.coffee
+++ src/util/spec.coffee
@@ -12,13 +12,13 @@
 ###
 MIXINS =

-  DEFAULT_FREEZE: false
+  FREEZE: false

   schematized_protomixin: (schema = ['special_key']) ->
     mixin = Mixin.from_obj
       name: 'Schematized Example Mixin'
       foo: 'bar'
-      , @DEFAULT_FREEZE
+      , @FREEZE
     mixin.premixing_hook = ->
       for key in schema || ['special_key';]
         unless @[key]?
@@ -32,7 +32,7 @@
       bar: 1
       baz: ->
         [@foo]
-      , @DEFAULT_FREEZE
+      , @FREEZE
     mixin.postmixing_hook = ->
       @modified_proto = true
     mixin


add support for dashed scenarios

add support for dashed scenarios

--- hubot/fleet.coffee
+++ hubot/fleet.coffee
@@ -47,7 +47,7 @@

   fleet_url = process.env.HUBOT_FLEET_URL

-  robot.respond /fleet me (\w+)( to (\w+))?( with (.*))?/i, (msg) ->
+  robot.respond /fleet me (\S+)( to (\S+))?( with (.*))?/i, (msg) ->

     scenario = msg.match[1]
     args = []


Fix destroy

Fix destroy

--- client/apps/edit/components/section_container/index.coffee
+++ client/apps/edit/components/section_container/index.coffee
@@ -23,6 +23,8 @@
   onClickOff: ->
     @setEditing(off)()
     @refs.section?.onClickOff?()
+    if @props.section.get('type') is 'image_set'
+      @props.section.destroy() if @props.section.get('images').length is 0

   componentDidMount: ->
     @props.section.on 'change:layout', => @forceUpdate()


remove tests

remove tests

--- client/apps/edit/components/section_tool/test/index.coffee
+++ client/apps/edit/components/section_tool/test/index.coffee
@@ -45,24 +45,6 @@
     @component.props.sections.last().get('type').should.equal 'text'
     @component.props.sections.last().get('body').should.equal ''

-  it 'does not show a callout section if there is not a text section below it', ->
-    r.simulate.click r.find @component, 'edit-section-tool-icon'
-    (r.findAll @component, 'edit-section-tool-callout')[0].props.className.should.containEql 'is-disabled'
-    React.renderToString(@SectionTool(
-        sections: @sections = new Backbone.Collection [
-          { body: 'Foo to the bar', type: 'text' }
-        ]
-        index: 0
-    )).should.containEql 'edit-section-tool-callout is-disabled'
-
-  it 'shows a callout section if there is a text section below it', ->
-    React.renderToString(@SectionTool(
-        sections: @sections = new Backbone.Collection [
-          { body: 'Foo to the bar', type: 'text' }
-        ]
-        index: -1
-    )).should.containEql 'edit-section-tool-callout'
-
 describe 'SectionTool - Hero', ->

   beforeEach (done) ->


Change default hotkey

Change default hotkey

--- keymaps/livereload.cson
+++ keymaps/livereload.cson
@@ -7,5 +7,8 @@

 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
-'.workspace':
-  'cmd-shift-l': 'livereload:toggle'
+
+'.platform-darwin':
+  'ctrl-shift-R': 'livereload:toggle'
+'.platform-win32':
+  'ctrl-shift-R': 'livereload:toggle'


Corrected issue with Tree not showing network list info, Split Ratio and FD profile info.

--- src/main/webapp/lib/views/TreeView.coffee
+++ src/main/webapp/lib/views/TreeView.coffee
@@ -151,7 +151,8 @@
       targets = @_findTargetElements(e, params.attachId)
       if targets? and !(targets.length is 0)
         switch params.type
-          when 'link', 'node' then name = targets[0].road_names()
+          when 'link' then name = targets[0].link_name()
+          when 'node' then name = targets[0].name()
           else name = targets[0].get('name')

         # for OD Profiles
@@ -214,7 +215,7 @@
   _setUpTreeData: ->
     @parentNodes = [
         {
-          parentList: @scenario.get('networklist')
+          parentList: @scenario.get('networkset')
           modelListName: 'network'
           attachId: 'network-list'
           nameList: null
@@ -236,7 +237,7 @@
           attachId: 'controllers'
         },
         {
-          parentList: @scenario.get('demandprofileset')
+          parentList: @scenario.get('demandset')
           modelListName: 'demandprofile'
           attachId: 'demand-profiles'
         },
@@ -246,32 +247,32 @@
           attachId: 'events'
         },
         {
-          parentList: @scenario.get('fundamentaldiagramprofileset')
+          parentList: @scenario.get('fundamentaldiagramset')
           modelListName: 'fundamentaldiagramprofile'
           attachId: 'fundamental-diagram-profiles'
         },
         {
-          parentList: @scenario.get('oddemandprofileset')
+          parentList: @scenario.get('demandset')
           modelListName: 'oddemandprofile'
           attachId: 'od-demand-profiles'
         },
         {
-          parentList: @scenario.get('downstreamboundarycapacityprofileset')
+          parentList: @scenario.get('downstreamboundarycapacityset')
           modelListName: 'downstreamboundarycapacityprofile'
           attachId: 'downstream-boundary-profiles'
         },
         {
-          parentList: @scenario.get('splitratioprofileset')
+          parentList: @scenario.get('splitratioset')
           modelListName: 'splitratioprofile'
           attachId: 'split-ratio-profiles'
         },
         {
-          parentList: @scenario.get('sensorlist')
+          parentList: @scenario.get('sensorset')
           modelListName: 'sensor'
           attachId: 'sensors'
         },
         {
-          parentList: @scenario.get('signallist')
+          parentList: @scenario.get('signalset')
           modelListName: 'signal'
           attachId: 'signals'
         }


Some bad URL's and filenames fixed

Some bad URL's and filenames fixed

--- javascript/nota-init.coffee
+++ javascript/nota-init.coffee
@@ -17,8 +17,10 @@
     [ "../../bower_components/backbone/backbone.js"],
     [
       # Core needs Backbone
-      "../../javascript/invoice-core.js",
-      "../../javascript/invoice-view.js",
+      "../../javascript/nota-core.js",
+      "../../javascript/nota-view.js",
+      # Aerix template model and view logic
+      "javascript/invoice-view.js",
       "javascript/invoice-model.js"
     ]
   ]


Fix session importer.

Fix session importer.

IsDefault is now a proper boolean, it seems.

--- jobs/import-sessions.coffee
+++ jobs/import-sessions.coffee
@@ -10,7 +10,7 @@
 persistSession = (session, db, promise) ->
   sessionInstance =
     name: session.Description,
-    current: (session.IsDefault.toLowerCase() == "true"),
+    current: session.IsDefault,
     library: session.Library

   db.collection("sessions").update


Fixed typo bug

Fixed typo bug

--- bot.iced
+++ bot.iced
@@ -378,7 +378,7 @@
 			, 2000
 		, 2000
 bot.on "user", (userInfo) ->
-	await Users_collection.findOne {"id": userInfo.friendid}, (err, user) ->
+	await Users_collection.findOne {"id": userInfo.friendid}, defer(err, user)
 	return console.error err if err
 	return unless user
 	if user.name isnt userInfo.playerName


Keep VMS as array

Keep VMS as array

--- client/landing/app/MainApp/VirtualizationController.coffee
+++ client/landing/app/MainApp/VirtualizationController.coffee
@@ -67,19 +67,19 @@
           bundle.debitGroup defaultVMOptions, callback

   fetchVMs:(callback)->
-    return callback null, @vms  if @vms
+    return callback null, @vms  if @vms.length > 0
     KD.remote.api.JVM.fetchVms (err, vms)=>
       @vms = vms  unless err
       callback err, vms

   fetchGroupVMs:(callback)->
-    return callback null, @groupVms  if @groupVms
+    return callback null, @groupVms  if @groupVms.length > 0
     KD.remote.api.JVM.fetchVmsByContext (err, vms)=>
       @groupVms = vms  unless err
       callback err, vms

   resetVMData:->
-    @vms = @groupVms = null
+    @vms = @groupVms = []

   # fixme GG!
   fetchTotalVMCount:(callback)->


simplify graph bindToBrush

simplify graph bindToBrush

--- app/graphing.coffee
+++ app/graphing.coffee
@@ -20,6 +20,63 @@
       React.DOM.img {src: @props.url, style: {border: '1px solid #aaa'}}

 Graphing = modules.export exports, 'graphing', ({component_fn, doc, cmd, fn}) ->
+  doc 'shareCursor', 'Use the same cursor on multiple graphs',
+  '''
+  # Usage
+
+  ## `shareCursor()`
+
+  Sets the `cursor` option to a new cursor. This cursor will be used by all subsequent calls to [`graph`](help:graphing.graph).
+
+  ## `shareCursor(false)`
+
+  Unsets the `cursor` option.
+
+  ## `shareCursor(cursor)`
+
+  Sets the value of the `cursor` option to the specified cursor.
+  '''
+
+  cmd 'shareCursor', (ctx, share=true) ->
+    options = ctx.options()
+    if share == false
+      delete options.cursor
+    else
+      if share instanceof Bacon.Observable
+        options.cursor = share
+      else
+        options.cursor = new Bacon.Model
+
+  doc 'shareBrush', 'Use the same brush on multiple graphs',
+  '''
+  # Usage
+
+  ## `shareBrush()`
+
+  Sets the `brush` option to a new brush. This brush will be used by all subsequent calls to [`graph`](help:graphing.graph).
+
+  ## `shareBrush(false)`
+
+  Unsets the `brush` option.
+
+  ## `shareBrush(brush)`
+
+  Sets the value of the `brush` option to the specified brush.
+  '''
+
+  cmd 'shareBrush', (ctx, share=true) ->
+    options = ctx.options()
+    if share == false
+      delete options.brush
+    else
+      if share instanceof Bacon.Observable
+        options.brush = share
+      else
+        options.brush = new Bacon.Model
+
+  fn 'brushParams', (ctx, brush) ->
+    Context.value brushParams brush ? ctx.options().brush
+
   brushParams = (brush) ->
     brush.filter(({brushing}) -> !brushing).map ({extent}) ->
       if extent?
@@ -40,71 +97,12 @@

     Bacon.combineTemplate params

-
-
-  doc 'shareCursor', 'Use the same cursor on multiple graphs',
-  '''
-  # Usage
-
-  ## `shareCursor()`
-
-  Sets the `cursor` option to a new cursor. This cursor will be used by all subsequent calls to [`graph`](help:graphing.graph).
-
-  ## `shareCursor(false)`
-
-  Unsets the `cursor` option.
-
-  ## `shareCursor(cursor)`
-
-  Sets the value of the `cursor` option to the specified cursor.
-  '''
-
-  cmd 'shareCursor', (ctx, share=true) ->
-    options = ctx.options()
-    if share == false
-      delete options.cursor
-    else
-      if share instanceof Bacon.Observable
-        options.cursor = share
-      else
-        options.cursor = new Bacon.Model
-
-  doc 'shareBrush', 'Use the same brush on multiple graphs',
-  '''
-  # Usage
-
-  ## `shareBrush()`
-
-  Sets the `brush` option to a new brush. This brush will be used by all subsequent calls to [`graph`](help:graphing.graph).
-
-  ## `shareBrush(false)`
-
-  Unsets the `brush` option.
-
-  ## `shareBrush(brush)`
-
-  Sets the value of the `brush` option to the specified brush.
-  '''
-
-  cmd 'shareBrush', (ctx, share=true) ->
-    options = ctx.options()
-    if share == false
-      delete options.brush
-    else
-      if share instanceof Bacon.Observable
-        options.brush = share
-      else
-        options.brush = new Bacon.Model
-
-  fn 'brushParams', (ctx, brush) ->
-    Context.value brushParams brush ? ctx.options().brush
-
   bindToBrush = (brush, source) ->
-    serverParams = new Bacon.Model null
-    serverParams.addSource brushParams(brush)
-
-    serverParams.flatMapLatest (brushParams) ->
-      Bacon.fromPromise source.load brushParams
+    sourceParams = new Bacon.Model null
+    sourceParams.addSource brushParams(brush)
+
+    sourceParams.flatMapLatest (params) ->
+      Bacon.fromPromise(source.load(params))

   fn 'bindToBrush', (ctx, args...) ->
     if args[0] instanceof Server.LeadDataSource
@@ -112,14 +110,17 @@
       brush = args[1]?.brush ? ctx.options().brush
     else
       allParams = Server.args_to_params {args, default_options: ctx.options()}
-      source = new Server.LeadDataSource (brushParams) ->
-        Server.get_data _.extend {}, allParams.server, brushParams
+      source = serverDataSource(allParams.server)
       brush = allParams.client.brush
     Context.value bindToBrush brush, source

   doc 'graph',
     'Loads and graphs time-series data'
     Documentation.load_file 'graphing.graph'
+
+  serverDataSource = (serverParams) ->
+    new Server.LeadDataSource (params) ->
+      Server.get_data _.extend {}, serverParams, params

   component_fn 'graph', (ctx, args...) ->
     if Q.isPromise args[0]
@@ -131,30 +132,24 @@
     else if args[0] instanceof Bacon.Observable
       data = args[0]
       params = _.extend {}, ctx.options(), args[1]
-    else if args[0] instanceof Server.LeadDataSource
-      # TODO opentsdb won't like some of these params
-      params = _.extend {}, ctx.options(), args[1]
-      if params.bindToBrush == true
-        params.brush ?= new Bacon.Model
-        data = bindToBrush params.brush, args[0]
-      else if params.bindToBrush instanceof Bacon.Observable
-        data = bindToBrush params.bindToBrush, args[0]
-      else
-        promise = args[0].load params
-    else
-      all_params = Server.args_to_params {args, default_options: ctx.options()}
-      params = all_params.client
-      source = new Server.LeadDataSource (brushParams) ->
-        Server.get_data _.extend {}, all_params.server, brushParams
+    else
+      if args[0] instanceof Server.LeadDataSource
+        source = args[0]
+        # TODO opentsdb won't like some of these params
+        params = _.extend {}, ctx.options(), args[1]
+      else
+        all_params = Server.args_to_params {args, default_options: ctx.options()}
+        params = all_params.client
+        source = serverDataSource(all_params.server)
+
       if params.bindToBrush == true
         params.brush ?= new Bacon.Model
         data = bindToBrush params.brush, source
       else if params.bindToBrush instanceof Bacon.Observable
         data = bindToBrush params.bindToBrush, source
         params.brush ?= params.bindToBrush
-        delete params.bindToBrush
-      else
-        promise = Server.get_data all_params.server
+      else
+        promise = source.load params

     if promise
       data = Bacon.fromPromise(promise)


fix issue where app crashes when 'version' isn't in storage


no default weight in multiplication

no default weight in multiplication

--- src/algebra/algebra.coffee
+++ src/algebra/algebra.coffee
@@ -5,8 +5,6 @@
 Sphere = require '../core/sphere'

 class Algebra
-  @DEFAULT_WEIGHT = 1
-
   @multiply: (contentSphere, filterSphere) ->
     product = Sphere.copy contentSphere
     for __, contentEdge of contentSphere.edges
@@ -14,8 +12,7 @@
         if contentEdge.end.toJson(omit: 'id').toLowerCase() is filterEdge.end.toJson(omit: 'id').toLowerCase()
           weight = if isFinite(contentEdge.get('weight')) and isFinite(filterEdge.get('weight'))
             contentEdge.get('weight') * filterEdge.get('weight')
-          else
-            @DEFAULT_WEIGHT
+
           product.addEdge
             start: contentEdge.start
             end: filterEdge.start


cleanned up js

cleanned up js

--- source/javascripts/application.coffee
+++ source/javascripts/application.coffee
@@ -1,40 +1,4 @@
-#= require 'jquery'
-#= require 'jquery.cookie'
-#= require 'jquery.hidescroll'
-#= require 'bootstrap'
-#= require 'konami'
-#= require 'shake'
-#= require 'time-elements'
-#= require 'suncalc'
-#= require 'underscore'
-
-# COOKIE_KEY_THEME = 'ngs.io.theme'
-# $.cookie.json = yes
-# themeCookieOptions = expires: 30, path: '/'
-# themeCookieOptions.domain = '.ngs.io' if /^(?:ja\.)?ngs\.io$/.test document.location.hostname
-# themes = null
-
-# getDefaultTheme = ->
-#   date = new Date()
-#   {sunset, sunrise} = SunCalc.getTimes date, 35.6216798, 139.6993775
-#   defaultTheme = if date > sunrise and date < sunset
-#     cssCdn: "http://netdna.bootstrapcdn.com/bootswatch/latest/united/bootstrap.min.css"
-#     name: "United"
-#     preview: "http://bootswatch.com/united/"
-#     isDefault: yes
-#   else
-#     cssCdn: "http://netdna.bootstrapcdn.com/bootswatch/latest/darkly/bootstrap.min.css"
-#     name: "Darkly"
-#     preview: "http://bootswatch.com/darkly/"
-#     isDefault: yes
-
-# shakeEventDidOccur = (e)->
-#   if $.cookie(COOKIE_KEY_THEME) and confirm 'Reset style?'
-#     $.removeCookie COOKIE_KEY_THEME, themeCookieOptions
-#     document.location.reload()
-
-# change color scheme every hour
-
+# this script changes the stylesheet every hour.

 getStylesheet = ->
   currentTime = (new Date).getHours()
@@ -89,118 +53,4 @@
   # if 24 <= currentTime and currentTime < 25
   #   document.write '<link rel=\'stylesheet\' href=\'http://localhost:4567/stylesheets/c24.css\' type=\'text/css\'>'
   return
-
 getStylesheet()
-
-
-# handleFilterTagsKeyUp = (e)->
-#   input = $ e.target
-#   filterTags input.val()
-
-# filterTags = (text)->
-#   $('#sidebar-tags-list > li').each ->
-#     self = $ @
-#     if self.text().indexOf(text) == -1
-#       self.addClass 'hidden'
-#     else
-#       self.removeClass 'hidden'
-
-# setUpMixCloud = ->
-#   $('.mixcloud[data-embed-uuid]').each ->
-#     ele = $ @
-#     { embedUuid, feed } = ele.data()
-#     light = $('body').css('background-color') is 'rgb(255, 255, 255)'
-#     src = "https://www.mixcloud.com/widget/iframe/?feed=#{ encodeURIComponent feed }&embed_uuid=#{ embedUuid }&replace=0&light=#{light}&hide_cover=1&embed_type=widget_standard&hide_tracklist=1"
-#     ele.replaceWith $('').attr {src}
-
-# handleShowAllLink = (e)->
-#   $('#sidebar-tags-list > li').removeClass 'hidden'
-#   $('.show-all-tags-link').remove()
-
-# handleReadMoreLink = (e)->
-#   link = $ @
-#   link.button 'loading'
-#   href = link.attr 'href'
-#   $.get(href)
-#   .done (res)->
-#     res = $ res
-#     articleBody = link.parents('.entry').find('.article-body')
-#     title = res.find('title').text()
-#     content = res.find('[role=main] .article-body').html()
-#     articleBody.html content
-#     history.pushState null, title, href
-#     ga 'send', 'pageview', {
-#       page: "#{href}?inline=1"
-#       title: title
-#     }
-#     link.remove()
-#     setUpMixCloud()
-#   no
-
-# loadThemeDropDown = ->
-#   $.get('http://api.bootswatch.com/3/')
-#   .done (res)->
-#     ul = $('.bootswatch-theme-list').empty()
-#     appendItem ul, {
-#       cssCdn: '//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css'
-#       preview: 'http://bootswatch.com/default/'
-#       name: 'Default'
-#     }
-#     appendItem ul, data for data in res.themes
-#     appendItem ul, {
-#       cssCdn: '/stylesheets/bootstrap/bootstra386.css'
-#       preview: 'https://kristopolous.github.io/BOOTSTRA.386/'
-#       name: 'BOOTSTRA.386'
-#     }
-
-# appendItem = (ul, data)->
-#   { cssCdn, name, preview } = data
-#   li = $ """
#{name}
"""
-#   li.find('a').data data
-#   ul.append li
-#   li
-
-# setTheme = (theme)->
-#   { name, preview, cssCdn, isDefault } = theme
-#   $('.bootswatch-theme-name').text name
-#   $('.bootswatch-link').text(name).attr 'href', preview
-#   link = $ 'link#bootswatch-css'
-#   if link.attr('href') isnt cssCdn
-#     link.attr 'href', cssCdn
-#   unless isDefault
-#     $.cookie COOKIE_KEY_THEME, theme, themeCookieOptions
-#   bgColor = $('body').css 'background-color'
-#   if m = bgColor.match /rgb\((\d+),\s*(\d+),\s*(\d+)\s*\)/
-#     [str, r, g, b] = m
-#     bgColor = "rgba(#{r}, #{g}, #{b}, 0.9)"
-#   $('#sidebar-navigation').css 'background-color', bgColor
-
-# handleYAuctionLink = (e) ->
-#   anchor = $ e.target
-#   href = anchor.attr 'href'
-#   anchor.attr 'href', "http://ck.jp.ap.valuecommerce.com/servlet/referral?sid=2462325&pid=883185139&vc_url=#{encodeURIComponent href}"
-
-# $ ->
-#   $('body').on 'click', '[href*="auction"][href*="yahoo.co.jp"]', handleYAuctionLink
-  # $('[data-toggle=tooltip]').tooltip()
-  # $('form#tag-filter-form')
-  # .on('submit', no)
-  # .find('input')
-  # .on('keyup', handleFilterTagsKeyUp)
-  # $('.article-body > table').addClass 'table-bordered table'
-  # $('.show-all-tags-link').on('click', handleShowAllLink)
-  # $('#sidebar-bootswatch [data-toggle="dropdown"]').on 'click', loadThemeDropDown
-  # $('.bootswatch-theme-list').on 'click', 'a', ->
-    # setTheme $(@).data()
-    # no
-  # $('.read-more a').on 'click', handleReadMoreLink
-  # setTheme theme
-  # window.addEventListener 'shake', shakeEventDidOccur, no
-  # $('#sidebar-navigation').hidescroll hiddenClass: 'nav-hidden'
-  # setUpMixCloud()
-
-# new Konami () ->
-#   $('#sidebar-bootswatch').fadeIn()
-
-# theme = $.cookie(COOKIE_KEY_THEME) || getDefaultTheme()
-# document.write """<link rel="stylesheet" type="text/css" href="#{theme.cssCdn}" id="bootswatch-css">"""


Return a Disposable from Workspace::registerOpener

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -5,7 +5,7 @@
 Q = require 'q'
 Serializable = require 'serializable'
 Delegator = require 'delegato'
-{Emitter} = require 'event-kit'
+{Emitter, Disposable} = require 'event-kit'
 TextEditor = require './text-editor'
 PaneContainer = require './pane-container'
 Pane = require './pane'
@@ -363,11 +363,16 @@
   # ```
   #
   # * `opener` A {Function} to be called when a path is being opened.
+  #
+  # Returns a {Disposable} on which `.dispose()` can be called to remove the
+  # opener.
   registerOpener: (opener) ->
     @openers.push(opener)
+    new Disposable => _.remove(@openers, opener)

   # Unregister an opener registered with {::registerOpener}.
   unregisterOpener: (opener) ->
+    Grim.deprecate("Call .dispose() on the Disposable returned from ::registerOpener instead")
     _.remove(@openers, opener)

   getOpeners: ->


Profile renders

Profile renders

--- lib/assets/javascripts/views/profile.js.coffee
+++ lib/assets/javascripts/views/profile.js.coffee
@@ -9,14 +9,10 @@
     @fetchMetaProfile(options.entity)

   fetchMetaProfile: (entity) =>
-    model = TentStatus.Models.MetaProfile.find(entity: entity, fetch: false) || new TentStatus.Models.MetaProfile(entity: entity)
+    model = TentStatus.Models.MetaProfile.find(entity: entity, fetch: false)
+    return console.warn("No MetaProfile for #{JSON.stringify(entity)}!") unless model
     @profile_cid = model.cid
-    model.fetch {entity: entity},
-      failure: (profile, xhr) =>
-        @render(@context(profile))
-
-      success: (profile) =>
-        @render(@context(profile))
+    @render(@context(model))

   profile: =>
     TentStatus.Models.MetaProfile.find(cid: @profile_cid, fetch: false)


Add note in import help

Add note in import help

--- views/akashic-advanced-module.cjsx
+++ views/akashic-advanced-module.cjsx
@@ -689,7 +689,7 @@

{__ "Support List"}

阿克夏记录

-
航海日誌 拡張版

+
航海日誌 拡張版 (某些版本)

KCV-yuyuvn


Fix again

Fix again

--- src/controller.coffee
+++ src/controller.coffee
@@ -2303,7 +2303,7 @@
           vector: translationVectors[i]

       top = Math.max @aceEditor.getFirstVisibleRow(), 0
-      bottom = Math.min @aceEditor.getLastVisibleRow(), @view.getViewFor(@tree).lineLength - 1
+      bottom = Math.min @aceEditor.getLastVisibleRow(), @view.getViewNodeFor(@tree).lineLength - 1
       aceScrollTop = @aceEditor.session.getScrollTop()

       treeView = @view.getViewNodeFor @tree


Catch and report Python path errors

Catch and report Python path errors

--- lib/fortran-provider.coffee
+++ lib/fortran-provider.coffee
@@ -13,6 +13,7 @@
   saveWatchers: undefined

   pythonPath: ''
+  pythonValid: -1
   parserPath: ''
   minPrefix: 2
   preserveCase: true
@@ -41,6 +42,7 @@
     @useSnippets = atom.config.get('autocomplete-fortran.useSnippets')
     @saveWatchers = new CompositeDisposable
     @workspaceWatcher = atom.workspace.observeTextEditors((editor) => @setupEditors(editor))
+    @checkPythonPath()

   destructor: () ->
     if @workspaceWatcher?
@@ -48,10 +50,45 @@
     if @saveWatchers?
       @saveWatchers.dispose()

+  checkPythonPath: () ->
+    command = @pythonPath
+    stdOutput = ""
+    errOutput = ""
+    args = ["-V"]
+    stdout = (output) => stdOutput = output
+    stderr = (output) => errOutput = output
+    exit = (code) =>
+      if @pythonValid == -1
+        unless code == 0
+          @pythonValid = 0
+        if errOutput.indexOf('is not recognized as an internal or external') > -1
+          @pythonValid = 0
+      if @pythonValid == -1
+        @pythonValid = 1
+      else
+        console.log '[ac-fortran] Python check failed'
+        console.log '[ac-fortran]',errOutput
+    bufferedProcess = new BufferedProcess({command, args, stdout, stderr, exit})
+    bufferedProcess.onWillThrowError ({error, handle}) =>
+      if error.code is 'ENOENT' and error.syscall.indexOf('spawn') is 0
+        @pythonValid = 0
+        console.log '[ac-fortran] Python check failed'
+        console.log '[ac-fortran]',error
+        handle()
+      else
+        throw error
+
   setupEditors: (editor) ->
-    @saveWatchers.add editor.onDidSave((event) => @fileUpdateSave(event))
+    scopeDesc = editor.getRootScopeDescriptor().getScopesArray()
+    if scopeDesc[0]?.indexOf('fortran') > -1
+      @saveWatchers.add editor.onDidSave((event) => @fileUpdateSave(event))

   fileUpdateSave: (event) ->
+    if @pythonValid < 1
+      if @pythonValid == 0
+        @addError("Python path error", "Disabling FORTRAN autocompletion")
+        @pythonValid = -2
+      return
     fileRef = @modFiles.indexOf(event.path)
     if fileRef > -1
       @fileUpdate(event.path, true)
@@ -309,6 +346,11 @@
         @globalObjInd.push(key)

   getSuggestions: ({editor, bufferPosition, prefix, activatedManually}) ->
+    if @pythonValid < 1
+      if @pythonValid == 0
+        @addError("Python path error", "Disabling FORTRAN autocompletion")
+        @pythonValid = -2
+      return
     unless @exclPaths.indexOf(editor.getPath()) == -1
       return []
     # Build index on first run


some more coverage

some more coverage

--- test/phabs_admin_test.coffee
+++ test/phabs_admin_test.coffee
@@ -734,29 +734,58 @@

     context 'when the alias does not exists yet', ->
-      beforeEach ->
-        room.robot.brain.data.phabricator.projects = {
-          'Bug Report': { phid: 'PHID-PROJ-qhmexneudkt62wc7o3z4' },
-          'project': {
-            phid: 'PHID-PROJ-1234567',
-            name: 'project'
-          },
-        }
-        room.robot.brain.data.phabricator.aliases = {
-          bugs: 'Bug Report',
-          bug: 'Bug Report'
-        }
-        do nock.disableNetConnect
-
-      afterEach ->
-        room.robot.brain.data.phabricator = { }
-        nock.cleanAll()
-
-      context 'phad alias project as pwp', ->
-        hubot 'phad alias project as pwp'
-        it 'should say that the alias was created', ->
-          expect(hubotResponse())
-            .to.eql "Ok, 'project' will be known as 'pwp'."
+      context 'and project has no parent', ->
+        beforeEach ->
+          room.robot.brain.data.phabricator.projects = {
+            'Bug Report': { phid: 'PHID-PROJ-qhmexneudkt62wc7o3z4' },
+            'project': {
+              phid: 'PHID-PROJ-1234567',
+              name: 'project'
+            },
+          }
+          room.robot.brain.data.phabricator.aliases = {
+            bugs: 'Bug Report',
+            bug: 'Bug Report'
+          }
+          do nock.disableNetConnect
+
+        afterEach ->
+          room.robot.brain.data.phabricator = { }
+          nock.cleanAll()
+
+        context 'phad alias project as pwp', ->
+          hubot 'phad alias project as pwp'
+          it 'should say that the alias was created', ->
+            expect(hubotResponse())
+              .to.eql "Ok, 'project' will be known as 'pwp'."
+
+      context 'and project has a parent', ->
+        beforeEach ->
+          room.robot.brain.data.phabricator.projects = {
+            'Bug Report': {
+              phid: 'PHID-PROJ-qhmexneudkt62wc7o3z4'
+            },
+            'Bug Report/project': {
+              phid: 'PHID-PROJ-1234567',
+              name: 'project',
+              parent: 'Bug Report'
+            },
+          }
+          room.robot.brain.data.phabricator.aliases = {
+            bugs: 'Bug Report',
+            pr: 'Bug Report/project'
+          }
+          do nock.disableNetConnect
+
+        afterEach ->
+          room.robot.brain.data.phabricator = { }
+          nock.cleanAll()
+
+        context 'phad alias pr as pwp', ->
+          hubot 'phad alias pr as pwp'
+          it 'should say that the alias was created', ->
+            expect(hubotResponse())
+              .to.eql "Ok, 'Bug Report/project' will be known as 'pwp'."

   # ---------------------------------------------------------------------------------
   context 'user wants to remove an alias', ->


Remove mini class from grammar selector

Remove mini class from grammar selector

Grammars were wrapping when miniaturized even though
there was plenty of room.

--- lib/grammar-selector.coffee
+++ lib/grammar-selector.coffee
@@ -5,7 +5,7 @@

 module.exports =
 class GrammarSelector extends SelectList
-  @viewClass: -> "#{super} grammar-selector from-top overlay mini"
+  @viewClass: -> "#{super} grammar-selector from-top overlay"

   @activate: ->
     rootView.command 'grammar-selector:show', '.editor', => new GrammarSelector()


correct file type

correct file type

--- grammars/bibtex.cson
+++ grammars/bibtex.cson
@@ -1,6 +1,6 @@
 scopeName: 'text.tex.bibtex'
 name: 'BiBTeX'
-fileTypes: [ 'exp' ]
+fileTypes: [ 'bib' ]
 limitLineLength: false

 patterns: [


Set presence status message correctly for offline contacts.

--- web/chat/coffeescripts/chat.coffee
+++ web/chat/coffeescripts/chat.coffee
@@ -132,9 +132,14 @@
   presence: (presence) ->
     from = presence.from.split('/')[0]
     return if from == @session.bareJid()
-    this.eachContact from, (node) ->
-      status = presence.status || 'Available'
-      $('.status-msg', node).text status
+    if !presence.type || presence.offline
+      status =
+        if presence.status       then presence.status
+        else if presence.offline then 'Offline'
+        else if presence.away    then 'Away'
+        else 'Available'
+      this.eachContact from, (node) ->
+        $('.status-msg', node).text status

     if presence.type == 'subscribe'
       node = $("""
@@ -252,6 +257,8 @@
       name: $('#edit-contact-name').val()
       groups: []
     @session.updateContact contact
+    this.eachContact @currentContact, (node) ->
+      node.attr 'data-name', contact.name || ''
     false

   toggleForm: (form, fn) ->
@@ -259,6 +266,7 @@
     $('.contact-form').each ->
       $(this).hide() unless this.id == form.attr 'id'
     if form.is ':hidden'
+      fn() if fn
       form.fadeIn 100
     else
       form.fadeOut 100, ->
@@ -354,7 +362,10 @@

     $('#add-contact').click    => this.toggleForm '#add-contact-form'
     $('#remove-contact').click => this.toggleForm '#remove-contact-form'
-    $('#edit-contact').click   => this.toggleForm '#edit-contact-form'
+    $('#edit-contact').click   => this.toggleForm '#edit-contact-form', =>
+      if @currentContact
+        $('#edit-contact-jid').text @currentContact
+        $('#edit-contact-name').val @session.roster[@currentContact].name

     $('#add-contact-cancel').click    => this.toggleForm '#add-contact-form'
     $('#remove-contact-cancel').click => this.toggleForm '#remove-contact-form'
@@ -367,6 +378,7 @@

     $('#search-roster-text').keyup  => this.filterRoster()
     $('#search-roster-text').change => this.filterRoster()
+    $('#search-roster-text').click  => this.filterRoster()
     $('#search-roster').click =>
       this.toggleForm '#search-roster-form', => this.filterRoster()


Removed view file

Removed view file

--- lib/bookmarklet-view.coffee
+++ lib/bookmarklet-view.coffee
@@ -1,24 +0,0 @@
-{View} = require 'atom'
-
-module.exports =
-class BookmarkletView extends View
-  @content: ->
-    @div class: 'bookmarklet overlay from-top', =>
-      @div "The Bookmarklet package is Alive! It's ALIVE!", class: "message"
-
-  initialize: (serializeState) ->
-    atom.workspaceView.command "bookmarklet:toggle", => @toggle()
-
-  # Returns an object that can be retrieved when package is activated
-  serialize: ->
-
-  # Tear down any state and detach
-  destroy: ->
-    @detach()
-
-  toggle: ->
-    console.log "BookmarkletView was toggled!"
-    if @hasParent()
-      @detach()
-    else
-      atom.workspaceView.append(this)


graph: fix spelling mistake

graph: fix spelling mistake

--- workers/social/lib/social/models/graph/activity.coffee
+++ workers/social/lib/social/models/graph/activity.coffee
@@ -101,7 +101,10 @@
   # this is used for activities on profile page
   @fetchUsersActivityFeed: (requestOptions, callback)->
     @getCurrentGroup requestOptions.client, (err, currentGroup)=>
-      if err then return callback errw
+      if err
+        console.log "fetchUsersActivityFeed err:", err
+        return callback err
+
       requestOptions.group = {groupName: currentGroup.slug, groupId: currentGroup._id}

       facetQuery = @generateFacets requestOptions


apps-controller: Fixed fetching update required apps.

--- client/app/MainApp/kodingappscontroller.coffee
+++ client/app/MainApp/kodingappscontroller.coffee
@@ -185,18 +185,16 @@
   getPublishedApps: (callback) ->
     return unless KD.isLoggedIn()
     @fetchApps (err, apps) =>
-      query = []
-      for appName, manifest of apps
-        query.push { name: "JApp", identifier: manifest.identifier }
-
-      KD.remote.cacheable query, (err, apps) =>
+      appNames = []
+      appNames.push appName for appName, manifest of apps
+
+      query = "manifest.name": "$in": appNames
+      KD.remote.api.JApp.someWithRelationship query, {}, (err, apps) =>
         @publishedApps = map = {}
         apps.forEach (app) =>
-          log app, apps, app.manifest.name
           map[app.manifest.name] = app
         @emit "UserAppModelsFetched", map
         callback? map
-        log map

   isAppUpdateAvailable: (appName, appVersion) ->
     if @publishedApps[appName]


Changed reply-text selector to utilize synced Session variable instead of immediate textbox.

--- client/coffeescript/templates/reply_box.coffee
+++ client/coffeescript/templates/reply_box.coffee
@@ -24,9 +24,8 @@
     #submit a reply.
     "click button[name='reply_submit']": (event) ->
       if not event.isImmediatePropagationStopped()
-        replyTextBox = event.target.parentNode.getElementsByTagName("textarea")[0]
-        replyContent = replyTextBox.value
-        #Session.set("composing_#{ @_id }", replyContent) #not strictly necessary unless we're using it again later.
+        #old way: replyTextBox = event.target.parentNode.getElementsByTagName("textarea")[0]
+        replyContent = Session.get("composing_#{ @_id }") #replyTextBox.value
         #console.log("ID of Post you're replying to: #{ @_id }")
         #console.log("Reply content: #{replyContent}")
         if(replyContent=="") #can do other checks to prevent them from submitting all whitespace stuff


Expose site API on server.

Expose site API on server.

--- src/blueprints/server.coffee
+++ src/blueprints/server.coffee
@@ -46,6 +46,7 @@
   'product'
   'referral'
   'referrer'
+  'site'
   'subscriber'
   'transaction'
   'user'


state change events

state change events


Added all to mentions

Added all to mentions

--- app/assets/javascripts/backbone/plugins/mentions.coffee
+++ app/assets/javascripts/backbone/plugins/mentions.coffee
@@ -18,8 +18,8 @@
       return Kandan.Helpers.Activities.buildFromMessageTemplate(message)

   @initUsersMentions: (activeUsers)->
-    users = _.map activeUsers, (user)->
-      user.username
-
-    $(".chat-input").atwho("@", {data: users});
-    return
+  	users = _.map activeUsers, (user)->
+  		user.username
+  	users.push "all"
+  	$(".chat-input").atwho("@", {data: users})
+	return


Fix displaying of the required error for commercial performance validateMoneyByYears validation

--- app/assets/javascripts/frontend/form-validation.js.coffee
+++ app/assets/javascripts/frontend/form-validation.js.coffee
@@ -254,6 +254,9 @@
       first_year_min_validation = true

     for subquestion in question.find("input")
+      subq = $(subquestion)
+      err_container = subq.closest(".span-financial")
+
       shown_question = true
       for conditional in $(subquestion).parents('.js-conditional-question')
         if !$(conditional).hasClass('show-question')
@@ -262,17 +265,15 @@
       if shown_question
         input_cells_counter += 1

-        subq = $(subquestion)
         if not subq.val() and question.hasClass("question-required")
           @log_this(question, "validateMoneyByYears", "This field is required")
-          @appendMessage(subq.closest("label"), "This field is required")
+          @appendMessage(err_container, "This field is required")
           @addErrorClass(question)
           continue
         else if not subq.val()
           continue

         value = subq.val().toString()
-        err_container = subq.closest(".span-financial")

         if not value.match(@numberRegex)
           @log_this(question, "validateMoneyByYears", "Not a valid currency value")


added str/repr builtin funcs

added str/repr builtin funcs

--- src/builtin/functions.coffee
+++ src/builtin/functions.coffee
@@ -23,3 +23,13 @@

 float: (operand) ->
   return new Number(window.Number(operand))
+
+str: (operand) ->
+  if operand?
+    return operand.__str__()
+  else
+    # [Relevant](http://docs.python.org/library/functions.html#str)
+    return ''
+
+repr: (operand) ->
+  return operand.__repr__()


Kontrol: Autheticate user from session id

--- client/landing/app/MainApp/kite/kontrol.coffee
+++ client/landing/app/MainApp/kite/kontrol.coffee
@@ -11,7 +11,7 @@
     @connect()

   connect:->
-    @ws = new WebSocket @addr
+    @ws = new WebSocket @addr, KD.remote.getSessionToken()
     @ws.onopen    = @bound 'onOpen'
     @ws.onclose   = @bound 'onClose'
     @ws.onmessage = @bound 'onMessage'


Do not animate changes in the favicon badge, just update the number.

Animations sometimes look ugly at least in firefox (sometimes the favicon blinks while the animation is in progress).

--- app/assets/javascripts/ng-services/ng-FavicoSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-FavicoSvc.js.coffee
@@ -11,7 +11,7 @@
   update_unread_badge: ->
     # Only one Favico object must exist
     if !$rootScope.favico?
-      $rootScope.favico = new Favico animation: 'slide', bgColor: '#428BCA'
+      $rootScope.favico = new Favico animation: 'none', bgColor: '#428BCA'
     unread_count = unreadCountSvc.total_unread_entries()
     $rootScope.favico.badge unread_count
     $window.document.title = "(#{unread_count}) Feedbunch"


Slower animation when scrolling, for a smoother experience.

--- app/assets/javascripts/ng-services/ng-ScrollSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-ScrollSvc.js.coffee
@@ -20,7 +20,7 @@
     # We leave an offset so that part of the entry above is still visible under the navbar.
     topOffset = 100
     $timeout ->
-      $('html,body').animate {scrollTop: target.offset().top - topOffset}, 300
+      $('html,body').animate {scrollTop: target.offset().top - topOffset}, 500
     , 300

 ]


Fix for dialog colors without shade or hue.

--- packages/landsofillusions/character/avatar/avatar.coffee
+++ packages/landsofillusions/character/avatar/avatar.coffee
@@ -51,7 +51,10 @@
     @constructor.noName()

   color: ->
-    @character.document()?.avatar?.color or super
+    return super unless color = @character.document()?.avatar?.color
+
+    hue: color?.hue or LOI.Assets.Palette.Atari2600.hues.grey
+    shade: color?.shade or LOI.Assets.Palette.Atari2600.characterShades.normal

   @noNameTranslation: ->
     AB.translation @_babelSubscription, 'No Name'


DockController: Add persistent type for our dock items, save user settings in order they change the dock

--- client/Main/maincontroller/dockcontroller.coffee
+++ client/Main/maincontroller/dockcontroller.coffee
@@ -1,21 +1,14 @@
 class DockController extends KDViewController

   defaultItems = [
-    { title : "Activity",  path : "/Activity", order : 10, type :"" }
-    # { title : "Topics",    path : "/Topics",   order : 20, type :"" }
-    { title : "Teamwork",  path : "/Teamwork", order : 20, type :"" }
-    { title : "Terminal",  path : "/Terminal", order : 30, type :"" }
-    { title : "Editor",    path : "/Ace",      order : 40, type :"" }
-    { title : "Apps",      path : "/Apps",     order : 50, type :"" }
-    # { title : "About",     path : "/About",    order : 70, type :"" }
+    { title : "Activity",  path : "/Activity", order : 10, type :"persistent" }
+    # { title : "Topics",    path : "/Topics",   order : 20, type :"persistent" }
+    { title : "Teamwork",  path : "/Teamwork", order : 20, type :"persistent" }
+    { title : "Terminal",  path : "/Terminal", order : 30, type :"persistent" }
+    { title : "Editor",    path : "/Ace",      order : 40, type :"persistent" }
+    { title : "Apps",      path : "/Apps",     order : 50, type :"persistent" }
+    # { title : "About",     path : "/About",    order : 70, type :"persistent" }
   ]
-
-  createHash = (arr)->
-
-    hash = {}
-    arr.forEach (item)-> hash[item.title] = item
-    return hash
-

   constructor:(options = {}, data)->

@@ -39,58 +32,72 @@
       title        : 'navigation'
       items        : []

-    KD.setNavItems defaultItems
-    @navController.reset()
-
-    # Disabled until we figure out the flow of dock controller ~ GG
-    #
-    # @storage.fetchStorage (err, storage)=>
-
-      # usersNavItems = @storage.getValue 'navItems'
-      # ourNavItems   = defaultItems
-      # ourNavObj     = createHash ourNavItems
-      # KD.setNavItems ourNavItems
-
-      # unless usersNavItems
-
-      #   @navController.reset()
-      #   log ourNavItems, 'ready'
-      #   return @emit 'ready'
-
-      # usersNavObj = createHash usersNavItems
-
-      # # reset default items' orders if user has customized them
-      # for ourItem in ourNavItems
-      #   continue unless usersItem = usersNavObj[ourItem.title]
-      #   log 'changing order for:', ourItem.title
-      #   ourItem.order = usersItem.order
-
-      # # add user's custom items in nav items
-      # for usersItem in usersNavItems
-      #   continue if ourNavObj[usersItem.title]
-      #   KD.registerNavItem usersItem
-
-      # # re-sort the navitems
-      # KD.setNavItems KD.getNavItems()
-      # @navController.reset()
-
-      # @emit 'ready'
-
     mainController = KD.getSingleton 'mainController'
     mainController.ready @bound 'accountChanged'

-    @emit 'ready'
+    @storage.fetchValue 'navItems', (usersNavItems)=>

-  setItemOrder:(item, order = 0)->
+      unless usersNavItems
+        @setNavItems defaultItems
+        return @emit 'ready'

-    item.order = order
-    KD.setNavItems KD.getNavItems()
+      @setNavItems @buildNavItems usersNavItems
+      @emit 'ready'

+  buildNavItems:(sourceItems)->
+
+    finalItems = []
+
+    _sources = KD.utils.arrayToObject sourceItems, 'title'
+    for defaultItem in defaultItems
+      sourceItem = _sources[defaultItem.title]
+      if sourceItem
+        continue  if sourceItem.deleted
+        sourceItem.type = defaultItem.type
+        finalItems.push sourceItem
+      else
+        finalItems.push defaultItem
+
+    _defaults = KD.utils.arrayToObject defaultItems, 'title'
+    for sourceItem in sourceItems
+      defaultItem = _defaults[sourceItem.title]
+      unless defaultItem
+        finalItems.push sourceItem
+
+    return finalItems
+
+  saveItemOrders:(items)->
+
+    items or= @navController.itemsOrdered
+
+    navItems = []
+    for own index, item of items
+      {data} = item
+      data.order = index
+      navItems.push data
+
+    @storage.setValue 'navItems', navItems, (err)->
+      warn "Failed to save navItems order", err  if err
+
+  resetItemSettings:->
+    item.order = index  for own index, item of defaultItems
+
+    @storage.unsetKey 'navItems', (err)=>
+      warn "Failed to reset navItems", err  if err
+
+      KD.resetNavItems defaultItems
+      @navController.reset()
+      "Navigation items has been reset."
+
+  setNavItems:(items)->
+    KD.setNavItems items
+    @navController.reset()

   addItem:(item)->

     if KD.registerNavItem item
       @navController.addItem item
+      @saveItemOrders()

   removeItem:(item)->

@@ -135,5 +142,3 @@

       appManager.on "AppUnregistered", (name, options) =>
         @setNavItemState {name, options}, 'initial'
-
-


MainController: start lazyloading when loggedout

--- client/Main/maincontroller/maincontroller.coffee
+++ client/Main/maincontroller/maincontroller.coffee
@@ -28,7 +28,7 @@
     @attachListeners()

     @detectIdleUser()
-    @startCachingAssets()  unless KD.isLoggedIn()
+    @startCachingAssets()  unless KD.isLoggedInOnLoad

   createSingletons:->


Changed: tooltip direction to left in attachment list when there is no preview (contextual attachment list)

--- client/app/components/attachement_preview.coffee
+++ client/app/components/attachement_preview.coffee
@@ -44,7 +44,7 @@
                 a
                     href: "#{@props.file.url}?download=1"
                     'aria-describedby': Tooltips.DOWNLOAD_ATTACHMENT
-                    'data-tooltip-direction': 'top',
+                    'data-tooltip-direction': 'left',
                     """#{@props.file.generatedFileName}
                     (#{@displayFilesize(@props.file.length)})"""


Using hasClass() over jQuery

Using hasClass() over jQuery

--- client/app/lib/providers/snapshotlistitem.coffee
+++ client/app/lib/providers/snapshotlistitem.coffee
@@ -200,7 +200,7 @@
   ###
   toggleEditable: ->

-    if @infoView.$().is ':visible'
+    if not @infoView.hasClass 'hidden'
       @infoView.hide()
       @editView.show()
       kd.utils.defer @editInput.bound 'setFocus'