Update instead of upgrade

Update instead of upgrade

--- lib/package-update-view.coffee
+++ lib/package-update-view.coffee
@@ -11,7 +11,7 @@
           @h4 class: 'package-name native-key-bindings', tabindex: -1, _.undasherize(_.uncamelcase(name))
           @p outlet: 'latestVersion', class: 'description native-key-bindings', tabindex: -1
           @div class: 'btn-toolbar', =>
-            @button outlet: 'upgradeButton', class: 'btn btn-primary', 'Upgrade'
+            @button outlet: 'upgradeButton', class: 'btn btn-primary', 'Update'
             @button outlet: 'uninstallButton', class: 'btn btn-default', 'Uninstall'
             @button outlet: 'settingsButton', class: 'btn btn-default', 'Settings'


Hide scores if unranked

Hide scores if unranked

--- resources/assets/coffee/react/beatmapset-page/main.coffee
+++ resources/assets/coffee/react/beatmapset-page/main.coffee
@@ -198,17 +198,18 @@
               beatmapset: @props.beatmapset
               currentUser: currentUser

-        div className: 'osu-page osu-page--generic',
-          el BeatmapsetPage.Scoreboard,
-            type: @state.currentScoreboardType
-            beatmap: @state.currentBeatmap
-            scores: @state.scores
-            userScore: @state.userScore?.score
-            userScorePosition: @state.userScore?.position
-            enabledMods: @state.enabledMods
-            countries: @props.countries
-            loading: @state.loading
-            hasScores: @props.beatmapset.has_scores
+        if @props.beatmapset.has_scores
+          div className: 'osu-page osu-page--generic',
+            el BeatmapsetPage.Scoreboard,
+              type: @state.currentScoreboardType
+              beatmap: @state.currentBeatmap
+              scores: @state.scores
+              userScore: @state.userScore?.score
+              userScorePosition: @state.userScore?.position
+              enabledMods: @state.enabledMods
+              countries: @props.countries
+              loading: @state.loading
+              hasScores: @props.beatmapset.has_scores

         div className: 'osu-page osu-page--generic-compact',
           el Comments,


[browser] Now using Set for windows holding instead of Array

--- src/browser/Application.coffee
+++ src/browser/Application.coffee
@@ -18,7 +18,7 @@
     constructor     : (options = {}) ->
         super()

-        @windows        = []
+        @windows        = new Set
         @options        = options
         @packageJson    = require "../package.json"
         @command        = require "./CommandManager"
@@ -44,13 +44,14 @@
     ###

     addWindow       : (window) ->
-        @windows.push window
-        @emit "did-window-added", window
+        preSize = @windows.size
+        if @windows.add(window).size isnt preSize
+            @emit "did-window-added", window
         return

     removeWindow    : (window) ->
-        @windows.splice index, 1 for index, w of @windows when w is window
-        @emit "did-window-remove"
+        if @windows.delete(window)
+            @emit "did-window-remove"
         return

     setLastFocusedWindow    : (window) ->


fixup! fix unbinding shortcuts on component unmount

--- src/component/shortcuts.coffee
+++ src/component/shortcuts.coffee
@@ -28,12 +28,14 @@
     stopPropagation: React.PropTypes.bool
     preventDefault: React.PropTypes.bool
     targetNode: React.PropTypes.object
+    ref: React.PropTypes.string
     nativeKeyBindingsClassName: React.PropTypes.string

   getDefaultProps: ->
     element: null
     tabIndex: null
     className: null
+    ref: null
     eventType: null
     stopPropagation: null
     preventDefault: true
@@ -96,6 +98,7 @@

     element
       tabIndex: @props.tabIndex or -1
+      ref: @props.ref
       className: @props.className,

       @props.children


Functional case

Functional case

--- lib/atom-gdb.coffee
+++ lib/atom-gdb.coffee
@@ -1,10 +1,13 @@
 {BufferedProcess} = require 'atom'
 {CompositeDisposable} = require 'atom'
+path = require 'path'
+fs = require 'fs'

 module.exports = AtomGdb =
   atomGdbView: null
   modalPanel: null
   subscriptions: null
+  breakPoints: []
   config:
     debuggerCommand:
       type: 'string'
@@ -31,9 +34,6 @@

   start: ->
     console.log 'Starting debugger...'
-    options =
-      cwd: atom.config.get('atom-gdb.startupDirectory')
-      env: process.env #not functional
     commandWords = atom.config.get('atom-gdb.debuggerCommand').split " "
     command = commandWords[0]
     args = commandWords[1..commandWords.length]
@@ -41,9 +41,23 @@
     stdout = (output) -> console.log("stdout:", output)
     stderr = (output) -> console.log("stderr:", output)
     exit = (return_code) -> console.log("Exit with ", return_code)
-    process = new BufferedProcess({command, args, options, stdout, stderr, exit})
+    process.chdir atom.config.get('atom-gdb.startupDirectory')
+    childProcess = new BufferedProcess({command, args, stdout, stderr, exit})

   toggle_breakpoint: ->
-    console.log 'Breakpoint...'
-    editor =  atom.workspace.getActiveTextEditor()
-    console.log editor.getCursorBufferPosition().row + 1
+    editor = atom.workspace.getActiveTextEditor()
+    filename = path.basename(editor.getPath())
+    row = editor.getCursorBufferPosition().row + 1
+    @breakPoints.push {filename:filename, line:row}
+    console.log("Added breakpoint:", filename, ":", row)
+    @updateGdbInit()
+
+  updateGdbInit: ->
+    process.chdir atom.config.get('atom-gdb.startupDirectory')
+    outputFile = fs.createWriteStream(".gdbinit")
+    bps = @breakPoints
+    outputFile.on 'open', (fd) ->
+      outputFile.write "set breakpoint pending on\n"
+      outputFile.write "b " + bp.filename + ":" + bp.line + "\n" for bp in bps
+      outputFile.end()
+      return


Propagate binder to the ack/socket

Propagate binder to the ack/socket

--- library/membrane/duplex.coffee
+++ library/membrane/duplex.coffee
@@ -156,7 +156,8 @@
     # around the provider invocation procedure. This wrapping is of
     # protective nature. It also exposes some goodies for the provider.
     # Such as Socket.IO handle, session if available and the context.
-    @covering: (method, socket, context) ->
+    @covering: (method, socket, context, binder) ->
+        assert socket.handshake.binder = binder
         assert _.isFunction o = Marshal.serialize
         assert _.isFunction i = Marshal.deserialize
         socket.on "disconnect", -> try guarded.dispose()
@@ -165,7 +166,7 @@
         assert _.isObject guarded = @guarded method, socket
         assert _.isFunction g = guarded.run.bind guarded
         s = (f) => session.save -> f.apply this, arguments
-        assert context; return (parameters..., callback) ->
+        assert binder; return (parameters..., callback) ->
             execute = (a...) => g => method.apply this, i(a)
             respond = (a...) => g => s => callback.apply this, o(a)
             respond.socket = socket; respond.context = context
@@ -278,7 +279,7 @@
             providing = value?.providing or null
             return unless _.isFunction providing
             assert _.isFunction(value), internal
-            bound = providing socket, context
+            bound = providing socket, context, binder
             assert mangled = "#{@location()}/#{name}"
             mangled += "/#{nsp}" if nsp = binder.nsp
             socket.on mangled, (args..., callback) =>


Add enum pointer

Add enum pointer

--- library/membrane/schema.coffee
+++ library/membrane/schema.coffee
@@ -107,6 +107,19 @@
 # specific kind of data type. Pointers may create simple or complex
 # data type references and definitions. Refer to their implementation.
 # This pointer creates a reference to an array of other pointers.
+module.exports.choose = choose = (description, values...) ->
+    noValues = "all values must be primitive strings"
+    noDescription = "no description has been given"
+    assert _.isString(description), noDescription
+    assert _.all(values, _.isString), noValues
+    @description = description.toString()
+    @enum = values; return this
+
+# This defines one of the built in pointers. A pointer is a method
+# defintion that provides an ability to specify (or point to) to a
+# specific kind of data type. Pointers may create simple or complex
+# data type references and definitions. Refer to their implementation.
+# This pointer creates a reference to an array of other pointers.
 module.exports.array = array = (description, pointer) ->
     noPointer = "got no pointer to array elements"
     noDescription = "no description has been given"


Fix a misnomer

Fix a misnomer

--- library/membrane/visual.coffee
+++ library/membrane/visual.coffee
@@ -152,7 +152,7 @@
     # from top to bottom (the ordering is important) and issue an
     # autocall for each remote/external method that is marked with
     # an autocall decorator and therefore must be called on site.
-    issueAutocalls: (context, symbol) ->
+    inlineAutocalls: (context, symbol) ->
         hierarchy = @constructor?.hierarchy?()
         noHierarchy = "could not scan the hierarchy"
         assert _.isArray(hierarchy), noHierarchy
@@ -208,7 +208,7 @@
         context.doctype = "<!DOCTYPE html>"
         prelude = @upstreamAsync "prelude", =>
             assert @deployContext context, symbol
-            assert @issueAutocalls context, symbol
+            assert @inlineAutocalls context, symbol
             context = @compressSources context if asm
             compiled = @compileContext context if asm
             return receive context, compiled or null


line length fix

line length fix

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -263,7 +263,8 @@

   each_pass = ->
     pass = new CompilePass(@)
-    pipeline(@adapters.map((a,i) -> pass.run.bind(pass, a, i + 1)), { result: @content })
+    pipeline(@adapters.map((a,i) -> pass.run.bind(pass, a, i + 1)),
+      { result: @content })

   ###*
    * Returns the absolute path to the file as requested through the browser,


cleanup

cleanup

--- lib/manifest.coffee
+++ lib/manifest.coffee
@@ -43,7 +43,6 @@
   save: (cb) ->
     id     = uuid.v1()
     buffer = new Buffer(JSON.stringify(@manifest), "binary")
-
     put = @knox.put "/manifest/#{id}.json", "Content-Length":buffer.length, "Content-Type":"application/json"
     put.on "response", (res) ->
       manifest_url = "#{process.env.ANVIL_HOST}/manifest/#{id}.json"


Can remove conditional guard

Can remove conditional guard

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -302,7 +302,7 @@
     options =
       stay: @needStayOnRestore()
       occurrenceSelected: @occurrenceSelected
-      isBlockwise: @target?.isBlockwise?()
+      isBlockwise: @target.isBlockwise()

     @mutationManager.restoreCursorPositions(options)
     @emitDidRestoreCursorPositions()
@@ -322,7 +322,7 @@

   execute: ->
     @startMutation(@selectTarget.bind(this))
-    # [FIXME] Don't use wise as status
+
     if @target.isTextObject() and @target.selectSucceeded
       wise = @target.wise
       if @isMode('visual')


fix mistake

fix mistake

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -650,7 +650,7 @@

   onConfirm: (input) ->
     return unless input
-    {from, @char} = input.split('')
+    [from, @char] = input.split('')
     super(from)

   getNewText: (text) ->


Log 400 (register) events

Log 400 (register) events

--- lib/register.coffee
+++ lib/register.coffee
@@ -1,6 +1,7 @@
-_            = require 'lodash'
-debug        = require('debug')('meshblu:register')
+_             = require 'lodash'
+debug         = require('debug')('meshblu:register')
 generateToken = require './generateToken'
+logEvent      = require './logEvent'

 module.exports = (device={}, callback=_.noop, dependencies={}) ->
   uuid         = dependencies.uuid || require 'node-uuid'
@@ -26,6 +27,8 @@
     debug 'about to update device', device
     updateDevice newDevice.uuid, device, (error, savedDevice) =>
       return callback new Error('Device not updated') if error?
+
+      logEvent 400, savedDevice
       savedDevice.token = device.token

       callback null, savedDevice


:lipstick:

:lipstick:

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -10,7 +10,7 @@
     return unless @shouldSendErrorFromUrl(url)
     @request
       method: 'POST'
-      url: "https://notify.bugsnag.com"
+      url: 'https://notify.bugsnag.com'
       headers: 'Content-Type' : 'application/json'
       body: JSON.stringify(@buildParams(message, url, line, column, error))

@@ -66,5 +66,5 @@
       ]

   @shouldSendErrorFromUrl: (url) ->
-    resourcePath = atom.getLoadSettings().resourcePath
+    {resourcePath} = atom.getLoadSettings()
     not atom.inDevMode() and url.indexOf(resourcePath) == 0


Use the error object's name as the 'errorClass' if it exists

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -19,11 +19,11 @@

   @buildParams: (message, url, line, column, error) ->
     message = message.substring(0, 5*1024)
-
-    if errorClass = message.split(':', 1)[0]
-      errorClass = errorClass.replace('Uncaught ', '')
-    else
-      errorClass = "UncaughtError"
+    unless errorClass = error?.name
+      if errorClass = message.split(':', 1)[0]
+        errorClass = errorClass.replace('Uncaught ', '')
+      else
+        errorClass = "UncaughtError"

     releaseStage = if atom.isReleasedVersion() then 'production' else 'development'
     {line, column, source} = coffeestack.convertLine(url, line, column) ? {line, column, source: url}


remove the no used function

remove the no used function

--- lib/sm-slack.coffee
+++ lib/sm-slack.coffee
@@ -127,12 +127,6 @@
       timestamp: ts
     SlackApi.pins.add opts

-  getUser:(name)->
-    opts=
-      token: @botToken
-      user:name
-    SlackApi.users.info opts
-
   listUsers: ()->
     opts=
       token: @botToken


Check for empty selection in expandSnippetUnderCursor

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -102,10 +102,7 @@
   enableSnippetsInEditor: (editorView) ->
     editor = editorView.getEditor()
     editorView.command 'snippets:expand', (event) =>
-      if editor.getSelection().isEmpty()
-        event.abortKeyBinding() unless @expandSnippetUnderCursor(editor)
-      else
-        event.abortKeyBinding()
+      event.abortKeyBinding() unless @expandSnippetUnderCursor(editor)

     editorView.command 'snippets:next-tab-stop', (event) ->
       unless editor.snippetExpansion?.goToNextTabStop()
@@ -149,6 +146,8 @@
     snippets

   expandSnippetUnderCursor: (editor) ->
+    return false unless editor.getSelection().isEmpty()
+
     snippets = @getSnippets(editor)
     return false if _.isEmpty(snippets)


Use getBoundingClientRect instead of offsetWidth to calculate the width of a terminal char (apparently the latter no longer works since the last Atom update...)

--- lib/terminal.coffee
+++ lib/terminal.coffee
@@ -202,7 +202,7 @@
     dummyElement.textContent = '_'
     body = document.getElementsByTagName('body')[0]
     body.appendChild(dummyElement)
-    charWidth = dummyElement.offsetWidth
+    charWidth = dummyElement.getBoundingClientRect().width
     body.removeChild(dummyElement)
     charWidth


Don't consume partial parts of delete when inserting a change

--- services/document-updater/app/coffee/RangesTracker.coffee
+++ services/document-updater/app/coffee/RangesTracker.coffee
@@ -206,12 +206,12 @@
 					# If this is an insert op at the end of an existing insert with a delete following, and it cancels out the following
 					# delete then we shouldn't append it to this insert, but instead only cancel the following delete.
 					# E.g.
-					#                   foo|<--- about to insert 'b' here
+					#                   foo|<--- about to insert 'bar' here
 					#  inserted 'foo'  --^ ^-- deleted 'bar'
-					# should become just 'foo' not 'foob' (with the delete marker becoming just 'ar'), .
+					# should become just 'foo' not 'foobar' (with the delete marker disappearing), .
 					next_change = @changes[i+1]
 					is_op_adjacent_to_next_delete = next_change? and next_change.op.d? and op.p == change_end and next_change.op.p == op.p
-					will_op_cancel_next_delete = is_op_adjacent_to_next_delete and next_change.op.d.slice(0, op.i.length) == op.i
+					will_op_cancel_next_delete = is_op_adjacent_to_next_delete and next_change.op.d == op.i

 					# If there is a delete at the start of the insert, and we're inserting
 					# at the start, we SHOULDN'T merge since the delete acts as a partition.


fetch today coding time at startup

fetch today coding time at startup

--- lib/wakatime.coffee
+++ lib/wakatime.coffee
@@ -143,6 +143,7 @@

   statusBarIcon?.setTitle('WakaTime ready')
   statusBarIcon?.setStatus(cachedToday)
+  getToday()
   log.debug 'Finished initializing WakaTime.'

 settingChangedHandler = (settings, initial) ->


test for flash

test for flash

oops

--- spec/javascripts/controllers/RecipeController_spec.coffee
+++ spec/javascripts/controllers/RecipeController_spec.coffee
@@ -3,6 +3,7 @@
   ctrl         = null
   routeParams  = null
   httpBackend  = null
+  flash        = null
   recipeId     = 42

   fakeRecipe   =
@@ -11,12 +12,13 @@
     instructions: "Pierce potato with fork, nuke for 20 minutes"

   setupController =(recipeExists=true)->
-    inject(($location, $routeParams, $rootScope, $httpBackend, $controller)->
+    inject(($location, $routeParams, $rootScope, $httpBackend, $controller, _flash_)->
       scope       = $rootScope.$new()
       location    = $location
       httpBackend = $httpBackend
       routeParams = $routeParams
       routeParams.recipeId = recipeId
+      flash = _flash_

       request = new RegExp("\/recipes/#{recipeId}")
       results = if recipeExists
@@ -47,4 +49,4 @@
       it 'loads the given recipe', ->
         httpBackend.flush()
         expect(scope.recipe).toBe(null)
-        # what else?!
+        expect(flash.error).toBe("There is no recipe with ID #{recipeId}")


Renamed menu item

Renamed menu item

--- menus/web-view.cson
+++ menus/web-view.cson
@@ -2,7 +2,7 @@
   {
     'label': 'Packages'
     'submenu': [
-      'label': 'WebView'
+      'label': 'Web View'
       'submenu': [
         { 'label': 'Go to page', 'command': 'web-view:go-to-page' }
       ]


lbar tooltip: clarified that SC/RP work only in editors

--- client/ide.coffee
+++ client/ide.coffee
@@ -138,8 +138,8 @@
           EP: Exit (and save changes):  Esc
           FD: Forward or Redo:          Ctrl+Shift+Enter
           BK: Backward or Undo:         Ctrl+Shift+Backspace
-          SC: Search:                   Ctrl+F
-          RP: Replace:                  Ctrl+G
+          SC: Search (in editors):      Ctrl+F
+          RP: Replace (in editors):     Ctrl+G
           ED: Edit:                     Shift+Enter
           ТC: Trace:                    Ctrl+Enter
           TL: Toggle localisation:      Ctrl+Up


add timeout for write_text_file_to_project

--- src/smc-hub/test/api/text_files.coffee
+++ src/smc-hub/test/api/text_files.coffee
@@ -25,6 +25,7 @@
                 done(err)

     it "creates a text file", (done) ->
+        @timeout 10000
         api.call
             event : 'write_text_file_to_project'
             body  :


Handle errors.

Handle errors.

--- src/spec/integration-order.spec.coffee
+++ src/spec/integration-order.spec.coffee
@@ -24,6 +24,8 @@
     .then (order) =>
       @order = order
       done()
+    .fail (error) ->
+      done(error)

   afterEach (done) ->

@@ -33,6 +35,8 @@
         deleteResourcePromise(@sync._rest, "/product-types/#{@productType.id}?version=#{@productType.version}")
     .then (productType) =>
       done()
+    .fail (error) ->
+      done(error)

   it "should do nothing", (done) ->
     expect(true).toBe true


Add setposition method to map

Add setposition method to map

--- client/map.coffee
+++ client/map.coffee
@@ -63,6 +63,11 @@
       @map.setZoom(projection.zoom || @zoom)
     , 1000)

+  setPosition: (latLng) ->
+    @rectangleEditor.setCenterLatLng(latLng)
+    @map.setView(latLng, @zoom)
+    @map.fitBounds(@rectangleEditor.getBounds())
+

   getZoom: ->
     return @map.getZoom()


Remove renegade center modal reference

Remove renegade center modal reference


Don't have an attentionSpan on touch devices

--- js-library/app/js/jail_iframe/classes/icon_buttons.coffee
+++ js-library/app/js/jail_iframe/classes/icon_buttons.coffee
@@ -122,20 +122,20 @@
     @_iconButton = new IconButton
       content: '+'
       targetElement: @$paragraph[0]
-      onmouseenter: => @_attentionSpan.gainAttention()
-      onmouseleave: => @_attentionSpan.loseAttention()
+      onmouseenter: => @_attentionSpan?.gainAttention()
+      onmouseleave: => @_attentionSpan?.loseAttention()
       onclick: @_onClick
-
-    @_attentionSpan = new FactlinkJailRoot.AttentionSpan
-      wait_for_neglection: 500
-      onAttentionGained: => @_iconButton.fadeIn()
-      onAttentionLost: => @_iconButton.fadeOut()

     FactlinkJailRoot.on 'factlink.factsLoaded factlinkAdded', @_destroyUnlessValid

     if FactlinkJailRoot.isTouchDevice()
       @_iconButton.fadeIn()
     else
+      @_attentionSpan = new FactlinkJailRoot.AttentionSpan
+        wait_for_neglection: 500
+        onAttentionGained: => @_iconButton.fadeIn()
+        onAttentionLost: => @_iconButton.fadeOut()
+
       @_robustParagraphHover = new FactlinkJailRoot.RobustHover
         $el: @$paragraph
         mouseenter: @_showOnlyThisParagraphButton


Extract computation of target vertical offset into helper

--- js-library/app/js/jail_iframe/classes/icon_buttons.coffee
+++ js-library/app/js/jail_iframe/classes/icon_buttons.coffee
@@ -90,6 +90,19 @@
     @$highlightElements = $(highlightElements)
     @_textContainer = findTextContainer(@$highlightElements[0])

+    @_iconButton = new IconButton
+      content: ''
+      targetElement: @_textContainer
+      targetOffset: @_targetOffset()
+      onmouseenter: @_onHover
+      onmouseleave: @_onUnhover
+      onclick: @_onClick
+
+    @_factId = factId
+
+    @_iconButton.fadeIn()
+
+  _targetOffset: ->
     # Calculate a vertical percentage to position the icon relative
     # to the textContainer
     # TODO: really do grouping, so we don't have to do hacks like this!
@@ -97,17 +110,8 @@
     verticalOffset = @$highlightElements[0].getBoundingClientRect().top - textContainerBoundingRect.top
     verticalOffsetPercentage = verticalOffset*100 / textContainerBoundingRect.height

-    @_iconButton = new IconButton
-      content: ''
-      targetElement: @_textContainer
-      targetOffset: "#{verticalOffsetPercentage}% 0"
-      onmouseenter: @_onHover
-      onmouseleave: @_onUnhover
-      onclick: @_onClick
+    "#{verticalOffsetPercentage}% 0"

-    @_factId = factId
-
-    @_iconButton.fadeIn()

   destroy: ->
     @_iconButton.destroy()


Fix post login redirects

Fix post login redirects

--- routes/auth.coffee
+++ routes/auth.coffee
@@ -4,8 +4,8 @@
 router = express.Router()

 router.post '/login', passport.authenticate 'local',
-  successRedirect: '/admin'
-  failureRedirect: '/'
+  successRedirect: '/admin/cc'
+  failureRedirect: '/admin'
   failureFlash: 'Invalid username or password!'

 module.exports = router


Manage an array of subscribers since there may be more than one subscription to a channel

--- lib/assets/javascripts/cable/subscriber_manager.js.coffee
+++ lib/assets/javascripts/cable/subscriber_manager.js.coffee
@@ -1,35 +1,36 @@
 class Cable.SubscriberManager
   constructor: (@cable) ->
-    @subscribers = {}
+    @subscribers = []

   add: (subscriber) ->
-    {identifier} = subscriber
-    @subscribers[identifier] = subscriber
+    @subscribers.push(subscriber)
     @notify(subscriber, "initialized")
-    if @sendCommand("subscribe", identifier)
+    if @sendCommand(subscriber, "subscribe")
       @notify(subscriber, "connected")

   reload: ->
-    for identifier, subscriber of @subscribers
-      if @sendCommand("subscribe", identifier)
+    for subscriber in @subscribers
+      if @sendCommand(subscriber, "subscribe")
         @notify(subscriber, "connected")

   remove: (subscriber) ->
-    {identifier} = subscriber
-    @sendCommand("unsubscribe", identifier)
-    delete @subscribers[identifier]
+    @sendCommand(subscriber, "unsubscribe")
+    @subscibers = (s for s in @subscribers when s isnt subscriber)

   notifyAll: (callbackName, args...) ->
-    for identifier, subscriber of @subscribers
+    for subscriber in @subscribers
       @notify(subscriber, callbackName, args...)

   notify: (subscriber, callbackName, args...) ->
     if typeof subscriber is "string"
-      subscriber = @subscribers[subscriber]
+      subscribers = (s for s in @subscribers when s.identifier is subscriber)
+    else
+      subscribers = [subscriber]

-    if subscriber
+    for subscriber in subscribers
       subscriber[callbackName]?(args...)

-  sendCommand: (command, identifier) ->
+  sendCommand: (subscriber, command) ->
+    {identifier} = subscriber
     return true if identifier is Cable.PING_IDENTIFIER
     @cable.send({command, identifier})


ProjectGroup fetch refactor/bug fix for summary

--- app/annotation/summary.cjsx
+++ app/annotation/summary.cjsx
@@ -18,31 +18,32 @@
   getInitialState: ->
     chimpsSeen: false
     siteLocation: null
+    group: null
     knownChimpsLink: null
     newChimpsLink: null

-  componentWillMount: ->
+  componentDidMount: ->
     @props.notes.map (note) =>
       if note.animal is steps[2][0].animal.options[2] #chimp
         @setState chimpsSeen: true

-  componentDidMount: ->
     ProjectGroup.on 'fetch', @onProjectGroupFetch
     ProjectGroup.fetch()
+
+  componentWillUnmount: ->
+    ProjectGroup.off 'fetch', @onProjectGroupFetch

   onProjectGroupFetch: ->
     groupId = Subject.current.group_id
     group = ProjectGroup.find groupId
-    @setState
+    @setState({
+      group: group
       knownChimpsLink: group.metadata.known_chimps_link
       newChimpsLink: group.metadata.new_chimps_link
-
-    @getSiteLocation()
+    }, => @getSiteLocation())

   getSiteLocation: ->
-    groupId = Subject.current.group_id
-    group = ProjectGroup.find groupId
-    locationName = group.metadata.site
+    locationName = @state.group.metadata.site

     siteLocation = switch
       when sites.siteA.indexOf(locationName) > -1 then "site-a"


Batch mutations and parsing is optimized

This is done by looking at the top most line that was affected by the
change and start the process from there. This change has knock on effect
that fixed few issues with cursor positioning. A few checks in
appended(), updated() and removed() might become unecessary which might
bring a whole lot of speed improvement.

--- lib/ecrire/app/assets/javascripts/admin/editor/content.coffee
+++ lib/ecrire/app/assets/javascripts/admin/editor/content.coffee
@@ -38,13 +38,13 @@

-  outdated: (mutations) =>
+  outdated: (observedMutations) =>
     @observer.hold =>
-      for mutation in mutations
-        @appended(node, mutation.target) for node in mutation.addedNodes
-        @removed(node, mutation.target) for node in mutation.removedNodes
-        if mutation.type == 'characterData'
-          @update mutation.target
+      mutations = new Mutations(observedMutations)
+      switch mutations.status()
+        when 'appended' then @appended(mutations)
+        when 'updated' then @updated(mutations)
+        when 'removed' then @removed(mutations)

     event = new CustomEvent('Editor:updated', {bubbles: true})
     @element().dispatchEvent(event)
@@ -83,7 +83,8 @@

-  update: (node) ->
+  updated: (mutations) ->
+    node = mutations.target
     while node? && node.parentElement != @element()
       node = node.parentElement

@@ -110,7 +111,8 @@
       @scrollLineIntoView(cursor.focus())

-  removed: (node, line) =>
+  removed: (mutations) =>
+    line = node = mutations.target
     while line? && line.parentElement != @element()
       line = line.parentElement

@@ -123,7 +125,7 @@
         offset = 0
       else
         offset = @lineOffset(line, sel.focusNode, sel.focusOffset)
-
+
       cursor = new Editor.Cursor(offset)

       lines = @parse(@cloneNodesFrom(line))
@@ -140,8 +142,8 @@

-  appended: (node) =>
-    el = node
+  appended: (mutations) =>
+    el = mutations.target
     while el? && el.parentElement != @element()
       el = el.parentElement

@@ -391,5 +393,37 @@
       @fragment.appendChild(node)

+class Mutations
+  constructor: (mutations) ->
+    @removed = []
+    @appended = []
+    @updated = []
+
+    for mutation in mutations
+      @setTarget(mutation.target)
+      if mutation.addedNodes.length > 0
+        @appended.push mutation.target
+      else if mutation.type == 'characterData'
+        @updated.push mutation.target
+      else
+        @removed.push mutation.target
+
+  setTarget: (target) ->
+    return unless target.parentElement?
+    if @target? && @target.compareDocumentPosition(target) & Node.DOCUMENT_POSITION_FOLLOWING
+      @target = target
+    else
+      @target = target
+
+  status: =>
+    if @appended.length > 0
+      "appended"
+    else if @updated.length > 0
+      'updated'
+    else if @removed.length > 0
+      'removed'
+    else
+      'none'
+
 Editor.Parsers = []
 Editor.Extensions = []


learning about array literals

learning about array literals

--- app/controllers/home.coffee
+++ app/controllers/home.coffee
@@ -19,11 +19,11 @@
         index: 0
         text:  req.param("zip-code")
         icon: "i120"
-
-        index: 0
+        ,
+        index: 1
         text:  req.param("zip-code")
         icon: "i120"
-
+        ,
         c : req.header("accept")
         d : req.headers
         e : req.params


flip y-axis tickmarks

flip y-axis tickmarks

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -174,7 +174,7 @@
     # lightcurve on top of tickmarks?
     # @drawYTickMarks([0..20], [0..@canvas.height], 1, 2)
     # console.log 'LIMITS: [',xMin,',',xMax,']'
-    @drawXTickMarks(xMin, xMax)
+    # @drawXTickMarks(xMin, xMax)
     @drawYTickMarks(yMin, yMax)

     # plot points
@@ -217,15 +217,15 @@
     textColor = '#323232'
     textSpacing = 15

-    for tickPos, i in [xTicks...]
+    for tick, i in [xTicks...]
       continue if i is 0 # skip first value
       # draw ticks
       @ctx.beginPath()
-      @ctx.moveTo( @toCanvasXCoord(tickPos), @canvas.height )
+      @ctx.moveTo( @toCanvasXCoord(tick), @canvas.height )
       if i % nIntervals is 0
-        @ctx.lineTo( @toCanvasXCoord(tickPos), @canvas.height - tickMajorLength ) # major tick
+        @ctx.lineTo( @toCanvasXCoord(tick), @canvas.height - tickMajorLength ) # major tick
       else
-        @ctx.lineTo( @toCanvasXCoord(tickPos), @canvas.height - tickMinorLength ) # minor tick
+        @ctx.lineTo( @toCanvasXCoord(tick), @canvas.height - tickMinorLength ) # minor tick
       @ctx.lineWidth = tickWidth
       @ctx.strokeStyle = tickColor
       @ctx.stroke()
@@ -235,7 +235,7 @@
         @ctx.font = '10pt Arial'
         @ctx.textAlign = 'center'
         @ctx.fillStyle = textColor
-        @ctx.fillText( tickPos, @toCanvasXCoord(tickPos), @canvas.height - textSpacing )
+        @ctx.fillText( tick, @toCanvasXCoord(tick), @canvas.height - textSpacing )

   drawYTickMarks: (yMin, yMax, nIntervals) ->
     console.log 'yLimits: [',yMin,',',yMax,']'
@@ -261,15 +261,20 @@
     textColor = '#323232'
     textSpacing = 15

-    for tickPos, i in [yTicks...]
-      continue if i is 0 # skip first value
+    for tick, i in [yTicks...]
+      # continue if i is 0 # skip first value
+      console.log 'tick: ', tick
+
+      tickPos = @toCanvasYCoord(tick)       # transform to canvas coordinate
+      tickPos = -tickPos + @canvas.height   # flip y-axis
+
       # draw ticks
       @ctx.beginPath()
-      @ctx.moveTo( 0, @toCanvasYCoord(tickPos) )
+      @ctx.moveTo( 0, tickPos )
       if i % nIntervals is 0
-        @ctx.lineTo( tickMajorLength, @toCanvasYCoord(tickPos) ) # major tick
+        @ctx.lineTo( tickMajorLength, tickPos ) # major tick
       else
-        @ctx.lineTo( tickMinorLength, @toCanvasYCoord(tickPos) ) # minor tick
+        @ctx.lineTo( tickMinorLength, tickPos ) # minor tick
       @ctx.lineWidth = tickWidth
       @ctx.strokeStyle = tickColor
       @ctx.stroke()
@@ -279,9 +284,9 @@
       @ctx.font = '10pt Arial'
       @ctx.textAlign = 'center'
       @ctx.fillStyle = textColor
-      # @ctx.fillText( tickPos.toFixed(2), 0+textSpacing+10, -(@toCanvasYCoord(tickPos)+5)+@canvas.height )
+      # @ctx.fillText( tick.toFixed(2), 0+textSpacing+10, -(@toCanvasYCoord(tick)+5)+@canvas.height )
       # flip about y-axis
-      @ctx.fillText( tickPos.toFixed(2), 0+textSpacing+10, @toCanvasYCoord(tickPos)+5 )
+      @ctx.fillText( tick.toFixed(2), 0+textSpacing+10, tickPos+5 )

     # # X-AXIS
     # # display 'days' label


Ensure help dialog is scrollable.

Ensure help dialog is scrollable.

When we open the help dialog, scroll it, close it then open it again,
the scroller loses track of the scrollable element.  This is because the
scroller is still referenceing the old scrollable content as its
"activated element".

Here, we click the dialog element to get the scroller back in sync.

(Note:  This is a more general problem which we need to look into.)

--- pages/help_dialog.coffee
+++ pages/help_dialog.coffee
@@ -42,6 +42,9 @@
           chrome.runtime.sendMessage handler: "copyToClipboard", data: commandName
           HUD.showForDuration("Yanked #{commandName}.", 2000)

+    # "Click" the dialog element (so that it becomes scrollable).
+    DomUtils.simulateClick @dialogElement
+
   hide: -> UIComponentServer.hide()
   toggle: -> @hide()


Add room number

Add room number

--- server/materials/data/level_about.coffee
+++ server/materials/data/level_about.coffee
@@ -1423,8 +1423,7 @@
         Правила получения зачета

ВШЭ

Только для школьников

-
Занятия проходят по воскресеньям в нижегородском филиале ВШЭ по адресу ул. Костина, д. 2б (вход с пл. Горького, дверь справа от центра оперативной печати, проходите здание насквозь и во дворе вход в нужное здание). Точные аудитории будут указаны после первого занятия,
-        пока просто звоните.

+
Занятия проходят по воскресеньям в нижегородском филиале ВШЭ по адресу ул. Костина, д. 2б (вход с пл. Горького, дверь справа от центра оперативной печати, проходите здание насквозь и во дворе вход в нужное здание), аудитория 203 (2 этаж).

Берите с собой паспорт или свидетельство о рождении. Если вас не пускает охрана, звоните мне.


fix search bar

fix search bar

--- lib/browser-plus-view.coffee
+++ lib/browser-plus-view.coffee
@@ -358,7 +358,7 @@
                 urls.protocol = 'http'
                 url = URL.format(urls)

-            @goToUrl(url)
+          @goToUrl(url)

       @refresh.on 'click', (evt)=>
         return if @model.uri is 'browser-plus://history'


Added heading

Added heading

--- scripts/jeb.coffee
+++ scripts/jeb.coffee
@@ -1,3 +1,11 @@
+exec  = require('child_process').exec
+
+execCommand = (msg, cmd) ->
+  exec cmd, (error, stdout, stderr) ->
+    msg.send error
+    msg.send stdout
+    msg.send stderr
+
 module.exports = (robot) ->

    robot.hear /jeb/i, (res) ->


remove class name from title of DocDetail

--- src/renderer/components/doc-detail-title-component.coffee
+++ src/renderer/components/doc-detail-title-component.coffee
@@ -6,9 +6,6 @@
 class DocDetailTitleComponent extends React.Component
   constructor: (props) ->
     super props
-
-  close: ->
-    @context.ctx.routeAction.navigate(document.location.pathname.match(/^(.+)\/[^\/]+$/)[1])

   genKindStringStyle: (kindString) ->
     color = '#333333'
@@ -35,7 +32,7 @@

{@props.current.kindString}

-          {@props.from.name}.{@props.current.name}
+          .{@props.current.name}

       <DocSignaturesComponent style={styles.signatures} current={@props.current} />


add "inherited from"

add "inherited from"

--- src/renderer/components/doc-detail-title-component.coffee
+++ src/renderer/components/doc-detail-title-component.coffee
@@ -37,6 +37,10 @@
           .{@props.current.name}

+      {
+        if @props.current.inheritedFrom?
+
{"Inherited from #{@props.current.inheritedFrom.name.replace(/__constructor/, 'constructor')}"}

+      }
       <DocSignaturesComponent style={styles.signatures} current={@props.current} />

@@ -72,6 +76,11 @@
     textDecoration: 'underline'
     cursor: 'pointer'

+  from:
+    marginTop: 10
+    fontSize: 15
+    color: colors.general.r.light
+
   signatures:
     marginTop: 23


All tests based on onCanPlay

All tests based on onCanPlay

--- spec/javascripts/audio_async_spec.coffee
+++ spec/javascripts/audio_async_spec.coffee
@@ -37,22 +37,18 @@
     done()

   it 'has correct audio source', (done) ->
-    setTimeout ->
+    no1.onCanPlay ->
       expect(no1.audio.currentSrc).toMatch /lib\/audio\/acoustic-b\.m4a/
       expect(no1.audio.currentSrc).not.toBe ''
       done()
-    , LOADING_TIMEOUT
-  , TEST_TIMEOUT

   it 'has correct audio duration', (done) ->
-    setTimeout ->
+    no1.onCanPlay ->
       expect(no1.audio.duration // 1).toBe 4
       done()
-    , LOADING_TIMEOUT
-  , TEST_TIMEOUT

   it 'seekPercent() works', (done) ->
-    setTimeout ->
+    no1.onCanPlay ->
       no1.seekPercent 0
       expect(no1.audio.currentTime // 1).toBe 0
       no1.seekPercent 50
@@ -62,11 +58,9 @@
       no1.seekPercent 150
       expect(no1.audio.currentTime // 1).toBe 4
       done()
-    , LOADING_TIMEOUT
-  , TEST_TIMEOUT

   it 'seekToTime() works', (done) ->
-    setTimeout ->
+    no1.onCanPlay ->
       no1.seekToTime 0
       expect(no1.audio.currentTime // 1).toBe 0
       no1.seekToTime 3
@@ -78,20 +72,16 @@
       no1.seekToTime '1:10'
       expect(no1.audio.currentTime // 1).toBe 4
       done()
-    , LOADING_TIMEOUT
-  , TEST_TIMEOUT

   it 'seekToTime() calls and return', (done) ->
     spyOn no1, 'updatePlayedProgress'
     spyOn no1, 'updateTimeStatuses'
-    setTimeout ->
+    no1.onCanPlay ->
       # Return value doesn't depend on canPlayCurrent
       expect(no1.seekToTime('00:01').seekToTime '00:02').toBe no1
       expect(no1.updatePlayedProgress).toHaveBeenCalledWith()
       expect(no1.updateTimeStatuses).toHaveBeenCalledWith()
       done()
-    , LOADING_TIMEOUT
-  , TEST_TIMEOUT

   it 'seekPercent() calls', (done) ->
     spyOn(no1, 'updatePlayedProgress').and.callThrough()


client orders js javítás

client orders js javítás

--- src/JCSGYK/AdminBundle/Resources/public/js/jcscatering.coffee
+++ src/JCSGYK/AdminBundle/Resources/public/js/jcscatering.coffee
@@ -135,7 +135,7 @@
                 $(this).find("input").attr("disabled","disabled")

     prepareOrders: ->
-        orders = []
+        orders = {}
         $("li.day.modifiable").each ->
             if $(this).data("order") == "order"
                 orders[$(this).data("date")] = 1
@@ -144,7 +144,7 @@
         $("input[name=orders]").val(JSON.stringify(orders))

     processOrders: ->
-        orders = []
+        orders = {}
         $("li.day.modifiable").each ->
             if $(this).data("new_order") isnt undefined and $(this).data("new_order") is "reorder"
                 orders[$(this).data("date")] = 1


Use the improved empty message text from Kevin's issue report

--- src/coffee/cilantro/ui/query/item.coffee
+++ src/coffee/cilantro/ui/query/item.coffee
@@ -11,7 +11,13 @@
     class EmptyQueryItem extends base.EmptyView
         icon: false

-        message: 'You have not yet created any queries or have had any shared with you'
+        align: 'left'
+
+        message: 'You don't have any saved or shared queries yet.
+

+            You can save a query for future use by clicking the "Create Query" button at the top of the Results page.
+

+            You can also share a saved query with specific users, either at the time you save the query or by editing the query within your workspace.'

     class QueryItem extends Marionette.ItemView
         className: 'row-fluid'


logger bug fix

logger bug fix

--- modules/log._coffee
+++ modules/log._coffee
@@ -21,7 +21,7 @@
         #log.title = title
         #log.content = content
         #log.save console.log
-        @client.log '0bf69f08-e6f2-4c42-8f39-4b5a606c8c90', "#{title}: ${content}"
+        @client.log '0bf69f08-e6f2-4c42-8f39-4b5a606c8c90', "#{title}: #{content}"

     logActivity: (title, content, _) =>
         title = "Activity: #{title}"


Disable script execution in loaded templates

--- nodejs/palsu.coffee
+++ nodejs/palsu.coffee
@@ -18,6 +18,10 @@
     server.use '/js', express.static "#{process.cwd()}//js"
     server.use browserify
         require: [ 'jquery-browserify' ]
+
+jsdom.defaultDocumentFeatures =
+    FetchExternalResources: ['script'],
+    ProcessExternalResources: false

 # Serve the list of meetings for /
 server.get '/', (request, response) ->


tsd task as default

tsd task as default

--- public/Gruntfile.coffee
+++ public/Gruntfile.coffee
@@ -62,4 +62,4 @@
     grunt.loadNpmTasks taskName

   grunt.registerTask('compile', ['typescript', 'compass', 'cmq', 'csscomb']);
-  grunt.registerTask('default', ['bower:install', 'compile']);
+  grunt.registerTask('default', ['bower:install', 'tsd', 'compile']);


fix align variable name

fix align variable name

--- lib/insert-image-view.coffee
+++ lib/insert-image-view.coffee
@@ -33,7 +33,7 @@
           @subview "heightEditor", new EditorView(mini: true)
         @div class: "col-2", =>
           @label "Alignment", class: "message"
-          @subview "positionEditor", new EditorView(mini: true)
+          @subview "alignEditor", new EditorView(mini: true)
       @div class: "image-container", =>
         @img outlet: 'imagePreview'

@@ -53,7 +53,7 @@
       alt: @titleEditor.getText()
       width: @widthEditor.getText()
       height: @heightEditor.getText()
-      position: @positionEditor.getText()
+      align: @alignEditor.getText()
       slug: utils.getTitleSlug(@editor.getPath())
     text = if img.src then @generateImageTag(img) else img.alt
     @editor.insertText(text)
@@ -110,7 +110,7 @@
         @widthEditor.setText("" + naturalWidth)
         @heightEditor.setText("" + naturalHeight)
         position = if naturalWidth > 300 then "center" else "right"
-        @positionEditor.setText(position)
+        @alignEditor.setText(position)
       @imagePreview.error =>
         @message.text("Error: Failed to Load Image.")
     else
@@ -118,7 +118,7 @@
       @imagePreview.attr("src", "")
       @widthEditor.setText("")
       @heightEditor.setText("")
-      @positionEditor.setText("")
+      @alignEditor.setText("")

   isValidImageFile: (file) ->
     path.extname(file).toLowerCase() in imageExtensions


Build: do npm i before gulp compile for framework dependencies

--- Builder.coffee
+++ Builder.coffee
@@ -70,7 +70,7 @@
   buildFramework:->

     @config ?= require('koding-config-manager').load("main.#{options.configFile}")
-    cmd = "cd client/Framework;gulp compile --buildVersion=#{@config.client.version} --outputDir=../../website/a/"
+    cmd = "cd client/Framework;npm i;gulp compile --buildVersion=#{@config.client.version} --outputDir=../../website/a/"
     exec cmd, (err, stdout, stderr)->
       console.warn "------------------------ FRAMEWORK COMPILED -------------------------- "
       console.warn " To use watcher for Framework use following command in different tab:  "


Converted the level select view into an atom-select-list view

--- lib/level-select-view.coffee
+++ lib/level-select-view.coffee
@@ -1,92 +1,78 @@
-{SelectListView} = require('atom-space-pen-views')
-
-workspace        = require('./workspace').getInstance()
-
-# ------------------------------------------------------------------------------
+SelectListView = require 'atom-select-list'
+workspace      = require('./workspace').getInstance()

 module.exports =
-class LevelSelectView extends SelectListView
-
-  ## Initialization and destruction --------------------------------------------
-
-  initialize: (@workspaceManager) ->
-    super
-    @addClass('levels-view level-select')
+class LevelSelectView
+  constructor: ->
+    @selectListView = new SelectListView
+      items: [],
+      filterKeyForItem: (level) -> level.getName(),
+      elementForItem: (level) => @viewForLevel level,
+      didCancelSelection: => @cancel(),
+      didConfirmSelection: (level) => @confirm level

   destroy: ->
     @cancel()
+    @selectListView.destroy()

-  cancelled: ->
-    @modalPanel?.destroy()
-    @modalPanel = null
+  cancel: ->
+    @panel?.destroy()
+    @panel = null

-  ## Overwritten list view methods ---------------------------------------------
+    @previouslyFocusedElement?.focus()
+    @previouslyFocusedElement = null

-  getFilterKey: ->
-    'filterKey'
+  attach: ->
+    @previouslyFocusedElement = document.activeElement
+    @panel ?= atom.workspace.addModalPanel item: @selectListView

-  confirmed: ({level}) ->
+    @selectListView.focus()
+    @selectListView.reset()
+
+  confirm: (level) ->
     @cancel()
-    unless level.getName() is @activeLevel.getName()
-      @activeLevelCodeEditor.setLevel(level)
-      @activeLanguage.setLastActiveLevel(level)
+    if level.getName() != @activeLevel.getName()
+      @activeLevelCodeEditor.setLevel level
+      @activeLanguage.setLastActiveLevel level

-  viewForItem: ({level}) ->
-    listElement = document.createElement('li')
-
-    if level.getDescription()?
-      listElement.classList.add('two-lines')
-      # define the primary line (level name)
-      nameElement = document.createElement('div')
-      if level is @activeLevel
-        nameElement.classList.add('primary-line','icon','icon-triangle-right')
-      else
-        nameElement.classList.add('primary-line','no-icon')
-      nameElement.textContent = level.getName()
-      # define the secondary line (level description)
-      descrElement = document.createElement('div')
-      descrElement.classList.add('secondary-line','no-icon')
-      descrElement.textContent = level.getDescription()
-      # append lines to the list element
-      listElement.appendChild(nameElement)
-      listElement.appendChild(descrElement)
+  toggle: ->
+    if @panel
+      @cancel()
     else
-      nameElement = document.createElement('span')
-      if level is @activeLevel
-        nameElement.classList.add('icon','icon-triangle-right')
-      else
-        nameElement.classList.add('no-icon')
-      nameElement.textContent = level.getName()
-      # append line to the list element
-      listElement.appendChild(nameElement)
-
-    listElement.dataset.level = level.getName()
-    listElement
-
-  ## Updating this view --------------------------------------------------------
+      @update workspace.getActiveLevelCodeEditor()
+      @attach()

   update: (@activeLevelCodeEditor) ->
     @activeLanguage = @activeLevelCodeEditor.getLanguage()
     @activeLevel = @activeLevelCodeEditor.getLevel()
-    @setItems @activeLanguage.getLevels().map (level) ->
-      filterKey: "#{level.getName()} #{level.getDescription()}"
-      level: level
+    @selectListView.update items: @activeLanguage.getLevels()

-  ## Showing and hiding this view ----------------------------------------------
+  viewForLevel: (level) ->
+    listElement = document.createElement 'li'
+    listElement.dataset.level = level.getName()

-  toggle: ->
-    if @modalPanel?
-      @hide()
+    if level.getDescription()
+      listElement.className = 'two-lines'
+
+      nameElement = document.createElement 'div'
+      if level == @activeLevel
+        nameElement.className = 'primary-line icon icon-triangle-right'
+      else
+        nameElement.className = 'primary-line no-icon'
+      nameElement.textContent = level.getName()
+      listElement.appendChild nameElement
+
+      descElement = document.createElement 'div'
+      descElement.className = 'secondary-line no-icon'
+      descElement.textContent = level.getDescription()
+      listElement.appendChild descElement
     else
-      @update(workspace.getActiveLevelCodeEditor())
-      @show()
+      nameElement = document.createElement 'span'
+      if level == @activeLevel
+        nameElement.className = 'icon icon-triangle-right'
+      else
+        nameElement.className = 'no-icon'
+      nameElement.textContent = level.getName()
+      listElement.appendChild nameElement

-  show: ->
-    @storeFocusedElement()
-    @modalPanel ?= atom.workspace.addModalPanel(item: @)
-    @focusFilterEditor()
-
-  hide: ->
-    @cancel()
-
-# ------------------------------------------------------------------------------
+    return listElement


CollectionBinding fixup

CollectionBinding fixup

--- src/view/bindings/class_binding.coffee
+++ src/view/bindings/class_binding.coffee
@@ -20,5 +20,3 @@
       @node.className = array.join ' '

   handleArrayChanged: => @updateFromCollection()
-  handleItemsWereRemoved: => @updateFromCollection()
-  handleItemsWereAdded: => @updateFromCollection()


为AbstractEditor添加一个类型判断保护

为AbstractEditor添加一个类型判断保护

--- src/widget/edit/abstract-editor.coffee
+++ src/widget/edit/abstract-editor.coffee
@@ -82,7 +82,7 @@
 				if entity instanceof cola.EntityList
 					entity = entity.current
 				if entity
-					keyMessage = entity.getKeyMessage(@_bindInfo.property)
+					keyMessage = entity.getKeyMessage?(@_bindInfo.property)
 					@set("state", keyMessage?.type)

 		if type isnt cola.constants.MESSAGE_VALIDATION_STATE_CHANGE


Use the description and URL when present

--- lib/snippets-provider.coffee
+++ lib/snippets-provider.coffee
@@ -22,6 +22,8 @@
       text: snippet.prefix
       replacementPrefix: prefix
       rightLabel: snippet.name
+      description: snippet.description
+      descriptionMoreURL: snippet.descriptionMoreURL

   onDidInsertSuggestion: ({editor}) ->
     atom.commands.dispatch(atom.views.getView(editor), 'snippets:expand')


HIRE-175: fixed a bug.

HIRE-175: fixed a bug.

--- src/main/java/app/profile/profile.coffee
+++ src/main/java/app/profile/profile.coffee
@@ -141,7 +141,7 @@
     data.locations = currentProjectAssociation.project.locations.slice() if currentProjectAssociation.project.locations?
     data.technologies = currentProjectAssociation.project.technologies.slice() if currentProjectAssociation.project.technologies?
     data.start = moment(currentProjectAssociation.project.start).format(dateFormat) if moment(currentProjectAssociation.project.start).isValid()
-    data.end = moment(currentProjectAssociation.project.end).format(dateFormat) if moment(currentProjectAssociation.project.start).isValid()
+    data.end = moment(currentProjectAssociation.project.end).format(dateFormat) if moment(currentProjectAssociation.project.end).isValid()
     $scope.projectData.splice(index, 1, data)
     $scope.loadProjectDefaultsIfFieldIsEmpty(index)
     return


Remove empty package-generator keymap

Remove empty package-generator keymap


tweak

tweak

Former-commit-id: 9e359edd43876edea6dc03a6ec19653b1d436ad9 [formerly e00ed7dfe09250024057421d66f4b5b73cc199df] [formerly 784e7346b5caca04b3a28c1b125e3e5b21d8cbba [formerly 3250308feb9754dae553913f6ef87023e46fa369]] [formerly c740f659c358cf7140bc35f9294f9c4ed11be2fc [formerly 84b34301c53f4e12b641b4846d614046c1e5cbe7] [formerly a84d8a3764bd38c1084d12a639470925d19130a1 [formerly a84d8a3764bd38c1084d12a639470925d19130a1 [formerly e89358028575632adb2189d999aaace7337f6cd0]]]]
Former-commit-id: b1da5107e2ba65bddda65e516caea5bd7860ebed [formerly 96e67183178bc7503fbc0c13a7ff332aa8cf5414] [formerly adc2ee5561a259c47e079639bc3a8f08cb85093c [formerly 30bf2f2c7c7f748eeba6371ae706e004d75a5c49]]
Former-commit-id: bc600613c8dc7530d73577da7ac6b9fecc57bde5 [formerly 9a1be48120cb9db64dfe97b6a9f688772c5f608d]
Former-commit-id: 0a7a365127d184f6ee06b38e78d876bfe8d905c1
Former-commit-id: 686bdfd813c170d874047237aa596e30e226f16c

--- @client/swapables.coffee
+++ @client/swapables.coffee
@@ -88,7 +88,7 @@
             id: 'watching_filter'
             style:
               position: 'absolute'
-              left: if lefty then 112 else -100
+              left: if lefty then 112 else -87
               top: 5
               border: "1px solid #bbb"
               opacity: if !filter.watched && !@local.hover_watch_filter then .3
@@ -105,8 +105,8 @@
               tooltip.coords = $(@getDOMNode()).find('#watching_filter').offset()
               tooltip.tip = "Filter proposals to those you're watching"
               save tooltip
-
               save @local
+
             onMouseLeave: =>
               @local.hover_watch_filter = false
               save @local


Update da.coffee

Update da.coffee

Added header wit language name and reference to translator

--- t9n/da.coffee
+++ t9n/da.coffee
@@ -1,5 +1,5 @@
-# We need a dummy translation so that a text is found.
-
+#Language: Danish
+#Translators: LarsBuur

 da =

@@ -111,4 +111,4 @@
       "Unknown error": "Ukendt fejl"

-T9n.map "da", da+T9n.map "da", da


Fix #24

Fix #24

--- lib/view/input-editor.coffee
+++ lib/view/input-editor.coffee
@@ -3,7 +3,7 @@
 {QueryCancelledError} = require './../error'
 parse = require './../parser'
 Promise = require 'bluebird'
-{CompositeDisposable, TextEditor} = require 'atom'
+{CompositeDisposable} = require 'atom'

 Vue.component 'panel-input-editor',
     template: '<atom-text-editor mini></atom-text-editor>'


Add overview section with window load time

--- lib/window-panel-view.coffee
+++ lib/window-panel-view.coffee
@@ -5,18 +5,75 @@
   @content: ->
     @div class: 'tool-panel padded', =>
       @div class: 'inset-panel', =>
-        @div class: 'panel-heading', 'Window Loading'
+        @div class: 'panel-heading', 'Overview'
         @div class: 'panel-body padded', =>
-          @div class: 'text-info', outlet: 'summary'
-          @ul class: 'list-group', outlet: 'list'
+          @ul class: 'list-group', =>
+            @li class: 'list-item', =>
+              @span class: 'inline-block', 'Total Load Time'
+              @span class: 'inline-block', outlet: 'windowLoading',
+            @li class: 'list-item', =>
+              @span class: 'inline-block', 'Package Loading'
+              @span class: 'inline-block', outlet: 'packageLoading'
+            @li class: 'list-item', =>
+              @span class: 'inline-block', 'Package Activation'
+              @span class: 'inline-block', outlet: 'packageActivation'
+            @li class: 'list-item', =>
+              @span class: 'inline-block', 'Theme Loading'
+              @span class: 'inline-block', outlet: 'themeLoading'
+            @li class: 'list-item', =>
+              @span class: 'inline-block', 'Theme Activation'
+              @span class: 'inline-block', outlet: 'themeActivation'

-  populate: ->
-    @list.empty()
+  updateWindowTime: ->
+    highlightClass = 'highlight-success'
+    highlightClass = 'highlight-warning' if atom.getWindowLoadTime() > 800
+    highlightClass = 'highlight-error' if atom.getWindowLoadTime() > 1000
+    @windowLoading.addClass(highlightClass)
+    @windowLoading.text("#{atom.getWindowLoadTime()}ms")

-    @list.append $$ ->
-      @li class: 'list-item', =>
-        @span class: 'inline-block', 'Total Time'
-        highlightClass = 'highlight-success'
-        highlightClass = 'highlight-warning' if atom.getWindowLoadTime() > 800
-        highlightClass = 'highlight-error' if atom.getWindowLoadTime() > 1000
-        @span class: "inline-block #{highlightClass}", "#{atom.getWindowLoadTime()}ms"
+  updatePackageLoadingTime: ->
+    time = 0
+    for pack in atom.packages.getLoadedPackages() when pack.getType() isnt 'theme'
+      time += pack.loadTime
+    highlightClass = 'highlight-success'
+    highlightClass = 'highlight-warning' if time > 250
+    highlightClass = 'highlight-error' if time > 500
+    @packageLoading.addClass(highlightClass)
+    @packageLoading.text("#{time}ms")
+
+  updatePackageActivationTime: ->
+    time = 0
+    for pack in atom.packages.getActivePackages() when pack.getType() isnt 'theme'
+      time += pack.activateTime
+    highlightClass = 'highlight-success'
+    highlightClass = 'highlight-warning' if time > 250
+    highlightClass = 'highlight-error' if time > 500
+    @packageActivation.addClass(highlightClass)
+    @packageActivation.text("#{time}ms")
+
+  updateThemeLoadingTime: ->
+    time = 0
+    for pack in atom.packages.getLoadedPackages() when pack.getType() is 'theme'
+      time += pack.loadTime
+    highlightClass = 'highlight-success'
+    highlightClass = 'highlight-warning' if time > 50
+    highlightClass = 'highlight-error' if time > 100
+    @themeLoading.addClass(highlightClass)
+    @themeLoading.text("#{time}ms")
+
+  updateThemeActivationTime: ->
+    time = 0
+    for pack in atom.packages.getActivePackages() when pack.getType() is 'theme'
+      time += pack.activateTime
+    highlightClass = 'highlight-success'
+    highlightClass = 'highlight-warning' if time > 50
+    highlightClass = 'highlight-error' if time > 100
+    @themeActivation.addClass(highlightClass)
+    @themeActivation.text("#{time}ms")
+
+  populate:  ->
+    @updateWindowTime()
+    @updatePackageLoadingTime()
+    @updatePackageActivationTime()
+    @updateThemeLoadingTime()
+    @updateThemeActivationTime()


Add footer callback in report data tables to recalculate & render table totals on filering event

--- app/assets/javascripts/data-tables-init.coffee
+++ app/assets/javascripts/data-tables-init.coffee
@@ -1,13 +1,29 @@
 $(document).on "page:change", ->
   $(".data-table").each ->
     table = $(@)
+
+    return if $.fn.dataTable.isDataTable(table)

-    return if $.fn.dataTable.isDataTable(table)
+    fnFooterCallback = (row, data, start, end, display) ->
+      monetaryColumnIndex = 1
+
+      # Utility function to convert string dollar amount to a number
+      intVal = (i) ->
+        if typeof i == 'string' then i.replace(/[\$,]/g, '') * 1 else if typeof i == 'number' then i else 0
+
+      # Calculate the total for the current page
+      pageTotal = @api().column(monetaryColumnIndex, page: 'current').data().reduce(((a, b) ->
+        intVal(a) + intVal(b)
+      ), 0).toFixed(2)
+
+      # Render the pageTotal on the bottom footer.
+      $(@api().column(monetaryColumnIndex).footer()).html '$'+ pageTotal

     options =
       responsive: true
       order: [[0, "desc"]]
       pageLength: 25
+      fnFooterCallback: fnFooterCallback

     ascColumn = table.find("th.sort-asc").index()
     descColumn = table.find("th.sort-desc").index()
@@ -21,4 +37,4 @@
     if table.hasClass("no-paging")
       options["paging"] = false

-    table.dataTable(options)
+    table.dataTable(options)


Adjusted timezone issue

Adjusted timezone issue

--- app/assets/javascripts/utils/helpers.js.coffee
+++ app/assets/javascripts/utils/helpers.js.coffee
@@ -14,6 +14,6 @@
   ###
   @convertDateTime: (input) ->
     if moment(input, 'X', true).isValid()
-      moment.utc(input, 'X').toDate()
+      moment(input, 'X').toDate()
     else
-      moment.utc(input, 'MM/DD/YYYY hh:mm A').toDate()
+      moment(input, 'MM/DD/YYYY hh:mm A').toDate()


ugly, but 1 minutes is uglier

ugly, but 1 minutes is uglier

--- app/assets/javascripts/views/navigation.coffee
+++ app/assets/javascripts/views/navigation.coffee
@@ -84,9 +84,9 @@
       if Math.abs(time_delta) < 360
         # TODO: Move tags stuff into templates
         if time_delta > 0
-          readable_time_delta = "#{Math.abs(time_delta)} minutes early"
+          readable_time_delta = "#{Math.abs(time_delta)} minute#{if time_delta > 1 then 's' else ''} early"
         else if time_delta < 0
-          readable_time_delta = "#{Math.abs(time_delta)} minutes late"
+          readable_time_delta = "#{Math.abs(time_delta)} minute#{if time_delta < -1 then 's' else ''}  late"
         else
           readable_time_delta = 'on time'


JWorkspace: use `/` as rootPath if machine provider is managed

--- workers/social/lib/social/models/workspace.coffee
+++ workers/social/lib/social/models/workspace.coffee
@@ -182,8 +182,8 @@
       return callback 'Machine not found'  unless machine

       {nickname} = client.connection.delegate.profile
-
-      selector = {machineUId, slug: 'my-workspace'}
+      rootPath   = '/'  if machine.provider is 'managed'
+      selector   = {machineUId, slug: 'my-workspace'}

       @one selector, (err, workspace) =>

@@ -194,12 +194,12 @@

           return callback err  if err

-          data =
+          data           =
             name         : 'My Workspace'
             isDefault    : yes
             machineLabel : machine.label
             machineUId   : machine.uid
-            rootPath     : "/home/#{nickname}"
+            rootPath     : rootPath ? "/home/#{nickname}"
             originId     : account.getId()

           @create client, data, callback


hub/stats: add duration in secs to debug output

--- src/smc-hub/postgres-server-queries.coffee
+++ src/smc-hub/postgres-server-queries.coffee
@@ -1975,8 +1975,9 @@
         opts = defaults opts,
             ttl : 120         # how long cached version lives (in seconds)
             cb  : undefined
-        stats = undefined
-        dbg = @_dbg('get_stats')
+        stats   = undefined
+        start_t = process.hrtime()
+        dbg     = @_dbg('get_stats')
         async.series([
             (cb) =>
                 dbg("using cached stats?")
@@ -2041,7 +2042,9 @@
                     if err
                         cb(err)
                     else
-                        dbg("everything succeeded in parallel above -- now insert stats")
+                        elapsed_t = process.hrtime(start_t)
+                        duration_s = (elapsed_t[0] + elapsed_t[1] / 1e9).toFixed(4)
+                        dbg("everything succeeded in parallel above after #{duration_s} secs -- now insert stats")
                         # storing in local and db cache
                         stats.id = misc.uuid()
                         @_stats_cached = misc.deep_copy(stats)


Hide playmode tabs when showing warning

Hide playmode tabs when showing warning

--- resources/assets/coffee/react/beatmapset-page/main.coffee
+++ resources/assets/coffee/react/beatmapset-page/main.coffee
@@ -239,14 +239,17 @@

   renderPageHeader: =>
-    el HeaderV4,
-      theme: 'beatmapsets'
-      titleAppend: el PlaymodeTabs,
+    unless @state.showingNsfwWarning
+      titleAppend = el PlaymodeTabs,
         beatmaps: @state.beatmaps
         currentMode: @state.currentBeatmap.mode
         hrefFunc: @tabHrefFunc
         showCounts: true

+    el HeaderV4,
+      theme: 'beatmapsets'
+      titleAppend: titleAppend
+
   saveStateToContainer: =>
     @props.container.dataset.state = JSON.stringify(@state)


Decrease preview volume

Decrease preview volume

--- resources/assets/coffee/react/beatmapset-page/main.coffee
+++ resources/assets/coffee/react/beatmapset-page/main.coffee
@@ -166,6 +166,7 @@
     @setCurrentScoreboard null, scoreboardType: 'global', resetMods: true

     @audioPreview = document.getElementsByClassName('js-beatmapset-page--audio-preview')[0]
+    @audioPreview.volume = 0.45

   componentWillUnmount: ->
     @removeListeners()


Temp. make allocation's projects async.

Temp. make allocation's projects async.

--- t2-people/app/models/allocation.coffee
+++ t2-people/app/models/allocation.coffee
@@ -2,7 +2,7 @@
 Allocation = DS.Model.extend
   startDate: DS.attr('date')
   endDate: DS.attr('date')
-  project: DS.belongsTo('project')
+  project: DS.belongsTo('project', {async: true})
   person: DS.belongsTo('person')

   billable: DS.attr('boolean')


Fix error trying to observe guest user's nonexistent cover

--- resources/assets/coffee/_classes/current-user-observer.coffee
+++ resources/assets/coffee/_classes/current-user-observer.coffee
@@ -18,7 +18,7 @@

     # one time setup to monitor cover url variable. No disposer because nothing destroys this object.
     $ =>
-      reaction((=> core.currentUser.cover.url), @setCovers)
+      reaction((=> core.currentUser?.cover.url), @setCovers)

   reinit: =>


Log instead of throwing compilation errors

--- tasks/compile.coffee
+++ tasks/compile.coffee
@@ -22,8 +22,8 @@
   [dist, dir] = item

   handleError = (err) ->
+    console.error err
     beeper()
-    throw err

   # Compile menus
   gulp.task 'compile:' + dist + ':menus', ['clean:build:' + dist], ->


Fixes require of logger in preload scripts

--- tasks/compile.coffee
+++ tasks/compile.coffee
@@ -41,7 +41,7 @@
     loggerHeader = [
       "if (__filename.indexOf('logger.js') == -1)"
       "{"
-      "var __LOGGER = require.main.require('./utils/logger');"
+      "var __LOGGER = require(require('app').getAppPath() + '/scripts/browser/utils/logger');"
       "var log = __LOGGER.debugLogger(__filename);"
       "var logError = __LOGGER.errorLogger(__filename, false);"
       "var logFatal = __LOGGER.errorLogger(__filename, true);"
@@ -72,7 +72,7 @@
     loggerHeader = [
       "if (__filename.indexOf('logger.js') == -1)"
       "{"
-      "var __LOGGER = require.main.require('../scripts/renderer/logger');"
+      "var __LOGGER = require(require('remote').app.getAppPath() + '/scripts/renderer/logger');"
       "var log = __LOGGER.debugLogger(__filename);"
       "var logError = __LOGGER.errorLogger(__filename, false);"
       "var logFatal = __LOGGER.errorLogger(__filename, true);"


Make highlights async, use process.stdout.write not console.log

console.log can do formatting of javascript data structures
Hopefully will be faster printing that way.

Not sure if making it async will make it faster, the same,
or slowing though.

--- highlights/highlight-filename-from-stdin.coffee
+++ highlights/highlight-filename-from-stdin.coffee
@@ -7,19 +7,19 @@
 highlighter.requireGrammarsSync
   modulePath: require.resolve('./atom-language-perl6/package.json')

-
 stdin = process.openStdin()
 stdin.setEncoding 'utf8'
 mystderr = process.stderr
+mystdout = process.stdout
+foo = (full_path) ->
+  fs.readFile full_path, 'utf8', (err, file_str) ->
+    if err
+      console.error err
+    else
+      mystdout.write highlighter.highlightSync(
+        fileContents: file_str
+        scopeName: 'source.perl6fe'
+      ) + '\n'
+
 stdin.on 'data', (input) ->
-    name = input.trim()
-    process.exit() if name == 'exit'
-    file_to_hl = path.resolve(name)
-    foo = ->
-      fs.readFileSync file_to_hl, 'utf8'
-
-    html = highlighter.highlightSync
-      fileContents: foo()
-      scopeName: 'source.perl6fe'
-
-    console.log html
+    foo path.resolve input.trim()


partial test fixing

partial test fixing

--- server/test/Component/Builtin/Database/CouchMuffin.coffee
+++ server/test/Component/Builtin/Database/CouchMuffin.coffee
@@ -45,10 +45,11 @@
             stdResult = stdMyData.MyKey

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    touch: (id, expiry, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        touch: (id, expiry, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -66,10 +67,11 @@
             stdResult = stdMyData.MyKey

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    touch: (id, expiry, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        touch: (id, expiry, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -84,10 +86,11 @@
             stdResult = null

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    touch: (id, expiry, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        touch: (id, expiry, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -104,10 +107,11 @@
             stdResult = stdMyData.MyKey

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    get: (info, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        get: (info, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -122,10 +126,11 @@
             stdResult = null

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    get: (info, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        get: (info, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -142,10 +147,11 @@
             stdResult = stdMyData

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    getMulti: (info, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        getMulti: (info, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -160,10 +166,11 @@
             stdResult = null

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    getMulti: (info, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        getMulti: (info, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -183,10 +190,11 @@
                 id: 'MyKey'

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    remove: (id, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        remove: (id, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -203,10 +211,11 @@
                 id: 'MyKey'

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    remove: (id, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        remove: (id, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -226,10 +235,11 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    replace: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        replace: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -251,10 +261,11 @@
                 options: stdOptions

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    replace: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        replace: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -272,10 +283,11 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    replace: (id, data, options, callback) ->
-                        callback stdError, null
+                limbo:
+                    _bucket:
+                        replace: (id, data, options, callback) ->
+                            callback stdError, null
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -292,10 +304,11 @@
                 id: 'MyKey'

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    replace: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        replace: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -315,10 +328,11 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -341,10 +355,11 @@

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -362,10 +377,11 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, null
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, null
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -382,10 +398,11 @@
                 id: 'MyKey'

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -402,10 +419,11 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -423,12 +441,13 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult
-                    counter: (id, delta, callback) ->
-                        callback null, 1
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                        counter: (id, delta, callback) ->
+                            callback null, 1
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -448,13 +467,14 @@
                 code: 13

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult if data != 1
-                        callback null, 1 if data == 1
-                    counter: (id, delta, callback) ->
-                        callback errorNotExist
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult if data != 1
+                            callback null, 1 if data == 1
+                        counter: (id, delta, callback) ->
+                            callback errorNotExist
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -472,10 +492,11 @@
                 data: stdResult

             loader.mockComponent 'DataSource.Couchbase',
-                init: ->
-                bucket:
-                    insert: (id, data, options, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        insert: (id, data, options, callback) ->
+                            callback stdError, stdResult
+                init: ->

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -508,13 +529,13 @@

             loader.mockComponent 'DataSource.Couchbase',
                 init: ->
-                bucket:
-                    query: (query, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        query: (query, callback) ->
+                            callback stdError, stdResult
                 n1ql:
                     fromString: (str) ->
                         str
-                bucketName: 'teste'

             instance = loader.createComponent 'Database.CouchMuffin', params

@@ -534,13 +555,13 @@

             loader.mockComponent 'DataSource.Couchbase',
                 init: ->
-                bucket:
-                    query: (query, callback) ->
-                        callback stdError, stdResult
+                limbo:
+                    _bucket:
+                        query: (query, callback) ->
+                            callback stdError, stdResult
                 n1ql:
                     fromString: (str) ->
                         str
-                bucketName: 'teste'

             instance = loader.createComponent 'Database.CouchMuffin', params


deal with nan tax rate if user is not in taxable location for subscription dashboard/change plan

--- services/web/public/coffee/main/subscription-dashboard.coffee
+++ services/web/public/coffee/main/subscription-dashboard.coffee
@@ -45,7 +45,10 @@
 			pricing.plan(planCode, { quantity: 1 }).currency(MultiCurrencyPricing.currencyCode).done (price)->
 				totalPriceExTax = parseFloat(price.next.total)
 				$scope.$evalAsync () ->
-					$scope.prices[planCode] = $scope.currencySymbol + (totalPriceExTax + (totalPriceExTax * taxRate))
+					taxAmmount = totalPriceExTax * taxRate
+					if isNaN(taxAmmount)
+						taxAmmount = 0
+					$scope.prices[planCode] = $scope.currencySymbol + (totalPriceExTax + taxAmmount)

 			price = ""


Document css class for background

Document css class for background

--- src/components/student-dashboard/dashboard.cjsx
+++ src/components/student-dashboard/dashboard.cjsx
@@ -26,14 +26,18 @@
     @context.router.transitionTo('viewGuide', {courseId: @props.courseId})

   selectTab: (index) ->
-    this.setState(selectedTabIndex:index)
+    @setState(selectedTabIndex:index)

   render: ->
     courseId = @props.courseId
     info = StudentDashboardStore.get(courseId)
+    # Discussions are on-going on the best way to choose the image and text for the large title,
+    # this method will most likely change in the future.
+    #
+    # The large background image is currently set via CSS based on the lowercase
+    # version of the short title, which will be something like "physics"
     {longTitle, shortTitle} = StudentDashboardStore.getTitles(courseId)
-
-

+

{shortTitle}

         <BS.Col xs={12} md={9}>


remove startup dependency on s3 settings

--- services/track-changes/app/coffee/MongoAWS.coffee
+++ services/track-changes/app/coffee/MongoAWS.coffee
@@ -9,12 +9,11 @@

 DAYS = 24 * 3600 * 1000 # one day in milliseconds

-AWS_CONFIG = {
-	accessKeyId: settings.trackchanges.s3.key
-	secretAccessKey: settings.trackchanges.s3.secret
-}
+createStream = (streamConstructor, project_id, doc_id, pack_id) ->
+	AWS_CONFIG =
+		accessKeyId: settings.trackchanges.s3.key
+		secretAccessKey: settings.trackchanges.s3.secret

-createStream = (streamConstructor, project_id, doc_id, pack_id) ->
 	return streamConstructor new AWS.S3(AWS_CONFIG), {
 		"Bucket": settings.trackchanges.stores.doc_history,
 		"Key": project_id+"/changes-"+doc_id+"/pack-"+pack_id


sidebar/machine: add missing method

sidebar/machine: add missing method

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- client/app/lib/sidebar/components/ownedresourceslist.coffee
+++ client/app/lib/sidebar/components/ownedresourceslist.coffee
@@ -24,6 +24,12 @@
     super props

     @headers = []
+
+
+  onMenuItemClickError: (name) ->
+
+    new kd.NotificationView { title: "Error occured while #{name} template" }
+

   getSectionCount: -> @props.resources.length


Use http instead https for vm domains.

Use http instead https for vm domains.

--- client/landing/app/MainApp/filetree/itemviews/vmitem.coffee
+++ client/landing/app/MainApp/filetree/itemviews/vmitem.coffee
@@ -23,7 +23,7 @@
       if not err and domains.length > 0
         @vmInfo.updatePartial """
           on
+          href="http://#{domains.first}" target="_blank">
           #{domains.first} VM
         """


use correct score for league leaderboard

--- app/views/ladder/components/Leaderboard.coffee
+++ app/views/ladder/components/Leaderboard.coffee
@@ -140,7 +140,7 @@
           model.get('submittedCodeLanguage'),
           model.rank || index+1,
           (model.get('fullName') || model.get('creatorName') || $.i18n.t("play.anonymous")),
-          model.get('totalScore') * 100 | 0,
+          @correctScore(model),
           @getAgeBracket(model),
           moment(model.get('submitDate')).fromNow().replace('a few ', ''),
           model.get('_id')
@@ -213,3 +213,7 @@

   getAgeBracket: (model) ->
     $.i18n.t("ladder.bracket_#{(model.get('ageBracket') || 'open').replace(/-/g, '_')}")
+
+  correctScore: (model) ->
+    sessionStats = if @league then _.find(model.get('leagues'), {leagueID: @league.id})?.stats else model.attributes
+    return (sessionStats?.totalScore || model.get('totalScore')/2) * 100 | 0


Add server auto respond to true

Add server auto respond to true

--- spec/javascripts/spec_helper.coffee
+++ spec/javascripts/spec_helper.coffee
@@ -42,6 +42,8 @@
 beforeEach( (done) ->
   # Fake XHR
   window.server = TestUtil.fakeServer()
+  server.autoRespond = true
+  server.autoRespondAfter = 1

   # Prevent automatic scheduling of runloops. For tests, we
   # want to have complete control of runloops.


fix (#6391)

fix (#6391)


Login: login link copies simplified

Login: login link copies simplified

--- client/Login/AppView.coffee
+++ client/Login/AppView.coffee
@@ -23,40 +23,33 @@
     loginHandler                  = handler.bind null, '/Login'
     registerHandler               = handler.bind null, '/Register'
     recoverHandler                = handler.bind null, '/Recover'
-    resendMailConfirmationHandler = handler.bind null, '/ResendToken'

     @logo = new KDCustomHTMLView
-      tagName     : "div"
       cssClass    : "logo"
-      partial     : "Koding"
+      partial     : "Koding"
       click       : homeHandler

     @backToLoginLink = new KDCustomHTMLView
-      tagName   : "a"
-      partial   : "Go ahead and login"
-      click     : loginHandler
+      tagName     : "a"
+      partial     : "Sign In"
+      click       : loginHandler

     @goToRecoverLink = new KDCustomHTMLView
       tagName     : "a"
-      partial     : "Recover password"
+      partial     : "Forgot your password?"
       testPath    : "landing-recover-password"
       click       : recoverHandler

     @goToRegisterLink = new KDCustomHTMLView
       tagName     : "a"
-      partial     : "Register an account"
+      partial     : "Create Account"
       click       : registerHandler

-    @goToResendMailConfirmationLink = new KDCustomHTMLView
-      tagName     : "a"
-      partial     : "Resend"
-      click       : resendMailConfirmationHandler
-
-    @loginOptions = new LoginOptions
-      cssClass : "login-options-holder log"
-
-    @registerOptions = new RegisterOptions
-      cssClass : "login-options-holder reg"
+    # @loginOptions = new LoginOptions
+    #   cssClass : "login-options-holder log"
+
+    # @registerOptions = new RegisterOptions
+    #   cssClass : "login-options-holder reg"

     @loginForm = new LoginInlineForm
       cssClass : "login-form"
@@ -173,12 +166,13 @@

-
Not a member? {{> @goToRegisterLink}}

-
Already a member? {{> @backToLoginLink}}

-
Trouble logging in? {{> @goToRecoverLink}}

-
Didn't receive confirmation email? {{> @goToResendMailConfirmationLink}}

-
Terms of service / Privacy policy

+

+
{{> @goToRecoverLink}}

{{> @goToRegisterLink}}•{{> @backToLoginLink}}

+

+
+      Terms of service•Privacy policy•photo by some motherf*cker
+
     """

   doReset:({recoveryToken, password, clientId})->


webapp/idle: forgot commenting log message

--- src/smc-webapp/client_browser.coffee
+++ src/smc-webapp/client_browser.coffee
@@ -133,7 +133,7 @@

     # ATTN use @reset_idle, not this one here (see constructor above)
     _idle_reset: =>
-        console.log("idle: _idle_reset got called")
+        # console.log("idle: _idle_reset got called")
         @_idle_time = (new Date()).getTime() + @_idle_timeout + 1000
         @emit('idle', 'active')


Tweak

Tweak

--- test/generators/relational/has_many.coffee
+++ test/generators/relational/has_many.coffee
@@ -282,7 +282,7 @@

                   owner.get 'reverses', (err, updated_reverses) ->
                     assert.ok(!err, "No errors: #{err}")
-                    assert.equal(updated_reverses.length, 3, "loaded correct models.")
+                    assert.equal(updated_reverses.length, 3, "loaded correct models. Expected: #{3}. Actual: #{updated_reverse_ids.length}")
                     updated_reverse_ids = (reverse.id for reverse in updated_reverses)

                     assert.equal(updated_reverse_ids.length, 3, "Moved the reverse. Expected: #{3}. Actual: #{updated_reverse_ids.length}")


SignUpWidget: Fixed image warning in karma runner.

--- src/tests/widgets/test_signup.coffee
+++ src/tests/widgets/test_signup.coffee
@@ -26,11 +26,11 @@

   it 'should have an image element and that image element should have correct src attribute ', ->
-    widget = new spark.widgets.SignUp imageUrl: 'lolo.png'
+    widget = new spark.widgets.SignUp imageUrl: 'http://localhost:9876'
     img    = widget.getElement().firstChild

     expect(img.tagName).toBe 'IMG'
-    expect(img.src.indexOf('lolo.png') > -1).toBeTruthy()
+    expect(img.src.indexOf('localhost') > -1).toBeTruthy()

   it 'should not have an image element if withImage option passed as false', ->


Removed unneeded check

Removed unneeded check

--- core/app/backbone/views/wheel/interactive_wheel_view.coffee
+++ core/app/backbone/views/wheel/interactive_wheel_view.coffee
@@ -2,34 +2,33 @@
   clickOpinionType: (opinionType) ->
     fact_id = @options.fact.id

-    if fact_id?
-      @toggleActiveOpinionType opinionType
-      if opinionType.is_user_opinion
-        $.ajax
-          url: "/facts/" + fact_id + "/opinion/" + opinionType.type + "s.json"
-          type: "POST"
-          success: (data) =>
-            @updateTo data.authority, data.opinion_types
-            mp_track "Factlink: Opinionate",
-              factlink: @options.fact.id
-              opinion: opinionType.type
+    @toggleActiveOpinionType opinionType
+    if opinionType.is_user_opinion
+      $.ajax
+        url: "/facts/" + fact_id + "/opinion/" + opinionType.type + "s.json"
+        type: "POST"
+        success: (data) =>
+          @updateTo data.authority, data.opinion_types
+          mp_track "Factlink: Opinionate",
+            factlink: @options.fact.id
+            opinion: opinionType.type

-          error: =>
-            @toggleActiveOpinionType opinionType
-            alert "Something went wrong while setting your opinion on the Factlink, please try again"
+        error: =>
+          @toggleActiveOpinionType opinionType
+          alert "Something went wrong while setting your opinion on the Factlink, please try again"

-      else
-        $.ajax
-          type: "DELETE"
-          url: "/facts/" + fact_id + "/opinion.json"
-          success: (data) =>
-            @updateTo data.authority, data.opinion_types
-            mp_track "Factlink: De-opinionate",
-              factlink: @options.fact.id
+    else
+      $.ajax
+        type: "DELETE"
+        url: "/facts/" + fact_id + "/opinion.json"
+        success: (data) =>
+          @updateTo data.authority, data.opinion_types
+          mp_track "Factlink: De-opinionate",
+            factlink: @options.fact.id

-          error: =>
-            @toggleActiveOpinionType opinionType
-            alert "Something went wrong while removing your opinion on the Factlink, please try again"
+        error: =>
+          @toggleActiveOpinionType opinionType
+          alert "Something went wrong while removing your opinion on the Factlink, please try again"

   toggleActiveOpinionType: (opinionType) ->
     oldAuthority = @model.get("authority")


manycurves: Add background curves in bottom panel; reverse sort in top panel

--- manycurves/manycurves.coffee
+++ manycurves/manycurves.coffee
@@ -52,7 +52,7 @@

   # order individuals by average phenotype
   orderedInd = d3.range(nInd).sort (a,b) ->
-    return -1 if avePhe[a] < avePhe[b]
+    return -1 if avePhe[a] > avePhe[b]
     return +1 if avePhe[b] < avePhe[a]
     return 0

@@ -276,6 +276,16 @@
       d3.svg.line()
         .x((d) -> xScaleCurve(d))
         .y((d,di) -> yScaleCurve(data.curves[ind][di]))
+
+  # background curves for all individuals
+  bgdcurves = curve.append("g").attr("id", "bgdphecurve")
+  for i of data.curves
+    bgdcurves.append("path")
+             .datum(data.times)
+             .attr("d", phecurve(i))
+             .attr("stroke", d3.rgb(170, 170, 170))
+             .attr("fill", "none")
+             .attr("stroke-width", 0.5)

   # function to draw curve for an individual
   drawCurve = (ind) ->


Removed debug statements

Removed debug statements

--- src/goo/loaders/handlers/MeshDataHandler.coffee
+++ src/goo/loaders/handlers/MeshDataHandler.coffee
@@ -137,8 +137,6 @@
 							offsetObj.zOffset
 						])
 				else if data.vertices instanceof Float32Array
-					# ----- DO MAGIC HERE
-					console.debug "Vertices are float32array..."
 					meshData.getAttributeBuffer(MeshData.POSITION).set(data.vertices)
 				else
 					JsonUtils.fillAttributeBuffer(data.vertices, meshData, MeshData.POSITION)
@@ -161,8 +159,6 @@
 						[scale, scale, scale], [offset, offset,offset])

 				else if data.normals instanceof Float32Array
-					# ----- DO MAGIC HERE
-					console.debug "Normals are float32array..."
 					meshData.getAttributeBuffer(MeshData.NORMAL).set(data.normals)
 				else
 					JsonUtils.fillAttributeBuffer(data.normals, meshData, MeshData.NORMAL)
@@ -195,8 +191,6 @@
 					for texObj, texIdx in textureUnits
 						attr = 'TEXCOORD' + texIdx
 						if texObj instanceof Float32Array
-							# ----- DO MAGIC HERE
-							console.debug "Texture coordinates in layer #{texIdx} are float32array..."
 							meshData.getAttributeBuffer(attr).set(texObj)
 						else
 							JsonUtils.fillAttributeBuffer(texObj, meshData, attr)


Add dubhacksii

Add dubhacksii

--- client/data/cardData.coffee
+++ client/data/cardData.coffee
@@ -1,4 +1,11 @@
 module.exports = [
+#   id: 'dubhacksii'
+#   title: 'DubHacks II'
+#   img: 'svg'
+#   description: 'DubHacks round 2.'
+#   url:
+#     github: 'https://github.com/dubhacks/15f'
+# ,
 #   id: 'capture'
 #   title: 'Capture'
 #   img: 'svg'


FSItem: fix the create issue with file and folder

--- client/ide/fs/fsitem.coffee
+++ client/ide/fs/fsitem.coffee
@@ -32,13 +32,11 @@

         kite[method](options).then (stat) ->

-          file = FSHelper.createFile {
+          FSHelper.createFile {
             path: actualPath
             type
             vmName
           }
-
-          file.save().then -> return file

       .nodeify(callback)


IDE: Existence check for pane hash.

IDE: Existence check for pane hash.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -847,6 +847,9 @@
     ideView.on 'PaneRemoved', (pane) =>
       ideViewLength  = 0
       ideViewLength += ideView.tabView.panes.length  for ideView in @ideViews
+
+      return unless pane.view?.hash
+
       delete @generatedPanes[pane.view.hash]

       if session = pane.view.remote?.session


Add defensive check

Add defensive check

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -1171,7 +1171,7 @@

     # when MachineStateModal calls this func, we need to rebind Klient.
     @bindKlientEvents machine
-    machine.getBaseKite().fetchTerminalSessions()
+    machine.getBaseKite()?.fetchTerminalSessions?()

     @fetchSnapshot (snapshot) =>


IDE: Remove isReadOnly checks.

IDE: Remove isReadOnly checks.

Prevents any possible race conditions with no side effect.

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -1641,9 +1641,6 @@

   makeReadOnly: ->

-    return  if @isReadOnly
-
-    @isReadOnly = yes
     ideView.isReadOnly = yes  for ideView in @ideViews
     @forEachSubViewInIDEViews_ (pane) -> pane.makeReadOnly()
     @finderPane.makeReadOnly()
@@ -1652,9 +1649,6 @@

   makeEditable: ->

-    return  unless @isReadOnly
-
-    @isReadOnly = no
     ideView.isReadOnly = no  for ideView in @ideViews
     @forEachSubViewInIDEViews_ (pane) -> pane.makeEditable()
     @finderPane.makeEditable()


Remove superfluous newline

Remove superfluous newline

--- coffee/chosen.jquery.coffee
+++ coffee/chosen.jquery.coffee
@@ -399,7 +399,6 @@
     if @search_field.val() is @default_text then "" else $('<div/>').text($.trim(@search_field.val())).html()

   winnow_results_set_highlight: ->
-
     selected_results = if not @is_multiple then @search_results.find(".result-selected.active-result") else []
     do_high = if selected_results.length then selected_results.first() else @search_results.find(".active-result").first()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- source/javascripts/_test/string_extensions.coffee
+++ source/javascripts/_test/string_extensions.coffee
@@ -54,8 +54,6 @@
   equals "0109".toInt(), 109

   equals "F".toInt(16), 15
-
-  equals "-1.02".toInt()

 test "#underscore", ->
   equals "Pro-tip".underscore(), "pro_tip"


+ register bluebird for any-promise

+ register bluebird for any-promise

--- test/any-test.coffee
+++ test/any-test.coffee
@@ -4,6 +4,8 @@
 assert          = chai.assert
 should          = chai.should()
 chai.use(sinonChai)
+
+require('any-promise/register')('bluebird')

 any             = require '../src/any'
 Promise         = require 'any-promise'


Omit slash

Omit slash

--- test/appveyor.coffee
+++ test/appveyor.coffee
@@ -51,4 +51,4 @@
           ErrorStackTrace: test.err?.stack

   runner.on 'end', ->
-    post tests, '/api/tests/batch'
+    post tests, 'api/tests/batch'