ActivitySidebar: Removed deprecated codes.

--- client/app/lib/activity/sidebar/activitysidebar.coffee
+++ client/app/lib/activity/sidebar/activitysidebar.coffee
@@ -75,8 +75,6 @@
     @itemsByName  = {}
     @selectedItem = null

-    # @workspaceItemChannelMap = {}
-
     # @appsList = new DockController

     router
@@ -104,7 +102,7 @@
     environmentDataProvider.revive()

     mainController.ready =>
-      whoami().on 'NewWorkspaceCreated', @bound 'newWorkspaceCreated'
+      whoami().on 'NewWorkspaceCreated', @bound 'updateMachines'

   # event handling
@@ -504,173 +502,6 @@
           publicLink.unreadCount.hide()

-  # workspacesFetched  = no
-  # fetchingWorkspaces = no
-
-  # fetchWorkspaces: do (callbackQueue = []) -> (callback = kd.noop) ->
-
-  #   activitySidebar = this
-
-  #   # return callback null, globals.userWorkspaces  if workspacesFetched
-  #   return callbackQueue.push callback       if fetchingWorkspaces
-
-  #   fetchingWorkspaces = yes
-
-  #   # put first callback to queue as well.
-  #   callbackQueue.push callback
-
-  #   remote.api.JWorkspace.fetchByMachines()
-
-  #     .then (workspaces) =>
-  #       fetchingWorkspaces = no
-
-  #       {socialapi} = kd.singletons
-
-  #       otherMachineUIds = []
-  #       myMachineUIds    = []
-
-  #       globals.userMachines.forEach (m) ->
-  #         if m.isMine() or m.isPermanent()
-  #         then myMachineUIds.push m.uid
-  #         else otherMachineUIds.push m.uid
-
-  #       otherWorkspaces  = workspaces.filter (ws) -> return ws.channelId and ws.machineUId in otherMachineUIds
-  #       myWorkspaces     = workspaces.filter (ws) -> return ws.machineUId in myMachineUIds
-
-  #       myChannels = []
-  #       queue      = []
-  #       otherWorkspaces.forEach (ws) ->
-  #         queue.push ->
-  #           socialapi.channel.byId id : ws.channelId, (err, channel) ->
-  #             myChannels.push channel.id  if channel
-  #             queue.fin()
-
-  #       sinkrow.dash queue, =>
-  #         workspacesIHaveAccess = otherWorkspaces.filter (ws) -> ws.channelId in myChannels
-  #         userWorkspaces        = myWorkspaces.concat workspacesIHaveAccess
-
-  #         globals.userMachines.forEach (machine) =>
-  #           return  unless machine.isMine()
-
-  #           for workspace in userWorkspaces \
-  #             when workspace and workspace.slug is 'my-workspace' \
-  #             and workspace.machineUId is machine.uid
-  #               return
-
-  #           userWorkspaces.push @getDummyWorkspace machine
-
-  #         globals.userWorkspaces  = userWorkspaces
-  #         # workspacesFetched     = yes
-  #         activitySidebar.updateMachineTree()
-
-  #         callbackQueue.forEach (fn) -> fn null, userWorkspaces
-  #         callbackQueue = []
-
-  #     .error (rest...) ->
-  #       fetchingWorkspaces = no
-  #       callbackQueue.forEach (fn) -> fn rest...
-  #       callbackQueue = []
-
-
-
-  # listMachines: (machines) ->
-
-    # treeData = []
-    # nickname = KD.nick()
-
-    # for machine in machines
-
-    #   treeData.push machine
-
-    #   unless machine.isPermanent()
-    #     treeData.push
-    #       title        : 'Workspaces'
-    #       type         : 'title'
-    #       parentId     : machine.getId()
-    #       id           : machine.getData().getId()
-    #       machineUId   : machine.uid
-    #       machineLabel : machine.slug or machine.label
-
-    #   ideRoute     = "/IDE/#{machine.slug or machine.label}/my-workspace"
-    #   machineOwner = machine.getOwner()
-    #   isMyMachine  = machine.isMine()
-    #   ideRoute     = "#{ideRoute}/#{machineOwner}"  unless isMyMachine
-    #   hasWorkspace = (KD.userWorkspaces.filter ({name, machineUId}) -> return name is 'My Workspace' and machineUId is machine.uid).length > 0
-
-    #   if machine.isMine() and not hasWorkspace
-    #     KD.userWorkspaces.push @getDummyWorkspace machine
-
-    #   @sortWorkspaces KD.userWorkspaces
-
-    #   KD.userWorkspaces.forEach (workspace) ->
-
-    #     unless workspace instanceof KD.remote.api.JWorkspace
-    #       workspace = KD.remote.revive workspace
-
-    #     if workspace.machineUId is machine.uid
-    #       ideRoute = "/IDE/#{machine.slug or machine.label}/#{workspace.slug}"
-    #       title    = "#{workspace.name}"
-
-    #       unless isMyMachine
-    #         if channelId = workspace.channelId
-    #         then ideRoute = "/IDE/#{channelId}"
-    #         else
-    #           return
-
-    #       if not workspace.isDefault or workspace.slug isnt 'my-workspace'
-    #         title += ""
-
-    #       treeData.push
-    #         title        : title
-    #         type         : 'workspace'
-    #         href         : ideRoute
-    #         machineLabel : machine.slug or machine.label
-    #         data         : workspace
-    #         id           : workspace._id
-    #         parentId     : machine.getId()
-
-    # for data in treeData
-
-    #   node = @machineTree.addNode data
-
-    #   @mapWorkspaceWithChannel data, node  if data.type is 'workspace'
-
-    # @emit 'MachinesListed'
-
-
-  # getDummyWorkspace: (machine) ->
-
-    # new KD.remote.api.JWorkspace
-    #   _id          : "#{machine.getId()}-my-workspace"
-    #   isDummy      : yes
-    #   isDefault    : yes
-    #   originId     : KD.whoami()._id # In case JAccount is not revived yet
-    #   slug         : 'my-workspace'
-    #   machineUId   : machine.uid
-    #   machineLabel : machine.label
-    #   name         : 'My Workspace'
-
-
-  # sortWorkspaces: (workspaces) ->
-
-    # workspaces.sort (a, b) ->
-    #   switch
-    #     when a.slug is 'my-workspace' then -1
-    #     when b.slug is 'my-workspace' then 1
-    #     when a.slug  b.slug then 1
-    #     else 0
-
-
-  # mapWorkspaceWithChannel: (data, node) ->
-
-    # return  unless data.data?.channelId?
-
-    # { channelId } = data.data
-
-    # @workspaceItemChannelMap[channelId] = node
-
-
   selectWorkspace: (data) ->

     { machine, workspace } = data
@@ -678,129 +509,12 @@
     for machineList in @machineLists
       machineList.selectMachineAndWorkspace machine.uid, workspace.slug

-    # data = @latestWorkspaceData or {}  unless data
-    # { workspace, machine } = data
-
-    # return if not machine or not workspace
-
-    # tree = @machineTree
-
-    # for key, node of tree.nodes
-    #   nodeData         = node.getData()
-    #   isSameMachine    = nodeData.uid is machine.uid
-    #   isMachineRunning = machine.status.state is Machine.State.Running
-
-    #   if node.type is 'machine'
-    #     if isSameMachine
-    #       if isMachineRunning
-    #         tree.expand node
-    #       else
-    #         tree.selectNode node
-    #         @watchMachineState data
-    #     else
-    #       tree.collapse node
-
-    #   else if node.type is 'workspace'
-    #     if isMachineRunning and nodeData.machineLabel is (machine.slug or machine.label)
-    #       slug = nodeData.data?.slug or KD.utils.slugify nodeData.title
-    #       tree.selectNode node  if slug is workspace.slug
-
-    # @latestWorkspaceData = data
-
-    # localStorage, what a good name, acet!
-    # localStorage = KD.getSingleton("localStorageController").storage "IDE"
-
-    # minimumDataToStore =
-    #   machineLabel     : machine.slug or machine.label
-    #   workspaceSlug    : workspace.slug
-    #   channelId        : data.channelId
-
-    # localStorage.setValue 'LatestWorkspace', minimumDataToStore
-
-
-  # watchMachineState: (data) ->
-
-  #   {workspace, machine} = data
-
-  #   @watchedMachines  or= {}
-
-  #   {Running} = Machine.State
-
-  #   return  if @watchedMachines[machine._id]
-
-  #   callback = (state) =>
-  #     return  if state.status isnt Running
-
-  #     machine.status.state = Running
-  #     delete @watchedMachines[machine._id]
-
-  #     if data is @latestWorkspaceData
-  #       @selectWorkspace data
-
-  #   kd.getSingleton 'computeController'
-  #     .on "public-#{machine._id}", callback
-
-  #   @watchedMachines[machine._id] = yes
-

   # TODO: Rename this method to fetchEnvironment - acet!
   fetchMachines: (callback) ->

     environmentDataProvider.fetch (data) =>
       callback data
-
-
-    # {computeController} = KD.singletons
-
-    # force refetch from server everytime machines fetched.
-    # computeController.reset()
-    # computeController.fetchMachines (err, machines)=>
-    #   if err
-    #     return new KDNotificationView title : 'Couldn\'t fetch your VMs'
-
-    #   callback machines
-
-
-
-
-  # addVMTree: ->
-
-  #   @addSubView section = new KDCustomHTMLView
-  #     tagName  : 'section'
-  #     cssClass : 'vms'
-
-  #   @machineTree = new JTreeViewController
-  #     type                : 'main-nav'
-  #     treeItemClass       : NavigationItem
-  #     addListsCollapsed   : yes
-
-  #   @machineTree.getView().unsetClass 'kdscrollview'
-
-  #   # This is temporary, we will create a separate TreeViewController
-  #   # for this and put this logic into there ~ FIXME ~ GG
-  #   @machineTree.dblClick = (nodeView, event)->
-  #     machine = nodeView.getData()
-  #     if machine.status?.state is Machine.State.Running
-  #       @toggle nodeView
-
-  #   section.addSubView header = new KDCustomHTMLView
-  #     tagName  : 'h3'
-  #     cssClass : 'sidebar-title'
-  #     partial  : 'VMs'
-  #     click    : @bound 'handleMoreVMsClick'
-
-  #   header.addSubView new CustomLinkView
-  #     cssClass : 'add-icon buy-vm'
-  #     title    : ' '
-
-  #   section.addSubView @machineTree.getView()
-
-  #   @machineTree.on 'NodeWasAdded', (machineItem) =>
-  #     machineItem.on 'click', @lazyBound 'handleMachineItemClick', machineItem
-
-  #   if KD.userMachines.length
-  #   then @listMachines (new Machine machine: (KD.remote.revive machine) for machine in KD.userMachines)
-  #   else @fetchMachines @bound 'listMachines'

   addMachineList: ->
@@ -845,59 +559,6 @@
     @addSubView list

     return list
-
-
-
-  # handleMachineItemClick: (machineItem, event) ->
-
-  #   machine  = machineItem.getData()
-  #   {status} = machine
-  #   {Building, Running} = Machine.State
-
-  #   @activityLink?.unsetClass 'selected'
-
-  #   if event.target.nodeName is 'SPAN'
-
-  #     if status?.state is Running
-  #       KD.utils.stopDOMEvent event
-  #       KD.singletons.mainView.openMachineModal machine, machineItem
-  #     else return
-
-  #   else if machineItem.getData().status?.state is Machine.State.Building
-
-  #     return
-
-
-  # handleMoreVMsClick: (ev) ->
-
-  #   KD.utils.stopDOMEvent ev
-
-  #   if 'add-icon' in ev.target.classList
-  #   then ComputeHelpers.handleNewMachineRequest()
-  #   else new MoreVMsModal {}, KD.userMachines
-
-
-  # handleMoreWorkspacesClick: (data) ->
-  #   workspaces = for workspace in KD.userWorkspaces when workspace.machineUId is data.machineUId
-  #     workspace.machineLabel = data.machineLabel
-  #     workspace
-
-  # ======= start of conflict block
-  # ======= preserved conflict since it's already commented out on refactor
-  # handleMoreWorkspacesClick: (data) ->
-
-  #   machine = m for m in KD.userMachines when m.uid is data.machineUId
-
-  #   return no  if not machine or not machine.isMine()
-
-  #   workspaces = for workspace in KD.userWorkspaces when workspace.machineUId is data.machineUId
-  #     workspace.machineLabel = data.machineLabel
-  #     workspace
-  # ======= end of conflict block
-
-  #   data.workspaces = workspaces or []
-
-  #   new MoreWorkspacesModal {}, data

   addFollowedTopics: ->
@@ -997,100 +658,6 @@
     else @once 'MachinesListed', => cb()

-  # addNewWorkspace: (machineData) ->
-  #   return if @addWorkspaceView
-
-  #   {machineUId, machineLabel, delegate} = machineData
-  #   type     = 'new-workspace'
-  #   parentId = machineUId
-  #   id       = "#{machineUId}-input"
-  #   data     = { type, machineUId, machineLabel, parentId, id }
-  #   tree     = @machineTree
-
-  #   @addWorkspaceView = delegate.addItem { type, machineUId, machineLabel }
-
-  #   @addWorkspaceView.child.once 'KDObjectWillBeDestroyed', =>
-  #     delegate.removeItem @addWorkspaceView
-  #     @addWorkspaceView = null
-
-  #   KD.utils.wait 177, => @addWorkspaceView.child.input.setFocus()
-
-
-  # createNewWorkspace: (options = {}) ->
-
-  #   {name, machineUId, rootPath, machineLabel} = options
-  #   {computeController, router } = KD.singletons
-  #   layout = {}
-
-  #   if not name or not machineUId
-  #     return warn 'Missing options to create a new workspace'
-
-  #   machine = m for m in computeController.machines when m.uid is machineUId
-  #   data    = { name, machineUId, machineLabel, rootPath, layout }
-
-  #   return warn "Machine not found."  unless machine
-
-  #   KD.remote.api.JWorkspace.create data, (err, workspace) =>
-  #     if err
-  #       @emit 'WorkspaceCreateFailed'
-  #       return KD.showError "Couldn't create your new workspace"
-
-  #     folderOptions  =
-  #       type         : 'folder'
-  #       path         : workspace.rootPath
-  #       recursive    : yes
-  #       samePathOnly : yes
-
-  #     machine.fs.create folderOptions, (err, folder) =>
-  #       if err
-  #         @emit 'WorkspaceCreateFailed'
-  #         return KD.showError "Couldn't create your new workspace"
-
-  #       filePath   = "#{workspace.rootPath}/README.md"
-  #       readMeFile = FSHelper.createFileInstance { path: filePath, machine }
-
-  #       readMeFile.save IDE.contents.workspace, (err) =>
-  #         if err
-  #           @emit 'WorkspaceCreateFailed'
-  #           return KD.showError "Couldn't create your new workspace"
-
-  #         for nodeData in @machineTree.indexedNodes when nodeData.uid is machine.uid
-  #           parentId = nodeData.id
-
-  #         view    = @addWorkspaceView
-  #         data    =
-  #           title : "#{workspace.name} "
-  #           type  : 'workspace'
-  #           href  : "/IDE/#{machine.slug or machine.label}/#{workspace.slug}"
-  #           data  : workspace
-  #           id    : workspace._id
-  #           machineLabel : machineLabel
-  #           parentId: parentId
-
-  #         if view
-  #           list  = view.getDelegate()
-  #           list.removeItem view  if view
-  #         else
-  #           for key, node of @machineTree.nodes when node.type is 'title'
-  #             list = node.getDelegate()
-
-  #         KD.userWorkspaces.push workspace
-  #         @sortWorkspaces KD.userWorkspaces
-
-  #         index = 1 + KD.userWorkspaces
-  #           .filter (w) -> w.machineUId is machine.uid
-  #           .map    (w) -> w.slug
-  #           .indexOf workspace.slug
-
-  #         @machineTree.addNode data, index
-
-  #         router.handleRoute data.href
-  #         @emit 'WorkspaceCreated', workspace
-
-
-  # updateMachineTree: ->
-
-
   updateMachines: (callback = kd.noop) ->

     @fetchMachines (data) =>
@@ -1098,12 +665,6 @@
       @sharedMachinesList.updateList data.shared.concat data.collaboration

-    # @machineTree.removeAllNodes()
-    # @listMachines machines
-
-    # @selectWorkspace()
-
-
   invalidateWorkspaces: (machine)->

     return  unless machine?
@@ -1111,11 +672,6 @@
     remote.api.JWorkspace.deleteByUid machine.uid, (err)=>

       return kd.warn err  if err?
-
-      # globals.userWorkspaces =
-      #   ws for ws in globals.userWorkspaces when ws.machineUId isnt machine.uid
-
-      # @updateMachineTree()

   removeMachineNode: (machine) ->
@@ -1134,18 +690,3 @@
           box = machineBox

     return box
-
-
-  newWorkspaceCreated: (workspace) ->
-
-    @updateMachines()
-
-
-    # matches = globals.userWorkspaces.filter (w) ->
-    #   w.machineUId is workspace.machineUId and \
-    #   w.slug is workspace.slug
-
-    # return  if matches.length
-
-    # globals.userWorkspaces.push workspace
-    # @updateMachineTree()


ActivitySidebar: Handle accountRemovedFromChannel.

--- client/app/lib/activity/sidebar/activitysidebar.coffee
+++ client/app/lib/activity/sidebar/activitysidebar.coffee
@@ -270,8 +270,10 @@

     @removeItem id

-    if @workspaceItemChannelMap[id]
-      @fetchMachines => @fetchWorkspaces()
+    @sharedMachinesList.removeWorkspaceByChannelId id
+
+    # if @workspaceItemChannelMap[id]
+    #   @fetchMachines => @fetchWorkspaces()

     # TODO update participants in sidebar


Fix AsyncFs error handling

Fix AsyncFs error handling

--- src/filesystem/asyncfs.coffee
+++ src/filesystem/asyncfs.coffee
@@ -11,8 +11,8 @@
   null

   invokeCallback = (callback, promise) ->
-    promise.then((value...) ->
-      callback(null, value...)
+    promise.then((value) ->
+      callback(null, value)
       return
     ).catch((error) ->
       callback(error)
@@ -23,8 +23,6 @@
   SEP         = "/"
   SEP_RE      = /\/+/
   SEP_LAST_RE = /\/+$/
-
-  window.AsyncFs = AsyncFs  # For debugging

   #--------------------------------------------------------------------------------
   # Original properties
@@ -193,8 +191,10 @@
       chrome.fileSystem.chooseEntry(
         {type: "openDirectory"}
         (entry) =>
-          return reject(Error(chrome.runtime.lastError)) unless entry?
-          return resolve(entry)
+          unless entry?
+            error = chrome.runtime.lastError
+            return reject(Error(error?.message or error))
+          return resolve(new Html5Fs(entry))
       )
     ) # return new Promise()


empty body when re-rendering a page

empty body when re-rendering a page

--- src/coffee/controller.coffee
+++ src/coffee/controller.coffee
@@ -49,8 +49,8 @@
       contents = @layout contents
     contents._context = this
     contents = SwanKiosk.Layout.build contents
-    @_getBody().html ''
-    @_getBody().get(0).appendChild contents
+    @_getBody().empty()
+    @_getBody().append contents

   _renderPlain: (contents) ->
     return false if @rendered


capitalize selectedIncidentType

capitalize selectedIncidentType

--- client/controllers/incidentReports/incidentForm.coffee
+++ client/controllers/incidentReports/incidentForm.coffee
@@ -97,7 +97,9 @@
       'active'

   selectedIncidentType: ->
-    Template.instance().incidentType.get().slice(0, -1)
+    switch Template.instance().incidentType.get()
+      when "cases" then "Case"
+      when "deaths" then "Death"

   suggestedField: (fieldName)->
     if fieldName in Template.instance().suggestedFields.get()


Much better naming

Much better naming

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -113,7 +113,7 @@
       else
         justFetchApps()

-  fetchCompiledApp:(manifest, callback)->
+  fetchCompiledAppSource:(manifest, callback)->

     indexJs = FSHelper.createFileFromPath "#{@getAppPath manifest}/index.js"
     indexJs.fetchContents (err, response)=> callback null, response
@@ -160,7 +160,7 @@
     if script = KD.getAppScript name
       callback null, script
     else
-      @fetchCompiledApp manifest, (err, script)=>
+      @fetchCompiledAppSource manifest, (err, script)=>
         if err
           @compileApp name, (err)->
             callback err, script
@@ -304,7 +304,7 @@
       , (err)=>
         if not err
           loader.notificationSetTitle "Fetching compiled app..."
-          @fetchCompiledApp app, (err, res)=>
+          @fetchCompiledAppSource app, (err, res)=>
             if not err
               @defineApp name, res
               loader.notificationSetTitle "App compiled successfully"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/game_state_cameras.coffee
+++ src/game_state_cameras.coffee
@@ -24,4 +24,6 @@
     ###
     cameras: ->
       return cameras
+    flash: ->
+      cameras.first().flash()
   }


take the default username from the key

take the default username from the key

--- src/kite-server/kite-server.coffee
+++ src/kite-server/kite-server.coffee
@@ -104,13 +104,13 @@

       @key = key

-      { kontrolURL } = getKontrolClaims @key
+      { kontrolURL, sub: keyUsername } = getKontrolClaims @key

       @kontrol = new Kontrol
         url             : userKontrolURL ? kontrolURL
         auth            : { type: 'kiteKey', key }
         name            : name
-        username        : username
+        username        : username ? keyUsername
         environment     : environment
         version         : version
         region          : region


Correct conditional

Correct conditional

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -238,4 +238,4 @@
   # successfully by anything above.
   require('artsy-error-handler') app,
     template: path.resolve(__dirname, '../components/main_layout/templates/error.jade'),
-    showDetail: NODE_ENV is not 'production'
+    showDetail: NODE_ENV isnt 'production'


add asset path to sharify data

add asset path to sharify data

--- lib/setup.coffee
+++ lib/setup.coffee
@@ -4,7 +4,7 @@
 # populating sharify data
 #

-{ API_URL, NODE_ENV, SESSION_SECRET, SESSION_COOKIE_MAX_AGE, SESSION_COOKIE_KEY, COOKIE_DOMAIN} = config = require "../config"
+{ API_URL, NODE_ENV, SESSION_SECRET, SESSION_COOKIE_MAX_AGE, SESSION_COOKIE_KEY, COOKIE_DOMAIN, ASSET_PATH} = config = require "../config"

 _ = require 'underscore'
 express = require "express"
@@ -24,6 +24,7 @@
   API_URL: API_URL
   JS_EXT: (if "production" is NODE_ENV then ".min.js" else ".js")
   CSS_EXT: (if "production" is NODE_ENV then ".min.css" else ".css")
+  ASSET_PATH: ASSET_PATH

 # current user management
 CurrentUser = require '../models/current_user'


Fix codeblock snippet for new markdown plugin

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -142,7 +142,7 @@
             })

             """
-'.source.gfm':
+'.text.md':
   'Octopress Codeblock':
     'prefix': 'cb'
     'body': """


Shorten Liquid "expression" snippet to "exp"

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -740,7 +740,7 @@
  .source.gfm':

   'expression':
-    'prefix': 'expression'
+    'prefix': 'exp'
     'body': '{{ $1 }}'

   'liquid':


Remove ambiguous/inconsistent C++ operator snippets

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -112,38 +112,6 @@
     'prefix': 'cerre'
     'body': "cerr << $1 << endl;"

-  'operator (=) ':
-    'prefix': 'op='
-    'body': "${1:Class}& operator=(const ${1:Class}& other)$2"
-
-  'operator (friend)':
-    'prefix': 'opfriend'
-    'body': "${1:friend }${2:Class} operator${3:+}(const ${4:Left}& left, const ${5:Right}& right)$6"
-
-  'operator (<<)':
-    'prefix': 'op<<'
-    'body': "${1:friend }ostream& operator<<(ostream& out, const ${2:Class}& other)$3"
-
-  'operator ([])':
-    'prefix': 'op[]'
-    'body': "${1:Class}& operator[](int) const$5"
-
-  'operator (++x)':
-    'prefix': 'op++x'
-    'body': "${1:Class}& operator${2:++}()$3"
-
-  'operator (x++)':
-    'prefix': 'opx++'
-    'body': "${1:Class} operator${2:++}(int)$3"
-
-  'operator (+)':
-    'prefix': 'op+'
-    'body': "${1:Class} operator${2:+}() const$3"
-
-  'operator (+=/-=)':
-    'prefix': 'op+='
-    'body': "${1:Class} operator${2:+}=() const$3"
-

 # JavaScript


Lefay, pls stop showing this gif avery time we talk about asset magick


fix: Remove debug logging

fix: Remove debug logging

--- app/web/caretaker-controlpanel/dialogs/caretaker-controlpanel-edit-widget-dialog.coffee
+++ app/web/caretaker-controlpanel/dialogs/caretaker-controlpanel-edit-widget-dialog.coffee
@@ -26,7 +26,6 @@
     @resolve @widget

   cancel: ->
-    console.log @initial
     @widget.device.id = @initial.deviceId
     @widget.title = @initial.title
     @widget.width = @initial.width


Correctly call resize (#4668)

Correctly call resize (#4668)

--- bokehjs/src/coffee/models/tools/actions/reset_tool.coffee
+++ bokehjs/src/coffee/models/tools/actions/reset_tool.coffee
@@ -10,7 +10,7 @@
     @plot_view.reset_selection()
     if @model.reset_size
       @plot_view.reset_dimensions()
-      @model.document.solver().trigger('resize')
+      @model.document.resize()

 class ResetTool extends ActionTool.Model
   default_view: ResetToolView


updated codeshare to have the same fix as code snip when it comes to malformed data objects

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeBin.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeBin.coffee
@@ -356,7 +356,7 @@

     @syntaxMode = new KDCustomHTMLView
       tagName  : "strong"
-      partial  : __aceSettings.syntaxAssociations[syntax][0] or syntax
+      partial  : __aceSettings.syntaxAssociations[syntax]?[0] or syntax ? "text"

     @saveButton = new KDButtonView
       title     : ""


do not init resposeDest.body to be a buffer

--- src/middleware/router.coffee
+++ src/middleware/router.coffee
@@ -109,34 +109,33 @@
 				when 'location' then responseDst.redirect(value)
 				else responseDst.header[key] = value

-		responseDst.body = new Buffer(0)
 		bufs = []
 		routeRes.on "data", (chunk) ->
-                        bufs.push chunk
+			bufs.push chunk

                 #See https://www.exratione.com/2014/07/nodejs-handling-uncertain-http-response-compression/
 		routeRes.on "end", ->
-                        responseDst.timestamp = new Date()
-                        charset = obtainCharset(routeRes.headers)
-                        if (routeRes.headers['content-encoding'] == 'gzip')
-                                console.log('gzip')
-                                zlib.gunzip(
-                                        Buffer.concat(bufs),
-                                        (gunzipError, buf)->
-                                                if (gunzipError) then console.log(gunzipError)
-                                                else responseDst.body = buf.toString(charset)
-                                )
-                        else if (routeRes.headers['content-encoding'] == 'deflate')
-                                console.log('deflate')
-                                zlib.inflate(
-                                        Buffer.concat(bufs),
-                                        (inflateError, buf)->
-                                                if (inflateError) then console.log(inflateError)
-                                                else responseDst.body = buf.toString(charset)
-                                )
-                        else
-                                responseDst.body = Buffer.concat(bufs)
+			responseDst.timestamp = new Date()
+			charset = obtainCharset(routeRes.headers)
+			if (routeRes.headers['content-encoding'] == 'gzip')
+				console.log('gzip')
+				zlib.gunzip(
+					Buffer.concat(bufs),
+					(gunzipError, buf)->
+						if (gunzipError) then console.log(gunzipError)
+						else responseDst.body=buf.toString(charset)
+				)
+			else if (routeRes.headers['content-encoding'] == 'deflate')
+				console.log('deflate')
+				zlib.inflate(
+					Buffer.concat(bufs),
+					(inflateError, buf)->
+						if (inflateError) then console.log(inflateError)
+						else responseDst.body = buf.toString(charset)
+				)
+			else
+				responseDst.body = Buffer.concat(bufs).toString(charset)
 			callback()

 	routeReq.on "error", (err) ->


Remove req.nconf

Remove req.nconf

--- server/packages/config/index.coffee
+++ server/packages/config/index.coffee
@@ -20,15 +20,15 @@
 	hostname: "//#{req.headers.host}"

 	# Is the server running in test mode?
-	testMode: if (req.nconf.get 'E2E')? then 'e2e' else false
+	testMode: if (nconf.get 'E2E')? then 'e2e' else false

 	# Debug mode if we're not running in production.
 	#
 	# } `TODO`: Remove this, and implement a client logging system.
-	debugging: 'production' isnt req.nconf.get 'NODE_ENV'
+	debugging: 'production' isnt nconf.get 'NODE_ENV'

 	# The list of enabled packages.
-	packageList: req.nconf.get 'packageList'
+	packageList: nconf.get 'packageList'

 # ## Implements hook `httpMiddleware`
 exports.$httpMiddleware = (http) ->
@@ -36,14 +36,6 @@
 	label: 'Serve package configuration'
 	middleware: [

-		# Store nconf in the request.
-		(req, res, next) ->
-
-			# } `TODO`: Should probably just remove this and `require 'nconf'`.
-			req.nconf = nconf
-
-			next()
-
 		# Serve the configuration module.
 		(req, res, next) ->


Groups: Environment stack title fix

Groups: Environment stack title fix

--- client/Environments/views/environmentsmainscene.coffee
+++ client/Environments/views/environmentsmainscene.coffee
@@ -44,14 +44,15 @@
     JStack.getStacks (err, stacks)=>
       warn err  if err

+      group = KD.getGroup().title
       if not stacks or stacks.length is 0
-        stacks = [{sid:0, group:KD.getGroup().slug}]
+        stacks = [{sid:0, group}]

       stacks.forEach (stack)=>

         title   = stack.meta?.title
         number  = if stack.sid > 0 then "#{stack.sid}." else "default"
-        title or= "Your #{number} stack on #{stack.group}"
+        title or= "Your #{number} stack on #{group}"

         @addSubView new StackView {}, {title, stack}


Mr conflict fix

Mr conflict fix

--- client/Social/Activity/views/feedcoverphotoview.coffee
+++ client/Social/Activity/views/feedcoverphotoview.coffee
@@ -21,9 +21,10 @@
   getCoverUpdateButton: ->
     if "admin" in KD.config.roles
       new KDButtonView
-        style     : "solid green small"
+        style     : "solid green small update-cover"
+        icon      : yes
         type      : "submit"
-        title     : "update cover photo"
+        title     : "Update cover image"
         callback  : =>
           new UploadImageModalView
             title      : "Change Cover Photo"


Instantiate stack machine list

Instantiate stack machine list

--- client/app/lib/activity/sidebar/activitysidebar.coffee
+++ client/app/lib/activity/sidebar/activitysidebar.coffee
@@ -594,7 +594,8 @@
         cssClass: 'machines-wrapper'

     if isKoding()
-      @createDefaultMachineList expandedBoxUIds
+    then @createDefaultMachineList expandedBoxUIds
+    else @createStackMachineList expandedBoxUIds

   createDefaultMachineList: (expandedBoxUIds) ->


Updated to use DatabaseURL

Updated to use DatabaseURL

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -38,30 +38,6 @@
   # @private
   @guid = -> return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4())

-  # @private
-  @parseUrl: (url) ->
-    url_parts = URL.parse(url)
-    database_parts = url_parts.pathname.split('/')
-    table = database_parts.pop()
-    database = database_parts[database_parts.length-1]
-    url_parts.pathname = database_parts.join('/')
-
-    result = {
-      host: url_parts.hostname
-      port: url_parts.port
-      database_path: URL.format(url_parts)
-      database: database
-      table: table
-      model_name: inflection.classify(inflection.singularize(table))
-    }
-
-    if url_parts.auth
-      auth_parts = url_parts.auth.split(':')
-      result.user = auth_parts[0]
-      result.password = if auth_parts.length > 1 then auth_parts[1] else null
-
-    return result
-
   @get: (model, key, default_value) ->
     model._orm or= {}
     return if model._orm.hasOwnProperty(key) then model._orm[key] else default_value
@@ -86,7 +62,7 @@
   @findOrGenerateModelName: (model_type) ->
     return model_type.model_name if model_type.model_name
     if url = _.result(model_type.prototype, 'url')
-      return model_name if model_name = Utils.parseUrl(url).model_name
+      return model_name if model_name = (new DatabaseURL(url)).modelName()
     return model_type.name if model_type.name
     throw "Could not find or generate model name for #{model_type}"


Add description for include utility func

--- lib/utils.coffee
+++ lib/utils.coffee
@@ -13,6 +13,7 @@
     else
       'character'

+  # Include module(object which normaly provides set of methods) to klass
   include: (klass, module) ->
     for key, value of module
       klass::[key] = value


enable showProgress once response content length is available

--- www/js/file.coffee
+++ www/js/file.coffee
@@ -24,6 +24,7 @@

 			progress: (event) =>
 				if event.lengthComputable && event.total > 0
+					@showProgress = true
 					@percentage = Math.round event.loaded / event.total * 100
 				else
 					@showProgress = false


Use applications kite for installing app

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -523,6 +523,7 @@
                 callback? err
               else
                 options =
+                  kiteName      : "applications"
                   method        : "installApp"
                   withArgs      :
                     owner       : acc.profile.nickname


updated to express 2.x API.

updated to express 2.x API.

--- lib/zappa.coffee
+++ lib/zappa.coffee
@@ -85,9 +85,9 @@
       @http_server.register '.coffee', coffeekup
       @http_server.set 'view engine', 'coffee'
     @http_server.configure =>
-      @http_server.use express.staticProvider("#{process.cwd()}/public")
-      @http_server.use express.bodyDecoder()
-      @http_server.use express.cookieDecoder()
+      @http_server.use express.static("#{process.cwd()}/public")
+      @http_server.use express.bodyParser()
+      @http_server.use express.cookieParser()
       # TODO: Make the secret configurable.
       @http_server.use express.session(secret: 'hackme')


ErrorReporter prints with error severity closes #220

--- wzk/app/App.coffee
+++ wzk/app/App.coffee
@@ -32,7 +32,7 @@
     @param {Object=} msgs
   ###
   run: (@win, flash, msgs = {}) ->
-    log = if @win['console']? then goog.bind(@win['console']['log'], @win['console']) else ->
+    log = if @win['console']? then goog.bind(@win['console']['error'], @win['console']) else ->
     @reporter.setLog log

     @doc = @win.document


test that actions are triggered when button clicked

--- coach/specs/concept-coach/error-notification.spec.cjsx
+++ coach/specs/concept-coach/error-notification.spec.cjsx
@@ -1,6 +1,7 @@
 {Testing, sinon, _, React, ReactTestUtils} = require 'shared/specs/helpers'

-{ConceptCoach}    = require 'concept-coach/base'
+jest.mock '../../src/navigation/model'
+
 ErrorNotification = require 'concept-coach/error-notification'

 TASK  = require '../../api/cc/tasks/C_UUID/m_uuid/GET'
@@ -18,8 +19,11 @@
     data:
       errors: [ {code: 'test_test_test'} ]

+Navigation = null
+
 describe 'CC Error Notification Component', ->
   beforeEach ->
+    Navigation = require '../../src/navigation/model'
     @props =
       course: new Course(_.first(AUTH_DATA.courses))
       close: sinon.spy()
@@ -36,15 +40,18 @@
     wrapper = shallow(<ErrorNotification {...@props} />)
     msg = 'undefined var foo used in bar'
     api.channel.emit('error', new Error(msg))
-    console.log wrapper.debug()
     expect(wrapper.find('ModalBody').render().text()).to.include("Error: #{msg}")
     undefined

   it 'shows error details by default', ->
     wrapper = shallow(<ErrorNotification {...@props} />)
+    comp = wrapper.instance()
+    sinon.stub(comp, 'onHide')
     api.channel.emit('error', ERROR)
     expect(wrapper.find('ModalTitle').render().text()).to.equal('Server Error encountered')
     expect(wrapper.find('ModalBody').render().text()).to.include('test_test_test')
+    wrapper.find('ModalFooter Button').simulate('click')
+    expect(comp.onHide).to.have.been.called
     undefined

   it 'renders course not started', ->
@@ -54,6 +61,8 @@
     api.channel.emit('error', error)
     expect(wrapper.find('ModalTitle').render().text()).to.equal('Future Course')
     expect(wrapper.find('ModalBody').render().text()).to.include('not yet started')
+    wrapper.find('ModalFooter Button').simulate('click')
+    expect(@props.close).to.have.been.called
     undefined

   it 'renders course has ended', ->
@@ -63,4 +72,6 @@
     api.channel.emit('error', error)
     expect(wrapper.find('ModalTitle').render().text()).to.equal('Past Course')
     expect(wrapper.find('ModalBody').render().text()).to.include('course ended')
+    wrapper.find('ModalFooter Button').simulate('click')
+    expect(Navigation.channel.emit).toHaveBeenCalledWith('show.progress', view: 'progress')
     undefined


Number#seconds

Number#seconds

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -401,6 +401,27 @@

   return sum

+###*
+Utility method to convert a number to a duration of seconds.
+
+

+3.seconds
+# => 3000
+
+setTimout doSometing, 3.seconds
+

+
+@name seconds
+@propertyOf Number#
+@returns {Number} This number as a duration of seconds
+###
+Object.defineProperty Number::, 'seconds',
+  get: ->
+    @ * 1000
+Object.defineProperty Number::, 'second',
+  get: ->
+    @ * 1000
+
 ###*
 The mathematical circle constant of 1 turn.


Rewrite halloheadings to use hallobutton

part of the reason for rewriting was that it simple didnt work in IE

--- src/plugins/headings.coffee
+++ src/plugins/headings.coffee
@@ -5,63 +5,44 @@
   jQuery.widget "IKS.halloheadings",
     options:
       editable: null
-      toolbar: null
-      uuid: ""
-      headers: [1,2,3]
+      uuid: ''
+      formatBlocks: ["p", "h1", "h2", "h3"]
+      buttonCssClass: null

     populateToolbar: (toolbar) ->
       widget = this
       buttonset = jQuery ""
-      id = "#{@options.uuid}-paragraph"
-      label = "P"
-      markup = "<input id=\"#{id}\" type=\"radio\"
-        name=\"#{widget.options.uuid}-headings\"/>
-        #{label}"
-      buttonset.append jQuery(markup).button()
-      button = jQuery "##{id}", buttonset
-      button.attr "hallo-command", "formatBlock"
-      button.on "change", (event) ->
-        cmd = jQuery(this).attr "hallo-command"
-        widget.options.editable.execute cmd, "P"
+      ie = jQuery.browser.msie
+      command = (if ie then "FormatBlock" else "formatBlock")

-      buttonize = (headerSize) =>
-        label = "H" + headerSize
-        id = "#{@options.uuid}-#{headerSize}"
-        buttonMarkup = "<input id=\"#{id}\" type=\"radio\"
-          name=\"#{widget.options.uuid}-headings\"/>
-          #{label}"
-        buttonset.append jQuery(buttonMarkup).button()
-        button = jQuery "##{id}", buttonset
-        button.attr "hallo-size", "H"+headerSize
-        button.on "change", (event) ->
-          size = jQuery(this).attr "hallo-size"
-          widget.options.editable.execute "formatBlock", size
+      buttonize = (format) =>
+        buttonHolder = jQuery ''
+        buttonHolder.hallobutton
+          label: format
+          editable: @options.editable
+          command: command
+          commandValue: (if ie then "<#{format}>" else format)
+          uuid: @options.uuid
+          cssClass: @options.buttonCssClass
+          queryState: (event) ->
+            try
+              value = document.queryCommandValue command
+              if ie
+                map = { p: "normal" }
+                for val in [1,2,3,4,5,6]
+                  map["h#{val}"] = val
+                compared = value.match(new RegExp(map[format],"i"))
+              else
+                compared = value.match(new RegExp(format,"i"))
+              buttonHolder.hallobutton('checked', if compared then true else false)
+            catch e
+              return
+        buttonHolder.find('button .ui-button-text').text(format.toUpperCase())
+        buttonset.append buttonHolder

-      buttonize header for header in @options.headers
-
-      buttonset.buttonset()
-
-      @element.on "keyup paste change mouseup", (event) ->
-        try
-          format = document.queryCommandValue("formatBlock").toUpperCase()
-        catch e
-          format = ''
-
-        if format is "P"
-          selectedButton = jQuery("##{widget.options.uuid}-paragraph")
-        else if matches = format.match(/\d/)
-          formatNumber = matches[0]
-          selectedButton = jQuery("##{widget.options.uuid}-#{formatNumber}")
-
-        labelParent = jQuery(buttonset)
-        labelParent.children("input").attr "checked", false
-        labelParent.children("label").removeClass "ui-state-clicked"
-        labelParent.children("input").button("widget").button "refresh"
-
-        if selectedButton
-          selectedButton.attr "checked", true
-          selectedButton.next("label").addClass "ui-state-clicked"
-          selectedButton.button "refresh"
-
-       toolbar.append buttonset
+      for format in @options.formatBlocks
+        buttonize format
+
+      buttonset.hallobuttonset()
+      toolbar.append buttonset
 )(jQuery)


webapp/latex: support for *.Rnw knitr files (like sagetex, but for R)

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -117,6 +117,7 @@
     pyx    : 'python'
     r      : 'r'
     rmd    : 'gfm2'
+    rnw    : 'stex2'
     rst    : 'rst'
     rb     : 'text/x-ruby'
     ru     : 'text/x-ruby'
@@ -172,6 +173,11 @@
 #    icon   : 'fa-file-code-o'
 #    opts   : {indent_unit:4, tab_size:4, mode:'stex2'}

+file_associations['rnw'] =
+    editor : 'latex'
+    icon   : 'fa-file-excel-o'
+    opts   : {mode:'stex2', indent_unit:4, tab_size:4}
+    name   : "Knitr LaTeX"

 file_associations['html'] =
     editor : 'html-md'
@@ -1903,6 +1909,7 @@
         @project_id = opts.project_id
         @filename   = opts.filename
         @image_type = opts.image_type
+        @ext = misc.filename_extension_notilde(@filename)?.toLowerCase()

         @_pages     = {}
         @num_pages  = 0
@@ -1911,8 +1918,12 @@
         @path = s.head
         if @path == ''
             @path = './'
-        @filename_tex  = s.tail
-        @base_filename = @filename_tex.slice(0, @filename_tex.length-4)
+        if @ext == 'rnw'
+            @filename_tex = misc.change_filename_extension(s.tail, 'tex')
+            @filename_rnw = s.tail
+        else
+            @filename_tex  = s.tail
+        @base_filename = misc.separate_file_extension(@filename_tex).name
         @filename_pdf  = @base_filename + '.pdf'

     dbg: (mesg) =>
@@ -2060,6 +2071,7 @@
         if not opts.latex_command?
             opts.latex_command = @default_tex_command()
         @_need_to_run =
+            knitr  : @ext == 'rnw'
             latex  : true   # initially, only latex is true
             sage   : false  # either false or a filename
             bibtex : false
@@ -2100,7 +2112,18 @@
             else
                 cb()

+        task_knitr = (cb) =>
+            if @_need_to_run.knitr
+                status?(start:'knitr')
+                @_run_knitr (err, _log) =>
+                    status?(end:'knitr', log:_log)
+                    log += _log
+                    cb(err)
+            else
+                cb()
+
         async.series([
+            task_knitr,
             task_latex,
             task_sage,
             task_bibtex,
@@ -2192,6 +2215,19 @@
             args    : [@base_filename]
             timeout : 10
             cb      : (err, output) =>
+                if err
+                    cb?(err)
+                else
+                    log = output.stdout + '\n\n' + output.stderr
+                    @_need_to_run.latex = true
+                    cb?(false, log)
+
+    _run_knitr: (cb) =>
+        @_exec
+            command  : "echo 'require(knitr); knit(\"#{@filename_rnw}\")' | R --no-save"
+            bash     : true
+            timeout  : 60
+            cb       : (err, output) =>
                 if err
                     cb?(err)
                 else
@@ -3165,7 +3201,7 @@

     # Editors for private normal editable files.
     register(false, HTML_MD_Editor,   html_md_exts)
-    register(false, LatexEditor,      ['tex'])
+    register(false, LatexEditor,      ['tex', 'rnw'])
     register(false, Terminal,         ['term', 'sage-term'])
     register(false, Media,            ['png', 'jpg', 'jpeg', 'gif', 'svg'].concat(VIDEO_EXTS))


Clarified comment

Clarified comment

--- core/app/backbone/initializers/site_initializer.coffee
+++ core/app/backbone/initializers/site_initializer.coffee
@@ -59,5 +59,5 @@

 refreshOnSocialSignin = ->
   currentSession.on 'user_refreshed', ->
-    # We still have some static user-dependent stuff on the site (not client)
+    # Top bar is still static and user-dependent
     window.location.reload(true)


Add random size to make bigger blueprints

--- src/generator.coffee
+++ src/generator.coffee
@@ -1,6 +1,7 @@
 FactoryGirl  = require 'factory_girl'
 faker        = require 'faker'
 indentString = require 'indent-string'
+async        = require 'async'

 FactoryGirl.define 'user', ->
   @id = Math.random() * 101|0
@@ -9,6 +10,11 @@

 user = FactoryGirl.create 'user'

+debug = false
+
+randomIntInc = (low, high) ->
+  Math.floor(Math.random() * (high - low + 1) + low)
+
 createMeta = ->
   "FORMAT: 1A\n"

@@ -16,33 +22,48 @@
   "# #{faker.name.findName()}\n"

 createGroup = (size) ->
-  "# Group #{faker.internet.userName()}\n"
+  output = ''
+  console.log "Group Size: #{size}" if debug
+  for i in [1..size]
+    output += "# Group #{faker.internet.userName()}\n"
+    endpointSize = Math.random()*10|0
+    output += createEndpointWithResponse(endpointSize)
+  output
+
+createEndpointWithResponse = (size) ->
+  output = ''
+  for i in [1..size]
+    output += "#{createEndpoint()}"
+    output += "#{createResponse()}"
+  output

 createEndpoint = ->
   "## #{faker.address.country()} [/#{faker.internet.userName().toLowerCase()}]\n"
-

 createResponse = (code = 200, method = 'GET') ->
   """
   ### #{faker.internet.domainWord()} [#{method}]
   + Response #{code} (application/json)

-  #{createBody()}
-
+  #{createJsonBody()}
+  \n
   """

-createBody = ->
+createJsonBody = ->
   string = JSON.stringify faker.helpers.createCard(), ' ', 2
   indentString string, ' ', 8

+createBody = ->
+  string = faker.lorem.paragraph
+  indentString string, ' ', 8

 createBlueprint = ->
+  groupSize = randomIntInc 1,3
+
   """
   #{createMeta()}
   #{createApiName()}
-  #{createGroup()}
-  #{createEndpoint()}
-  #{createResponse()}
+  #{createGroup(groupSize)}
   """

 module.exports = createBlueprint


activity: improve syntax

activity: improve syntax

--- client/activity/lib/components/topicchatpane/index.coffee
+++ client/activity/lib/components/topicchatpane/index.coffee
@@ -18,7 +18,9 @@

   getDataBindings: ->
+    return {
       messages: ActivityFlux.getters.selectedChannelThreadMessages
+    }

   componentDidMount: ->


test(viewService): urls and trailing slashes in getDirection method

--- modules/services/view/test/index.coffee
+++ modules/services/view/test/index.coffee
@@ -23,13 +23,14 @@

   describe 'getDirection', ->

+    # using state names
     it 'should detect normal direction using state name strings', ->
       expect(viewService.getDirection 'home', 'second').toBe 'normal'

     it 'should detect reverse direction using state name strings', ->
       expect(viewService.getDirection 'second', 'home').toBe 'reverse'

-    it 'should detct normal using state name properties', ->
+    it 'should detect normal direction using state names in properties', ->
       expect(viewService.getDirection
         from: 'home'
         to: 'second'
@@ -41,7 +42,44 @@
         to: 'home'
       ).toBe 'reverse'

-    it 'should detect normal direction using only one state name property', ->
+    it 'should detect none direction from "^" url', ->
+      state.transitionTo 'home'
       expect(viewService.getDirection
         to: 'second'
+      ).toBe 'none'
+
+
+    # using urls
+    it 'should detect normal direction using url strings', ->
+      expect(viewService.getDirection '/home', '/home/second').toBe 'normal'
+
+    it 'should detect reverse direction using url strings', ->
+      expect(viewService.getDirection '/home/second', '/home').toBe 'reverse'
+
+    it 'should detect normal direction using urls in properties', ->
+      expect(viewService.getDirection
+        from: '/home'
+        to: '/home/second'
       ).toBe 'normal'
+
+    it 'should detect reverse direction using urls in properties', ->
+      expect(viewService.getDirection
+        from: '/home/second'
+        to: '/home'
+      ).toBe 'reverse'
+
+    it 'should detect none direction using "equal" URLs', ->
+      expect(
+        viewService.getDirection '/home/third', '/home/second'
+      ).toBe 'none'
+
+    it 'should detect none direction from "^" url', ->
+      state.transitionTo 'home'
+      expect(viewService.getDirection
+        to: '/second'
+      ).toBe 'none'
+
+    it 'should not care about trailing slashes', ->
+      expect(viewService.getDirection '/home/', '/home/second').toBe 'normal'
+      expect(viewService.getDirection '/home', '/home/second/').toBe 'normal'
+      expect(viewService.getDirection '/home/', '/home/second/').toBe 'normal'


Correct code comments for handler.proxy

Correct code comments for handler.proxy

--- src/tb/lib/ti/events.coffee
+++ src/tb/lib/ti/events.coffee
@@ -41,10 +41,9 @@

   handler.fn = fn

-  # Titanium handles calls to `apply` differently than the node javascript
-  # engine, so we'll use `call` instead.
   handler.proxy = (e) ->

+    # Make sure events are passed into an array so they can be passed to 'apply'.
     unless _.isArray e
       e = [e]


Fixed #374

Fixed #374


(fix)onboarding: Must pass approval_prompt=force for Google OAuth

Otherwise, if you've ever previously authorized your account against Edgehill's
Google client ID but need to reconnect it, the consent page is bypassed and no
refresh token is returned to the callback URL, breaking the rest of the flow.

--- internal_packages/onboarding/lib/account-choose-page.cjsx
+++ internal_packages/onboarding/lib/account-choose-page.cjsx
@@ -85,6 +85,7 @@
             https://mail.google.com/ \
             https://www.google.com/m8/feeds \
             https://www.googleapis.com/auth/calendar'
+        approval_prompt: 'force'
     })
     shell.openExternal(googleUrl)


Update /pager sup to include multiple assignees

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -460,8 +460,9 @@
                 ""
             else
               ""
-    assigned_to = if inc.assigned_to_user
-                    "- assigned to #{inc.assigned_to_user.name}"
+    assigned_to = if inc.assigned_to
+                    names = inc.assigned_to.map (assignment) -> assignment.object.name
+                    "- assigned to #{names.join(', ')}"
                   else
                     ""


Updated to supported languages as of 20120801.

This updates the supported languages to the ones listed in the [Language reference](https://developers.google.com/translate/v2/using_rest#language-params) as of 20120801.

Specifically it adds:

* Azerbaijani (az)
* Basque (eu)
* Bengali (bn)
* Esperanto (eo
* Georgian (ka)
* Gujarati (gu)
* Haitian Creole (ht)
* Kannada (kn)
* Latin (la)
* Tamil (ta)
* Telugu (te)
* Urdu (ur)

--- src/scripts/translate.coffee
+++ src/scripts/translate.coffee
@@ -9,6 +9,9 @@
   "af": "Afrikaans",
   "sq": "Albanian",
   "ar": "Arabic",
+  "az": "Azerbaijani",
+  "eu": "Basque",
+  "bn": "Bengali",
   "be": "Belarusian",
   "bg": "Bulgarian",
   "ca": "Catalan",
@@ -19,13 +22,17 @@
   "da": "Danish",
   "nl": "Dutch",
   "en": "English",
+  "eo": "Esperanto",
   "et": "Estonian",
   "tl": "Filipino",
   "fi": "Finnish",
   "fr": "French",
   "gl": "Galician",
+  "ka": "Georgian",
   "de": "German",
   "el": "Greek",
+  "gu": "Gujarati",
+  "ht": "Haitian Creole",
   "iw": "Hebrew",
   "hi": "Hindi",
   "hu": "Hungarian",
@@ -34,7 +41,9 @@
   "ga": "Irish",
   "it": "Italian",
   "ja": "Japanese",
+  "kn": "Kannada",
   "ko": "Korean",
+  "la": "Latin",
   "lv": "Latvian",
   "lt": "Lithuanian",
   "mk": "Macedonian",
@@ -52,9 +61,12 @@
   "es": "Spanish",
   "sw": "Swahili",
   "sv": "Swedish",
+  "ta": "Tamil",
+  "te": "Telugu",
   "th": "Thai",
   "tr": "Turkish",
   "uk": "Ukranian",
+  "ur": "Urdu",
   "vi": "Vietnamese",
   "cy": "Welsh",
   "yi": "Yiddish"


d850d878621f3c14e75d8f5120dba26f9c3f4ba4 fix

[#97184290]

--- review_front/app/components/commit-github-button.coffee
+++ review_front/app/components/commit-github-button.coffee
@@ -1,35 +1,35 @@
 `import Ember from 'ember'`

 CommitGithubButton = Ember.Component.extend
-  classNames: ['btn-group', 'btn-group-xs', 'commit-action-buttons']
+  classNames: ["btn-group", "btn-group-xs", "commit-action-buttons"]
   COMMIT_PREVIEW = { width: 1024, height: 768 }
-  url: Ember.computed.oneWay('commit.remoteUrl')
+  url: Ember.computed.oneWay("commit.remoteUrl")

   showCommitInModal: ()->
-    url = @get('url')
+    url = @get("url")

     left = screen.width / 2 - COMMIT_PREVIEW.width / 2 + screen.availLeft
     top = screen.height / 2 - COMMIT_PREVIEW.height / 2 + screen.availTop

-    commit_prev = window.open(url, 'commit_preview', "width=#{COMMIT_PREVIEW.width},
+    commit_prev = window.open(url, "commit_preview", "width=#{COMMIT_PREVIEW.width},
       height=#{COMMIT_PREVIEW.height}, top=#{top}, left=#{left}")
     commit_prev.focus()

   changeCommitStateTo: (state)->
-    commit = @get('commit')
-    currentUser = @get('current_user')
-    commitAuthor = @get('commit.author')
+    commit = @get("commit")
+    currentUser = @get("current_user")
+    commitAuthor = @get("commit.author")

-    return if commitAuthor.get('name') == currentUser.get('name')
+    return if commitAuthor.get("name") == currentUser.get("name")

-    commit.set('state', state)
-    commit.set('reviewer', currentUser).save()
+    commit.set("state", state)
+    commit.set("reviewer", currentUser).save()

   actions:
     viewCommit: ()-> @showCommitInModal()
-    acceptCommit: ()-> @changeCommitStateTo('accepted')
-    passCommit: ()-> @changeCommitStateTo('passed')
-    rejectCommit: ()-> @changeCommitStateTo('rejected')
+    acceptCommit: ()-> @changeCommitStateTo("accepted")
+    passCommit: ()-> @changeCommitStateTo("passed")
+    rejectCommit: ()-> @changeCommitStateTo("rejected")

 `export default CommitGithubButton`


chat ticket: boxFade: auto adjust height

--- app/assets/javascripts/app/controllers/layout_ref.coffee
+++ app/assets/javascripts/app/controllers/layout_ref.coffee
@@ -2194,7 +2194,6 @@
     super
     @render()
     @scrollToBottom()
-    @boxFade.height @chatBox.outerHeight()
     @placeBoxFade()

   render: ->
@@ -2204,6 +2203,7 @@
     @scrollHolder.scrollTop(@scrollHolder.prop('scrollHeight'))

   placeBoxFade: =>
+    @boxFade.height @chatBox.outerHeight()
     y1 = @attachments.offset().top - @boxFade.offset().top

     @boxFade.html App.view('layout_ref/boxFade')


support relationship links without data

support relationship links without data

--- src/yayson/presenter.coffee
+++ src/yayson/presenter.coffee
@@ -55,9 +55,9 @@
             id: @constructor.adapter.id d
             type: presenter::type
         build = (d) =>
-          rel =
-            data:
-              buildData(d)
+          rel = {}
+          if d?
+            rel.data = buildData(d)
           if links[key]?
             rel.links = buildLinks links[key]
           rel
@@ -65,10 +65,8 @@
         relationships[key] ||= {}
         relationships[key]= if data instanceof Array
           data: data.map buildData
-        else if data?
+        else
           build data
-        else
-          null
       relationships

     buildSelfLink: (instance) ->
@@ -127,5 +125,4 @@
       (new this).render arguments...

-  module.exports = Presenter
-
+  module.exports = Presenter


webapp/editor: Cannot read property getCursor of undefined

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -1827,6 +1827,8 @@

         update_context_sensitive_bar = () =>
             cm = @focused_codemirror()
+            if not cm?
+                return
             pos = cm.getCursor()
             name = cm.getModeAt(pos).name
             #console.log("update_context_sensitive_bar, pos=#{misc.to_json(pos)}, name=#{name}")


added error logger when transactionId does not exist

--- src/middleware/messageStore.coffee
+++ src/middleware/messageStore.coffee
@@ -102,7 +102,7 @@
 exports.storeNonPrimaryResponse = (ctx, routeObject, done) ->
   # check if channel response body is false and remove
   if ctx.authorisedChannel.responseBody == false
-    response.response.body = ''
+    routeObject.response.body = ''

   if ctx.transactionId?
     transactions.Transaction.findByIdAndUpdate ctx.transactionId, {$push: { "routes": routeObject } } , (err,tx) ->
@@ -110,6 +110,8 @@
       if err
         logger.error err
       done tx
+  else
+    logger.error "the request has no transactionId"

 exports.setFinalStatus = setFinalStatus = (ctx, callback) ->


10 seconds instead

10 seconds instead

--- src/flow-deploy-model.coffee
+++ src/flow-deploy-model.coffee
@@ -140,7 +140,7 @@
       @sendMessage flow, 'delete', (error) =>
         _.delay =>
           meshbluHttp.update @flowId, stopping: false
-        , 30000
+        , 10000
         callback error

 module.exports = FlowDeployModel


added tooltips to buttons. close #5

added tooltips to buttons. close #5

--- src/ui/views/controls.coffee
+++ src/ui/views/controls.coffee
@@ -11,15 +11,19 @@
     {conv, viewstate} = models
     c = conv[viewstate.selectedConv]
     div class:'controls', ->
-        div class:'button', onclick:onclickaction('togglenotif'), ->
+        div class:'button', title:'Toggle notifications', onclick:onclickaction('togglenotif'), ->
             if conv.isQuiet(c)
                 span class:'icon-bell-off-empty'
             else
                 span class:'icon-bell'
-        div class:'button', onclick:onclickaction('convsettings'), -> span class:'icon-cog'
+        div class:'button', title:'Conversation settings',
+            onclick:onclickaction('convsettings'), -> span class:'icon-cog'
         if c?.type?.indexOf('ONE_TO_ONE') > 0
-            div class:'button', onclick:onclickaction('deleteconv'), -> span class:'icon-cancel'
+            div class:'button', title:'Delete conversation',
+            onclick:onclickaction('deleteconv'), -> span class:'icon-cancel'
         else
-            div class:'button', onclick:onclickaction('leaveconv'), -> span class:'icon-cancel'
+            div class:'button', title:'Leave conversation',
+            onclick:onclickaction('leaveconv'), -> span class:'icon-cancel'
         div class:'fill'
-        div class:'button', onclick:onclickaction('addconversation'), -> span class:'icon-plus'
+        div class:'button', title:'Add new conversation',
+            onclick:onclickaction('addconversation'), -> span class:'icon-plus'


Publish all tests at once

Publish all tests at once

--- test/appveyor.coffee
+++ test/appveyor.coffee
@@ -41,7 +41,7 @@
   for k, v of events
     do (v)->
       runner.on k, (test)->
-        post
+        tests.push
           testFramework: 'mocha'
           testName: test.fullTitle()
           fileName: path.relative '', test.file
@@ -49,4 +49,6 @@
           durationMilliseconds: test.duration
           ErrorMessage: test.err?.message
           ErrorStackTrace: test.err?.stack
-          '/api/tests'
+
+  runner.on 'end', ->
+    post tests, '/api/tests/batch'


comment support for hipchat

comment support for hipchat

--- plugins/hipchat/index.coffee
+++ plugins/hipchat/index.coffee
@@ -16,7 +16,11 @@
         error: event.error
         spiking: event.trigger.type == 'projectSpiking'
         rate: event.trigger.rate
+        comment: event.comment
+        user: event.user

+      if details.comment.message
+        details.comment.message = details.comment.message.truncate(80)

     else

@@ -59,15 +63,20 @@
       callback(res.error)

   @render: Handlebars.compile(
-    '{{#if spiking}}' +
-      'Spike of {{rate}} exceptions/minute in {{project.name}}
' +
-      'Most recent error: {{error_string}} (details)' +
+    '{{#if comment}}' +
+      '{{user.name}} commented on {{error_string}} (details)' +
+      '
   "{{comment.message}}"' +
     '{{else}}' +
-      '{{title}} from {{project.name}}' +
-      '{{#if error}}' +
-        ' in {{error.context}} (details)' +
-        '
   {{error_string}}' +
-        '{{#if stack_trace_line}}
   {{stack_trace_line}}{{/if}}' +
+      '{{#if spiking}}' +
+        'Spike of {{rate}} exceptions/minute in {{project.name}}
' +
+        'Most recent error: {{error_string}} (details)' +
+      '{{else}}' +
+        '{{title}} from {{project.name}}' +
+        '{{#if error}}' +
+          ' in {{error.context}} (details)' +
+          '
   {{error_string}}' +
+          '{{#if stack_trace_line}}
   {{stack_trace_line}}{{/if}}' +
+        '{{/if}}' +
       '{{/if}}' +
     '{{/if}}'
   )


Remove tagging in update

Remove tagging in update

Don't need it anymore, maybe never did...

--- lib/git.coffee
+++ lib/git.coffee
@@ -167,8 +167,6 @@
     .then () ->
       commit opts.repo, opts.user, opts.message
     .then (oid) ->
-      tag opts.repo, oid
-    .then (tag) ->
       push opts.repo, opts.ref, opts.ref
     .then () ->
       callback null


Testing objectid equivalence fixed

Testing objectid equivalence fixed

--- test/lib_test.coffee
+++ test/lib_test.coffee
@@ -47,7 +47,7 @@
                 console.log err if err

                 Player.findOne().where('name', 'albireox').exec (err, albireox) ->
-                  game.rankings[0].player.should.equal albireox
+                  game.rankings[0].player.toString().should.equal albireox._id.toString()
                   done()

   after (done) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -81,6 +81,7 @@
 @returns {String} File extension
 ###
 String::extension = ->
+  if
   return this.match(/\.([^\.]*)$/, '').last() || '';

 ###*


Fixed import paths

Fixed import paths

--- lib/dub-config.coffee
+++ lib/dub-config.coffee
@@ -32,7 +32,7 @@
 	getImports: (config) ->
 		imports = atom.config.get("atomize-d.dImportPaths")

-		imports.push.apply @config?.importPaths or "source/"
-		imports.push.apply @config.configurations[config].importPaths if @config?.configurations?[config]?.importPaths
+		imports.push.apply imports, @config?.importPaths or "source/"
+		imports.push.apply imports, @config.configurations[config].importPaths if @config?.configurations?[config]?.importPaths

 		return imports


Don't show follow button until state determined

--- assets/javascripts/views/profile_follow_button.js.coffee
+++ assets/javascripts/views/profile_follow_button.js.coffee
@@ -8,12 +8,15 @@
     @$entity = ($ '[name=entity]', @$el)
     @entity = @$entity.val()

+    @hide()
+
     @setFollowing() if @$el.attr('data-following') == 'true'
     unless @is_following
       @current_entity = @parentView.entity
       if @entity == TentStatus.config.current_entity.toStringWithoutSchemePort()
         @buttons.submit.attr 'disabled', 'disabled'
         @buttons.submit.val 'You'
+        @show()
       else
         new HTTP 'GET', "#{TentStatus.config.tent_api_root}/followings", {
           entity: @entity
@@ -46,9 +49,18 @@
     @buttons.submit.val 'Unfollow'
     @buttons.submit.removeClass('btn-success').addClass('btn-danger')
     @buttons.submit.removeAttr 'disabled'
+    @show()

   unsetFollowing: =>
     @is_following = false
     @buttons.submit.val 'Follow'
     @buttons.submit.removeClass('btn-danger').addClass('btn-success')
     @buttons.submit.removeAttr 'disabled'
+    @show()
+
+  show: =>
+    @$el.show()
+
+  hide: =>
+    @$el.hide()
+


Relaxed a test range.

Relaxed a test range.

It turns out that the range I had here yielded a fairly high p-value, i.e., it was likely to "fail" fairly often just through random chance. So I relaxed the range some to reduce the number of false negatives.

--- src/test/nesting_spec.coffee
+++ src/test/nesting_spec.coffee
@@ -341,7 +341,7 @@
           When "eggs hatch", ->
             newBirds = nesting.hatchEggs()
           Then "there should be about #{numBirds} new birds", ->
-            newBirds.length.should.be.approximately(numBirds, 0.33 * numBirds)
+            newBirds.length.should.be.approximately(numBirds, 0.5 * numBirds)
           And "#{numEarlyBirds} of those birds should be captive reared", ->
             captiveReared = newBirds.filter((b) -> b.isCaptive())
             numCaptiveReared = captiveReared.length


comment changes -- and removed prop that was stubbed, active, but not used

--- src/art/engine/core/element.coffee
+++ src/art/engine/core/element.coffee
@@ -218,7 +218,7 @@
       preprocess: (v, oldValue) -> if v instanceof PointLayoutBase then v else new PointLayout v, oldValue

     ###
-    TODO: Update StateEpochLayout to use this.
+    TODO: Update StateEpochLayout to use: childrenSizePreprocessor

     How do we want to handle currentPadding?
       - is it always set; gut: yes
@@ -237,10 +237,11 @@

           childrenSizePreprocessor(...).add currentPadding.getWidth(), currentPadding.getHeight()
           # note, this only creates a second point if there is non-zero padding.
-    ###
+
     childrenSizePreprocessor:
       default: (left, top, right, bottom) -> point right, bottom
       validate: (v) -> isFunction v
+    ###

     location:
       default: 0


shorter code

shorter code

--- js/umobi.page.coffee
+++ js/umobi.page.coffee
@@ -104,10 +104,8 @@
             AdjustContentHeight = (e) ->
               # console.log "pagereveal" , h.height(), f.height()
               contentHeight = $(window).height()
-              contentTop    = 0
-              contentBottom = 0
-              contentTop    = h.height() if h.get(0)
-              contentBottom = f.height() if f.get(0)
+              contentTop    = if h.get(0) then h.height() else 0
+              contentBottom = if f.get(0) then f.height() else 0
               $contentContainer.css
                 position: 'absolute'
                 top: contentTop + 'px'


Dispatch locationchange event on history changes

--- app/main.cjsx
+++ app/main.cjsx
@@ -10,6 +10,9 @@
 if process.env.NON_ROOT isnt 'true' and window.location? and window.location.hash isnt ""
   window.location.pathname = window.location.hash.slice(1)

+history.listen (location) ->
+  window.dispatchEvent new CustomEvent 'locationchange'
+
 location = if process.env.NON_ROOT == "true"
     null
   else


Clarify some output

Clarify some output

--- picksel.coffee
+++ picksel.coffee
@@ -296,7 +296,8 @@
   newUser =
     apiKey: ''

-  console.log 'Let\'s associate a Pixabay account with this project...'
+  console.log 'Let\'s associate a Pixabay account with your local copy of' \
+    + ' this project...'

   apiKey = readline.question 'What\'s your Pixabay API key? To find it you' \
     + ' can log in to the Pixabay website and visit: ' \
@@ -308,7 +309,8 @@
   persistUser()

   log.info "New file created at '#{USER_PATH}' containing your API key." \
-    + " DON'T CHECK THIS FILE IN TO SOURCE CONTROL."
+    + " DON'T CHECK THIS FILE IN TO SOURCE CONTROL BECAUSE IT HAS YOUR" \
+    + " SECRET API KEY IN IT."

 # Prints usage information for the application.


fucking knocks you down two karma points

--- scripts/karma.coffee
+++ scripts/karma.coffee
@@ -37,11 +37,19 @@
     @cache[thing] -= 1
     @robot.brain.data.karma = @cache

+  doubleDecrement: (thing) ->
+    @cache[thing] ?= 0
+    @cache[thing] -= 2
+    @robot.brain.data.karma = @cache
+
   incrementResponse: ->
      @increment_responses[Math.floor(Math.random() * @increment_responses.length)]

   decrementResponse: ->
      @decrement_responses[Math.floor(Math.random() * @decrement_responses.length)]
+
+  doubleDecrementResponse: ->
+     'Yeah, Fuck'

   get: (thing) ->
     k = if @cache[thing] then @cache[thing] else 0
@@ -94,4 +102,8 @@
     match = msg.match[1].toLowerCase()
     if match != "best" && match != "worst"
       msg.send "\"#{match}\" has #{karma.get(match)} karma."
-  +
+  robot.hear /(fucking|fuckin'?) (.*)/i, (msg) ->
+    subject = msg.match[2].toLowerCase()
+    karma.doubleDecrement subject
+    msg.send "#{karma.doubleDecrementResponse()} #{subject} (Karma: #{karma.get(subject)})"


Updated HelpTool redirect URL to include a section reference

--- bokehjs/src/coffee/models/tools/actions/help_tool.coffee
+++ bokehjs/src/coffee/models/tools/actions/help_tool.coffee
@@ -18,7 +18,7 @@
     ]
     redirect:     [
       p.String
-      'http://bokeh.pydata.org/en/latest/docs/user_guide/tools.html'
+      'http://bokeh.pydata.org/en/latest/docs/user_guide/tools.html#built-in-tools'
     ]
   }


Use root atom folder in bin folder path

Use root atom folder in bin folder path

--- src/browser/squirrel-update.coffee
+++ src/browser/squirrel-update.coffee
@@ -4,7 +4,7 @@
 path = require 'path'

 rootAtomFolder = path.resolve(process.execPath, '..', '..')
-binFolder = path.resolve(process.execPath, 'bin')
+binFolder = path.join(rootAtomFolder, 'bin')
 updateDotExe = path.join(rootAtomFolder, 'Update.exe')
 exeName = path.basename(process.execPath)


js problem was hidding hamburguer menu

js problem was hidding hamburguer menu

--- src/ui/views/listhead.coffee
+++ src/ui/views/listhead.coffee
@@ -1,7 +1,7 @@
 module.exports = view (models) ->
 	div class:'listheadlabel', ->
 		if process.platform isnt 'darwin'
-			button title: i18n.__ 'Menu', onclick: togglemenu, ->
+			button title: i18n.__('Menu'), onclick: togglemenu, ->
 				i class:'material-icons', "menu"
 		span i18n.__("Conversations")


Add more argument checks for simple channel

--- src/channels/simple_channel.coffee
+++ src/channels/simple_channel.coffee
@@ -44,6 +44,12 @@
       @direction ? directions.null

+  assertSingleArgument: (count) ->
+    if count != 1
+      throw new Error "Single argument expected, got #{count} instead"
+    return this
+
+
   assertSource: (source) ->
     unless source?.getNodeSource?
       throw new Error "#{inspect source} is not a valid source node"
@@ -51,6 +57,7 @@

   fromSource: (source) ->
+    @assertSingleArgument(arguments.length)
     @assertSource(source)
     @sources.push source
     return this
@@ -65,6 +72,7 @@

   fromDynamicSources: (sources) ->
+    @assertSingleArgument(arguments.length)
     for source in sources
       @assertSource(source)
       @sources.push source
@@ -85,6 +93,7 @@

   toTarget: (target) ->
+    @assertSingleArgument(arguments.length)
     @assertTarget(target)
     @targets.push target
     return this
@@ -99,6 +108,7 @@

   toDynamicTargets: (targets) ->
+    @assertSingleArgument(arguments.length)
     for target in targets
       @assertTarget(target)
       @targets.push target
@@ -114,6 +124,7 @@

   toConnectionTarget: (connectionTarget) ->
+    @assertSingleArgument(arguments.length)
     @assertConnectionTarget(connectionTarget)
     @connectionTargets.push connectionTarget
     return this


initial registry recreation

initial registry recreation

--- src/mist-ninja-builder.coffee
+++ src/mist-ninja-builder.coffee
@@ -8,5 +8,18 @@
  #             MIST BUILD SYSTEM
  # Copyright (c) 2015 On Demand Solutions, inc.

+path = require 'path'
+
 module.exports = class MistNinjaBuilder
+  construct: (@rootDir, @mistDir)->
+    @reg =
+      rules: {}
+      vars: [
+        ['ninja_required_version', '1.5.0']
+        ['builddir', path.join @rootDir, '.mist']
+      ]
+      groups: {}
+      targets: []

+  render: -> ''
+  run: (exArgs = [])->


MongodbMixin trackdown the new mongodb version changes

--- src/mixin/MongodbMixin.coffee
+++ src/mixin/MongodbMixin.coffee
@@ -44,7 +44,7 @@
       db: db

     if typeof db == 'string'
-      (target._mongo.whenConnected = mongo.MongoClient.connectAsync db)
+      (target._mongo.whenConnected = mongo.connectAsync db)
         .then (db) ->
           target._mongo.db = db
           target.whenFinished().then -> target._mongo.db.close()
@@ -53,11 +53,6 @@

     _wrapMethod target, name for name in _wrappedMethods
     _wrapFind target
-
-    target.setGlobalDefaultMaxBsonSize = (size) ->
-     require('mongodb').Connection.DEFAULT_MAX_BSON_SIZE = size
-     require('mongodb').Connection.DEFAULT_MAX_MESSAGE_SIZE = size
-     @

     target.db = ->
       @_mongo.db


single parts should definitely render footers as passed in

--- src/components/exercise/index.cjsx
+++ src/components/exercise/index.cjsx
@@ -50,7 +50,7 @@
       focus: true
       includeGroup: true

-    partProps.footer = footer if canOnlyContinue(part.id)
+    partProps.footer = footer

     @renderPart(part, partProps)


added spinner to inspector save button

added spinner to inspector save button

--- app/assets/javascripts/lib/nypl_inspector.coffee
+++ app/assets/javascripts/lib/nypl_inspector.coffee
@@ -171,8 +171,8 @@
           t: type
           f: data
         success: () ->
+          inspector.showNextPolygon()
           inspector.hideSpinner()
-          inspector.showNextPolygon()
       )

   showSpinner: () ->


Fix countAll().

Fix countAll().

--- app/assets/javascripts/pods/pods_store.js.coffee
+++ app/assets/javascripts/pods/pods_store.js.coffee
@@ -30,7 +30,7 @@
         r = s.put(pod)
   countAll: () ->
     promise = new Promise (resolve, reject) =>
-      @database.then (db) ->
+      @database().then (db) ->
         t = db.transaction 'pods', 'readonly'
         s = t.objectStore('pods')
         r = s.count()


Rename AsyncAction setTimeout to withTimeout.

--- src/Witness/_witness/Scripts/witness/AsyncAction.coffee
+++ src/Witness/_witness/Scripts/witness/AsyncAction.coffee
@@ -9,7 +9,7 @@
 	constructor: (@func, @args = [], @description, @timeout = AsyncAction.defaultTimeout) ->
 		@on = Event.define "running", "passed", "failed"

-	setTimeout: (timeout) ->
+	withTimeout: (timeout) ->
 		@timeout = timeout
 		return this


activity: remove unused view from topicchatview

--- client/activity/lib/components/topicchatpane/view.coffee
+++ client/activity/lib/components/topicchatpane/view.coffee
@@ -21,12 +21,3 @@
     <TopicChatPane channel={@data} />

-
-class ChatView extends ReactView
-
-  constructor: (options = {}, data) ->
-    options.cssClass = 'ChatView'
-    super options, data
-
-
-


Performance - Check line visible before the regex.

--- lib/jumpy-view.coffee
+++ lib/jumpy-view.coffee
@@ -102,28 +102,28 @@
             isScreenRowVisible = (lineNumber) ->
                 return lineNumber > editorView.getFirstVisibleScreenRow() &&
                     lineNumber < editorView.getLastVisibleScreenRow()
+
             for line, lineNumber in editorView.getEditor().buffer.lines
-                continue if line == ''
+                continue if line == '' || !isScreenRowVisible lineNumber + 1
                 while ((word = wordsPattern.exec(line)) != null)
-                    if isScreenRowVisible lineNumber + 1
-                        keyLabel = nextKeys.shift()
-                        position = {row: lineNumber, column: word.index}
-                        # creates a reference:
-                        @allPositions[keyLabel] = {
-                            editor: editorId
-                            position: position
-                        }
-                        pixelPosition = editorView
-                            .pixelPositionForBufferPosition [lineNumber,
-                            word.index]
-                        labelElement =
-                            $("
#{keyLabel}
")
-                                .css {
-                                    left: pixelPosition.left
-                                    top: pixelPosition.top
-                                }
-                        $labels
-                            .append labelElement
+                    keyLabel = nextKeys.shift()
+                    position = {row: lineNumber, column: word.index}
+                    # creates a reference:
+                    @allPositions[keyLabel] = {
+                        editor: editorId
+                        position: position
+                    }
+                    pixelPosition = editorView
+                        .pixelPositionForBufferPosition [lineNumber,
+                        word.index]
+                    labelElement =
+                        $("
#{keyLabel}
")
+                            .css {
+                                left: pixelPosition.left
+                                top: pixelPosition.top
+                            }
+                    $labels
+                        .append labelElement
         console.timeEnd('toggle')

     clear: ->


Implement Pay Day message.

Implement Pay Day message.

--- data/bw/moves.coffee
+++ data/bw/moves.coffee
@@ -488,6 +488,10 @@
     user.currentHP = 0
     target.boost(attack: -2, specialAttack: -2)

+extendMove 'pay-day', ->
+  @afterSuccessfulHit = (battle, user, target) ->
+    battle.message "Coins were scattered everywhere!"
+
 extendMove 'psywave', ->
   @calculateDamage = (battle, user, target) ->
     fraction = battle.rng.randInt(5, 15) / 10


Always use global rootView object

Always use global rootView object

This removes the last few places where rootView was
looked up via jQuery selector and instead just uses
the rootView property available on the window.

--- lib/tag-reader.coffee
+++ lib/tag-reader.coffee
@@ -11,7 +11,7 @@
   word = editor.getTextInRange(editor.getCursor().getCurrentWordBufferRange())
   return [] unless word.length > 0

-  tagsFile = @getTagsFile(editor.rootView().project)
+  tagsFile = @getTagsFile(rootView.project)
   return [] unless tagsFile

   $tags.find(tagsFile, word) or []


Remove -khtml-border-radius too

Remove -khtml-border-radius too

--- data/prefixes.coffee
+++ data/prefixes.coffee
@@ -48,7 +48,7 @@
 feature require('caniuse-db/features-json/border-radius'), (browsers) ->
   prefix 'border-radius', 'border-top-left-radius', 'border-top-right-radius',
          'border-bottom-right-radius', 'border-bottom-left-radius',
-          mistakes:   ['-ms-', '-o-']
+          mistakes:   ['-khtml-', '-ms-', '-o-']
           transition: true
           browsers:   browsers


Fix . . . -> …

Fix . . . -> …

--- def/de/settings.cson
+++ def/de/settings.cson
@@ -3,7 +3,7 @@
   menu: [
     {
       _label: "Core"
-      value: "Core"
+      value: "Kern"
     }
     {
       _label: "Editor"
@@ -36,17 +36,17 @@
   ]
   "btn-open-config-folder": "Öffne Konfigurations-Ordner"
   sectionHeadings: [
-    {_label: "Core Settings", value: "Core-Einstellungen"}
+    {_label: "Core Settings", value: "Kern-Einstellungen"}
     {_label: "Editor Settings", value: "Editor-Einstellungen"}
     {_label: "System Settings", value: "Systemeinstellungen"}
     {_label: "Keybindings", value: "Tastenkürzel"}
     {_label: "Installed Packages", value: "Installierte Plugins"}
-    {_label: "Choose a Theme", value: "Ein Theme auswählen"}
-    {_label: "Installed Themes", value: "Installierte Themes"}
+    {_label: "Choose a Theme", value: "Ein Thema auswählen"}
+    {_label: "Installed Themes", value: "Installierte Themen"}
     {_label: "Install Packages", value: "Plugin installieren"}
     {_label: "Featured Packages", value: "Vorgestellte Plugins"}
-    {_label: "Install Themes", value: "Themes installieren"}
-    {_label: "Featured Themes", value: "Vorgestellte Themes"}
+    {_label: "Install Themes", value: "Themen installieren"}
+    {_label: "Featured Themes", value: "Vorgestellte Themen}
     {_label: "Available Updates", value: "Verfügbare Aktualisierungen"}
   ]
   subSectionHeadings: [
@@ -55,10 +55,10 @@
     {_label: "Core Packages", value: "Core-Plugins"}
     {_label: "Development Packages", value: "Entwicklungs-Plugins"}
     {_label: "Git Packages", value: "Git-Plugins"}
-    {_label: "Community Themes", value: "Community-Themes"}
-    {_label: "Core Themes", value: "Core-Themes"}
-    {_label: "Development Themes", value: "Entwickler-Themes"}
-    {_label: "Git Themes", value: "Git-Themes"}
+    {_label: "Community Themes", value: "Community-Themen"}
+    {_label: "Core Themes", value: "Kern-Themen"}
+    {_label: "Development Themes", value: "Entwickler-Themen"}
+    {_label: "Git Themes", value: "Git-Themen"}
   ]
   settings: {
     notes: [
@@ -400,7 +400,7 @@
   updates: {
     "check-updates": "Suche nach Aktualisierungen"
     "update-all": "Alle aktualisieren"
-    "checking-updates": "Suche nach Aktualisierungen..."
+    "checking-updates": "Suche nach Aktualisierungen…"
     "all-updated-message": "Alle deine installierten Plugins sind aktuell!"
   }
   install: {


index assignment supports ⍬-s, fixed #52

--- src/vocabulary/squish.coffee
+++ src/vocabulary/squish.coffee
@@ -27,7 +27,7 @@
     if all(for x in subscripts then x.length)
       u = repeat [0], subscripts.length
       p = omega.offset
-      for a in [0...subscripts.length]
+      for a in [0...subscripts.length] by 1
         p += subscripts[a][0] * omega.stride[a]
       loop
         data.push omega.data[p]
@@ -55,10 +55,14 @@
   # 'hello'[1]                          <=> 'e'
   # 'ipodlover'[1 2 5 8 3 7 6 0 4]      <=> 'poordevil'
   # ('axlrose'[4 3 0 2 5 6 1])[0 1 2 3] <=> 'oral'
+  # (1 2 3)[⍬]                          <=> ⍬
+  # ⍴(1 2 3)[1 2 3 0 5⍴0]               <=> 1 2 3 0 5
+  # (⍳3)[]                              <=> ⍳3
+  # ⍴(3 3⍴⍳9)[⍬;⍬]                      <=> 0 0
   #
-  #! " X"[(3 3⍴⍳9)∊1 3 6 7 8] <=> 3 3⍴,/(' X '
-  #! ...                                 'X  '
-  #! ...                                 'XXX')
+  # " X"[(3 3⍴⍳9)∊1 3 6 7 8] <=> 3 3⍴(' X ',
+  # ...                               'X  ',
+  # ...                               'XXX')
   _index: (alphaAndAxes, omega) ->
     [alpha, axes] = alphaAndAxes.toArray()
     squish omega, alpha, axes
@@ -76,6 +80,9 @@
   # a←'this is a test' ⋄ a[0 5]←'TI' <=> 'This Is a test'
   # Data←0 4 8 ⋄ 10+ (Data[0 2]← 7 9) <=> 17 14 19
   # a←3 4⍴⍳12 ⋄ a[;1 2]←99 <=> 3 4⍴0 99 99 3 4 99 99 7 8 99 99 11
+  # a←1 2 3 ⋄ a[⍬]←4 ⋄ a <=> 1 2 3
+  # a←3 3⍴⍳9 ⋄ a[⍬;1 2]←789 ⋄ a <=> 3 3⍴⍳9
+  # a←1 2 3 ⋄ a[]←4 5 6 ⋄ a <=> 4 5 6
   _substitute: (args) ->
     [value, alpha, omega, axes] =
       for x in args.toArray()
@@ -94,7 +101,8 @@

     r = new APLArray omega.toArray(), omega.shape
     p = 0 # pointer in r
-    for a in [0...subscripts.length]
+    for a in [0...subscripts.length] by 1
+      if subscripts[a].length is 0 then return r
       p += subscripts[a][0] * r.stride[a]
     q = value.offset # pointer in value
     u = repeat [0], subscripts.length
@@ -136,7 +144,7 @@
       if not isInt x then domainError()
       if not (0 <= x < omega.shape[axis]) then indexError()

-  for i in [0...subscripts.length] when typeof subscripts[i] is 'undefined'
+  for i in [0...subscripts.length] by 1 when typeof subscripts[i] is 'undefined'
     subscripts[i] = [0...omega.shape[i]]
     subscriptShapes[i] = [omega.shape[i]]


Revert "fix to get extension if link has query params after extension"

--- files.coffee
+++ files.coffee
@@ -1082,7 +1082,7 @@
   ###
   _getExt: (fileName) ->
     if !!~fileName.indexOf('.')
-      extension = fileName.split('.').pop().split('?')[0]
+      extension = fileName.split('.').pop()
       return { ext: extension, extension, extensionWithDot: '.' + extension }
     else
       return { ext: '', extension: '', extensionWithDot: '' }


remove leftover key filtering on exporter, fix #13

--- src/scripts/editor/Exporter.coffee
+++ src/scripts/editor/Exporter.coffee
@@ -20,7 +20,6 @@
     getJSON: () =>
       options = @editor.options
       json_replacer = (key, val) ->
-        if key == 'tween' then return undefined
         # Disable all private properies from TweenMax/TimelineMax
         if key.indexOf('_') == 0 then return undefined
         if options.json_replacer? then return options.json_replacer(key, val)


Fixes #64

Fixes #64


Don't steal focus when restoring snapshots

--- src/trix/controllers/editor_controller.coffee
+++ src/trix/controllers/editor_controller.coffee
@@ -43,6 +43,7 @@
     @loadSnapshot({document, selectedRange: [0, 0]})

   loadSnapshot: (snapshot) ->
+    @loadingSnapshot = true
     @undoManager = new Trix.UndoManager @composition
     @composition.loadSnapshot(snapshot)

@@ -104,6 +105,7 @@
     @attachmentLocationRange = null

   compositionDidRequestChangingSelectionToLocationRange: (locationRange) ->
+    return if @loadingSnapshot and not @isFocused()
     @requestedLocationRange = locationRange
     @documentWhenLocationRangeRequested = @composition.document
     @render() unless @handlingInput
@@ -111,6 +113,7 @@
   compositionDidLoadSnapshot: ->
     @compositionController.refreshViewCache()
     @render()
+    @loadingSnapshot = false

   getSelectionManager: ->
     @selectionManager
@@ -376,3 +379,6 @@
       Math.floor(new Date().getTime() / Trix.config.undoInterval)
     else
       0
+
+  isFocused: ->
+    @editorElement is @editorElement.ownerDocument?.activeElement


Render a collection of Evidences

Render a collection of Evidences

--- core/app/backbone/views/facts/ndp_discussion_view.coffee
+++ core/app/backbone/views/facts/ndp_discussion_view.coffee
@@ -1,15 +1,16 @@
+#= require ../users/interacting_users_view
 class Evidence extends Backbone.Model

 class OpinionatersEvidence extends Evidence

   initialize: (opts) ->
-    @type = opts.type
-    @fact_id = opts.fact_id
+    @set type: opts.type
+    @set fact_id: opts.fact_id

   opinionaters: ->
     @_opinionaters ?= new NDPInteractorsPage
-      fact_id: @fact_id
-      type: @type
+      fact_id: @get('fact_id')
+      type: @get('type')

 group_for_type = (type) ->
   switch type
@@ -41,9 +42,14 @@
   onRender: ->
     @factRegion.show new TopFactView model: @model

-    believers_model = new OpinionatersEvidence
-      type: 'believe'
-      fact_id: @model.id
+    opinionaters_collection = new Backbone.Collection [
+      new OpinionatersEvidence(type: 'believe',    fact_id: @model.id),
+      new OpinionatersEvidence(type: 'disbelieve', fact_id: @model.id),
+      new OpinionatersEvidence(type: 'doubt',      fact_id: @model.id)
+    ]

-    @evidenceRegion.show new AgreeingInteractingUsersView
-      model: believers_model
+    @evidenceRegion.show new NDPEvidenceCollectionView
+      collection: opinionaters_collection
+
+class NDPEvidenceCollectionView extends Backbone.Marionette.CollectionView
+  itemView: AgreeingInteractingUsersView


Restore proper discussion functionality

Restore proper discussion functionality

--- core/app/backbone/views/facts/ndp_discussion_view.coffee
+++ core/app/backbone/views/facts/ndp_discussion_view.coffee
@@ -11,8 +11,11 @@
   onRender: ->
     @factRegion.show new TopFactView model: @model

-    opinionaters_collection = new NDPEvidenceCollection []
-    opinionaters_collection.loading = true
+    opinionaters_collection = new NDPEvidenceCollection [
+      new OpinionatersEvidence({type: 'believe'   }, fact: @model),
+      new OpinionatersEvidence({type: 'disbelieve'}, fact: @model),
+      new OpinionatersEvidence({type: 'doubt'     }, fact: @model)
+    ]

     @evidenceRegion.show new NDPEvidenceCollectionView
       collection: opinionaters_collection


Redirect to original url after login. Fixes #34

--- both/router.coffee
+++ both/router.coffee
@@ -21,6 +21,12 @@
         Meteor.subscribe 'comments'
         Meteor.subscribe 'attachments'
       ]
+    onBeforeAction: ->
+      url = Session.get 'redirectToAfterSignIn'
+      if url
+        Session.set 'redirectToAfterSignIn', null
+        Router.go url
+      @next()
     data: ->
       Posts: Posts.find({},{sort: {createdAt: -1}}).fetch()
   @route "profile",
@@ -66,7 +72,14 @@
   if @next
     @next()

+saveRedirectUrl = ->
+  unless Meteor.loggingIn()
+    if not Meteor.user()
+      Session.set 'redirectToAfterSignIn', @url
+  @next()
+
 publicRoutes = _.union Config.publicRoutes, ['entrySignIn','entrySignUp','entryForgotPassword']
+Router.onBeforeAction saveRedirectUrl, {except: _.union publicRoutes, ['entrySignOut']}
 Router.onBeforeAction signInRequired, {except: publicRoutes}

 signInProhibited = ->


Fix that negative lengths were added to the offset

--- src/trix/models/location_range.coffee
+++ src/trix/models/location_range.coffee
@@ -1,13 +1,13 @@
 class Trix.LocationRange
   @forLocationWithLength: (location, length) ->
-    if length > 0
+    locationWithLength = index: location.index, offset: location.offset + length
+
+    if length >= 0
       start = location
-      end = index: location.index, offset: location.offset + length
-    else if length < 0
-      start = index: location.index, offset: location.offset - length
+      end = locationWithLength
+    else
+      start = locationWithLength
       end = location
-    else
-      start = end = location

     new this start, end


Fix output message

Fix output message

--- src/site_mapper/http_source.coffee
+++ src/site_mapper/http_source.coffee
@@ -31,7 +31,7 @@
           url: @url
       else
         urls = @bodyProcessor(body)
-        console.log "Read #{body.length} bytes from #{@url}, #{urls.length} urls, first: #{util.inspect urls[0]}, status: #{response.statusCode}"
+        console.log "Read #{body?.length || 0} bytes from #{@url}, #{urls.length} urls, first: #{util.inspect urls[0]}, status: #{response.statusCode}"
         if urls.length <= 0 && !@allowNoUrls
           @error
             message: "Despite 200 response, no valid urls were returned"


Remove all delegated events after fetch event (closes #8)

--- src/jquery.turbolinks.coffee
+++ src/jquery.turbolinks.coffee
@@ -23,7 +23,9 @@
   ready()

 # Fetch event handler
-fetch = -> $.isReady = false
+fetch = ->
+  $(document).off(undefined, '**')
+  $.isReady = false

 # Bind `ready` to DOM ready event
 $(ready)


Set session token as client identifier cookie

--- node_modules_koding/bongo/lib/expressify.coffee
+++ node_modules_koding/bongo/lib/expressify.coffee
@@ -23,6 +23,9 @@
         console.log "bongo.fetchClient: #{sessionToken} not found in #{userArea}"
         return res.status(500).send 'An error occcurred'

+      if sessionToken isnt client.sessionToken
+        res.cookie 'clientId', client.sessionToken
+
       workQueue = requestQueue.map (message, i) -> ->
         bongo.handleRequest channelName, { message, client }, (secretName, callbackId, args) ->
           bongo.scrubResponse callbackId, args, (message) ->


update jetsync lib

update jetsync lib

--- lib/jetsync.coffee
+++ lib/jetsync.coffee
@@ -322,7 +322,7 @@
       offsetC = 0
       _.each(deltasInC, (deltaInC) ->
         if JetDelta.isInsert(delta)
-          d = new JetInsert(delta.text.substring(offsetC, deltaInC.getLength()), deltaInC.attributes)
+          d = new JetInsert(delta.text.substring(offsetC, offsetC + deltaInC.getLength()), deltaInC.attributes)
           deltas.push(d)
         else if JetDelta.isRetain(delta)
           deltasInA = deltaA.getDeltasAt(delta.start + offsetC, deltaInC.getLength())


activity edit disabled again

activity edit disabled again

--- client/landing/app/Applications/Activity.kdapplication/ListItems/ActivityListItem.coffee
+++ client/landing/app/Applications/Activity.kdapplication/ListItems/ActivityListItem.coffee
@@ -96,8 +96,8 @@
         menu        : [
           type      : "contextmenu"
           items     : [
-            # { title : 'Edit',   id : 1,  parentId : null, callback : => new KDNotificationView type : "mini", title : "
Currently disabled.
" }
-            { title : 'Edit',   id : 1,  parentId : null, callback : => @getSingleton('mainController').emit 'ActivityItemEditLinkClicked', data }
+            { title : 'Edit',   id : 1,  parentId : null, callback : => new KDNotificationView type : "mini", title : "
Currently disabled.
" }
+            # { title : 'Edit',   id : 1,  parentId : null, callback : => @getSingleton('mainController').emit 'ActivityItemEditLinkClicked', data }
             { title : 'Delete', id : 2,  parentId : null, callback : => data.delete (err)=> @propagateEvent KDEventType: 'ActivityIsDeleted'  }
           ]
         ]


Clean and power up tip's animation options. :zap:

--- src/js/jquery.hlf.tip.coffee
+++ src/js/jquery.hlf.tip.coffee
@@ -71,25 +71,6 @@
       # - `triggerContent` can be the name of the trigger element's attribute or a
       #   function that provides custom content when given the trigger element.
       triggerContent: null
-      # - `ms.duration` are the durations of sleep and wake animations.
-      # - `ms.delay` are the delays before sleeping and waking.
-      ms:
-        duration:
-          in: 200
-          out: 200
-          resize: 300
-        delay:
-          in: 300
-          out: 300
-      # - `easing` stores the custom easing for baked-in animation support. The
-      #   keys are the same as those of `shouldAnimate` and work if they are
-      #   specified, with `base` being the default easing
-      easing:
-        base: 'ease-in-out'
-      # - `shouldAnimate` provides baked-in animation support. The `resize`
-      #   animation is like `$.fn.show` but with CSS transitions.
-      shouldAnimate:
-        resize: on
       # - `cursorHeight` is the browser's cursor height. We need to know this to
       #   properly offset the tip to avoid cases of cursor-tip-stem overlap.
       cursorHeight: 12
@@ -121,6 +102,20 @@
         (classNames[key] = "#{pre}#{key}") for key in keys
         classNames.tip = 'js-tip'
         classNames
+      # - `animations` are very configurable. Individual animations can be
+      #   customized and will default to the base animation settings as needed.
+      animations:
+        base:
+          delay: 0
+          duration: 200
+          easing: 'ease-in-out'
+          enabled: yes
+        show:
+          delay: 200
+        hide:
+          delay: 200
+        resize:
+          delay: 300

   hlf.tip.snap =
     debug: off
@@ -167,6 +162,8 @@
     # binding event listeners to triggers, which can improve performance and
     # allow dynamic binding.
     constructor: (@$triggers, options, @$context) ->
+      for name, animation of options.animations when name isnt 'base'
+        _.defaults animation, options.animations.base

     init: ->
       # Bind handler methods here after class setup completes.
@@ -316,10 +313,9 @@
       $tip = $(html).addClass @classNames.follow
       # Animation setup.
       transitionStyle = []
-      if @shouldAnimate.resize
-        duration = @ms.duration.resize / 1000.0 + 's'
-        easing = @easing.resize
-        easing ?= @easing.base
+      if @animations.resize.enabled
+        duration = @animations.resize.duration / 1000.0 + 's'
+        easing = @animations.resize.easing
         transitionStyle.push "width #{duration} #{easing}", "height #{duration} #{easing}"
       transitionStyle = transitionStyle.join(',')
       # /Animation setup.
@@ -337,7 +333,7 @@
       @debugLog 'update direction class', compoundDirection
       $content = @selectByClass 'content'
       $content.text $trigger.data @attr('content')
-      if @shouldAnimate.resize
+      if @animations.resize.enabled
         contentSize = @sizeForTrigger $trigger, (contentOnly = yes)
         $content
           .width contentSize.width
@@ -527,8 +523,9 @@
       if event? then @debugLog event.type
       # Don't toggle if awake or waking, or if event isn't `truemouseenter`.
       return no if @_state in ['awake', 'waking']
-      delay = @ms.delay.in
-      duration = @ms.duration.in
+      # Get delay and initial duration.
+      delay = @animations.show.delay
+      duration = @animations.show.duration
       # Our `wake` subroutine runs the timed-out logic, which includes the fade
       # transition. The latter is also affected by `safeToggle`. The `onShow`
       # and `afterShow` hook methods are also run.
@@ -566,10 +563,10 @@
       clearTimeout @_wakeCountdown
       @_sleepCountdown = setTimeout =>
         @onHide()
-        @$tip.stop().fadeOut @ms.duration.out, =>
+        @$tip.stop().fadeOut @animations.hide.duration, =>
           @_setState 'asleep'
           @afterHide()
-      , @ms.delay.out
+      , @animations.hide.delay
       yes

     # These methods are hooks for custom functionality from subclasses. Some are


Delete config require. Let out large sigh

--- models/comment.coffee
+++ models/comment.coffee
@@ -2,7 +2,6 @@
 sd = require("sharify").data
 _ = require 'underscore'
 _s = require 'underscore.string'
-config = require '../config.coffee'
 markdown = require '../lib/markdown.coffee'
 striptags = require 'striptags'


extend data.user attrs for logging in

extend data.user attrs for logging in

--- models/invitee.coffee
+++ models/invitee.coffee
@@ -1,11 +1,13 @@
 Base = require "./base.coffee"
 sd = require("sharify").data
+_ = require 'underscore'

 module.exports = class Invitee extends Base

   url: -> "#{sd.API_URL}/accounts/invitations/accept?invitation_token=#{@get('invitation_token')}"

-  parse: (data) -> data.user
+  parse: (data) ->
+    _.extend data, data.user

   sync: (method, model, options) ->
     switch method


Fix parsing HTML for attachments in columns

--- src/trix/models/html_parser.coffee
+++ src/trix/models/html_parser.coffee
@@ -238,6 +238,7 @@

   isBlockElement: (element) ->
     return unless element?.nodeType is Node.ELEMENT_NODE
+    return if nodeIsAttachmentElement(element)
     return if findClosestElementFromNode(element, matchingSelector: "td", untilNode: @containerElement)
     tagName(element) in getBlockTagNames() or window.getComputedStyle(element).display is "block"


revertsish

revertsish

--- communist.coffee
+++ communist.coffee
@@ -34,21 +34,20 @@

 Socialist = (fun)->
 	_func = fun
-	@send = (data..., cb) ->
-		@self = {}
-		@self.send = (m)->
-			cb.apply @, [null, m]
+	_send = (data..., cb) ->
+		@send = (m)->
+			cb.apply null, m
 		try
-			cb.apply @, [null, _func(data...)]
+			cb null, _func.apply(@,data)
 		catch err
 			cb err
 		true
-
+	@send = _send
 	@close = ->
 		_func = undefined
 		true
 	@
-
+

 window.communist = (fun) ->
 	if window.Worker


fix: Remove github from assets

fix: Remove github from assets

--- app/assets/javascripts/application.coffee
+++ app/assets/javascripts/application.coffee
@@ -1,5 +1,4 @@
 #= require lodash
-#= require github
 #= require angular
 #= require angular-bootstrap
 #= require angular-ui-router


Missed a line.

Missed a line.

--- app/assets/javascripts/calendar.js.coffee
+++ app/assets/javascripts/calendar.js.coffee
@@ -95,7 +95,6 @@
       this.color_reservations("#{year}-#{month}-#{day}")
       window.ReservationPopupManager.hide_popup()
       window.CancelPopupManager.hide_popup()
-      $(".popup").hide()
     )
     return
   color_reservations: (date)->


zoom in-out

zoom in-out

--- app/assets/javascripts/d3/topology.coffee
+++ app/assets/javascripts/d3/topology.coffee
@@ -24,7 +24,7 @@
       .attr('transform', (d) => "translate(#{@x d.x},#{@y d.y})")

     @nodes.append('svg:rect')
-      .attr('width', @x 100)
+      .attr('width', @x 70)
       .attr('height', @y 50)
       .attr('fill', (d, i) => @colors i)
       .attr('data-tooltip', (d) -> d.key)
@@ -37,6 +37,27 @@
       style:
         classes: "ui-tooltip-tipsy"

+  zoom_in: => @zoom(0.5)
+
+  zoom_out: => @zoom(2)
+
+  zoom: (x) =>
+    old = @x.domain()
+    @x.domain([old[0], old[1] * x])
+    old = @y.domain()
+    @y.domain([old[0], old[1] * x])
+    @redraw()
+
+
+  redraw: =>
+    @svg.selectAll('g.node').transition()
+      .attr('transform', (d) => "translate(#{@x d.x},#{@y d.y})")
+
+    @svg.selectAll('rect')
+      .transition()
+      .attr('width', @x 70)
+      .attr('height', @y 50)
+

 $ ->
-  new Topology()+  window.chart = new Topology()