Stop resize if button isn't pressed

Stop resize if button isn't pressed

Previously dragging off screen and then releasing the mouse button
would continue the drag when moving back over the document.

This same style of fix is done in the editor view for selections.

Closes atom/atom#2683

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -187,14 +187,16 @@
     false

   resizeStarted: =>
-    $(document.body).on('mousemove', @resizeTreeView)
-    $(document.body).on('mouseup', @resizeStopped)
+    $(document).on('mousemove', @resizeTreeView)
+    $(document).on('mouseup', @resizeStopped)

   resizeStopped: =>
-    $(document.body).off('mousemove', @resizeTreeView)
-    $(document.body).off('mouseup', @resizeStopped)
-
-  resizeTreeView: ({pageX}) =>
+    $(document).off('mousemove', @resizeTreeView)
+    $(document).off('mouseup', @resizeStopped)
+
+  resizeTreeView: ({pageX, which}) =>
+    return @resizeStopped() unless which is 1
+
     if atom.config.get('tree-view.showOnRightSide')
       width = $(document.body).width() - pageX
     else


Remove unused params

Remove unused params

--- lib/tree-view.coffee
+++ lib/tree-view.coffee
@@ -119,11 +119,11 @@

     false

-  resizeStarted: (e) =>
+  resizeStarted: =>
     $(document.body).on('mousemove', @resizeTreeView)
     $(document.body).on('mouseup', @resizeStopped)

-  resizeStopped: (e) =>
+  resizeStopped: =>
     $(document.body).off('mousemove', @resizeTreeView)
     $(document.body).off('mouseup', @resizeStopped)


some renaming

some renaming

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -235,7 +235,7 @@

         # if we have started an operation that responds to canComposeWith check if it can compose
         # with the operation we're going to push onto the stack
-        if (tailOperation = @tailOperation())? and tailOperation.canComposeWith? and not tailOperation.canComposeWith(operation)
+        if (tailOperation = @getTailOperation())? and tailOperation.canComposeWith? and not tailOperation.canComposeWith(operation)
           @resetNormalMode()
           @emitter.emit('failed-to-compose')
           break
@@ -261,7 +261,7 @@
   # Private: Removes all operations from the stack.
   #
   # Returns nothing.
-  clearOperations: ->
+  clearOperationsQueue: ->
     @operationsQueue = []

   undo: ->
@@ -272,18 +272,17 @@
   #
   # Returns nothing.
   processOperations: ->
-    unless @operationsQueue.length > 0
-      return
-
-    unless @tailOperation().isComplete()
-      if @isNormalMode() and @tailOperation().isOperator?()
+    return unless @operationsQueue.length
+
+    unless @getTailOperation().isComplete()
+      if @isNormalMode() and @getTailOperation().isOperator?()
         @activateOperatorPendingMode()
       return

     operation = @operationsQueue.pop()
     if @operationsQueue.length
       try
-        @tailOperation().compose(operation)
+        @getTailOperation().compose(operation)
         @processOperations()
       catch e
         if (e instanceof Operators.OperatorError) or (e instanceof Motions.MotionError)
@@ -297,7 +296,7 @@
   # Private: Fetches the last operation.
   #
   # Returns the last operation.
-  tailOperation: ->
+  getTailOperation: ->
     _.last @operationsQueue

   # Private: Fetches the value of a given register.
@@ -413,7 +412,7 @@

     @changeModeClass('normal-mode')

-    @clearOperations()
+    @clearOperationsQueue()
     selection.clear(autoscroll: false) for selection in @editor.getSelections()
     for cursor in @editor.getCursors()
       if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine()
@@ -574,7 +573,7 @@
   #
   # Returns nothing.
   resetNormalMode: ->
-    @clearOperations()
+    @clearOperationsQueue()
     @editor.clearSelections()
     @activateNormalMode()

@@ -606,8 +605,8 @@
   repeatPrefix: (e) ->
     keyboardEvent = e.originalEvent?.originalEvent ? e.originalEvent
     num = parseInt(atom.keymaps.keystrokeForKeyboardEvent(keyboardEvent))
-    if @tailOperation()?.isRepeat?()
-      @tailOperation().addDigit(num)
+    if @getTailOperation()?.isRepeat?()
+      @getTailOperation().addDigit(num)
     else
       if num is 0
         e.abortKeyBinding()
@@ -627,7 +626,7 @@
   #
   # Returns new motion or nothing.
   moveOrRepeat: (e) ->
-    if @tailOperation()?.isRepeat?()
+    if @getTailOperation()?.isRepeat?()
       @repeatPrefix(e)
       null
     else
@@ -641,6 +640,7 @@
   # Returns nothing.
   linewiseAliasedOperator: (constructor) ->
     if @isSameOperatorPending(constructor)
+      # [FIXME] This is very quick and dirty solution.
       new Motions.MoveToRelativeLine(@editor, this)
     else
       new constructor(@editor, this)


Fix subject viewer events

Fix subject viewer events

--- libubret/tool.coffee
+++ libubret/tool.coffee
@@ -18,8 +18,7 @@
     # Mixins
     _.each(@mixins, (mixin) =>
       @events = @events.concat(mixin.events) if mixin.events
-      delete mixin.events
-      _.extend(@constructor::, mixin))
+      _.extend(@constructor::, _.omit(mixin, 'events')))

     # Initialize Element
     @el = document.createElement('div')


WIP: Removed @nodelisteners in link manager.

--- src/code/models/link-manager.coffee
+++ src/code/models/link-manager.coffee
@@ -16,7 +16,6 @@
     init: (context) ->
       @linkKeys           = {}
       @nodeKeys           = {}
-      @nodeListeners      = []
       @loadListeners      = []
       @filename           = null
       @filenameListeners  = []
@@ -54,10 +53,6 @@
     addChangeListener: (listener) ->
       log.info("adding change listener")
       @undoRedoManager.addChangeListener listener
-
-    addNodeListener: (listener) ->
-      log.info("adding node listener")
-      @nodeListeners.push listener

     addFilenameListener: (listener) ->
       log.info("adding filename listener #{listener}")
@@ -143,10 +138,7 @@
     _addNode: (node) ->
       unless @hasNode node
         @nodeKeys[node.key] = node
-        for listener in @nodeListeners
-          log.info("notifying of new Node")
-          listener.handleNodeAdd(node)
-          NodesStore.actions.nodesChanged(@getNodes())
+        NodesStore.actions.nodesChanged(@getNodes())
         @updateListeners()
         return true
       return false
@@ -154,9 +146,6 @@
     _removeNode: (node) ->
       delete @nodeKeys[node.key]
       NodesStore.actions.nodesChanged(@getNodes())
-      for listener in @nodeListeners
-        log.info("notifying of deleted Node")
-        listener.handleNodeRm(node)
       @updateListeners()

     moveNodeCompleted: (nodeKey, pos, originalPos) ->
@@ -171,9 +160,6 @@
       return unless node
       node.x = pos.left
       node.y = pos.top
-      for listener in @nodeListeners
-        log.info("notifying of NodeMove")
-        listener.handleNodeMove(node)
       @updateListeners()

     selectedNode: ->
@@ -191,8 +177,6 @@

     _notifyNodeChanged: (node) ->
       NodesStore.actions.nodesChanged(@getNodes())
-      for listener in @nodeListeners
-        listener.handleNodeChange(node)
       @_maybeChangeSelectedItem node
       @updateListeners()


[talk] fix talk used to hang when the user was typing, shouldn't do that anymore

--- src/coffee/content/main-talk.coffee
+++ src/coffee/content/main-talk.coffee
@@ -28,12 +28,16 @@
     forceUpdate = ->
         module.doOnce.update()

-        module.checkElement window.document
+        module.checkElement $root[0]

     observer = new window.MutationObserver (mutations) ->
         mutations.each (mutation) ->
             Array.prototype.each.call mutation.addedNodes, (node) ->
                 module.checkElement node
+
+    # use $root instead of document.body, because we don't want to fire our
+    # listeners every time the user types a character.
+    $root = null

     $ ->
         $ window.document.body
@@ -43,9 +47,16 @@

         module.extension.init() if module.extension.init?

+        $root = $ '.Xg .Xg'
+
+        if $root.length is 0
+            # this is not a chat pane, but the main talk frame on the right
+            $root = $ window.document.body
+
         module.comm.setOnUpdate forceUpdate

         forceUpdate()
-        observer.observe window.document, { childList: true, subtree: true }
+
+        observer.observe $root[0], { childList: true, subtree: true }

 )(iidentity or (iidentity = window.iidentity = {}), window.jQuery, window)


Esconde buy button no modo de exibição lista

--- src/coffee/portal-buy-button.coffee
+++ src/coffee/portal-buy-button.coffee
@@ -7,7 +7,7 @@
 class BuyButton extends ProductComponent
 	constructor: (@element, @productId, buyData = {}, @options) ->
 		@SDK = CATALOG_SDK
-		@productData = @SDK.getProductWithVariations(@productId)
+		@productData = @SDK?.getProductWithVariations(@productId)

 		@sku = buyData.sku || null
 		@quantity = buyData.quantity || 1
@@ -143,7 +143,7 @@
 			@element.hide()
 		if @options.hideUnselected and not @skuData
 			@element.hide()
-		if @productData and !@productData.available
+		if @productData and (!@productData.available or @productData.displayMode == 'lista')
 			@element.hide()

 	buyButtonHandler: (evt) =>


Added ability to explode particles away on click

--- js/particles.coffee
+++ js/particles.coffee
@@ -115,6 +115,7 @@
     @$canvas = canvas
     @canvas = @$canvas[0]
     @$canvas.mousemove(@update_mouse_pos)
+    @$canvas.mousedown(@explode_particles)
     @particles = @generate_particles(50)
     @tick = .001

@@ -132,6 +133,16 @@
     rect = @canvas.getBoundingClientRect()
     MOUSE.pos.x = evt.clientX - rect.left
     MOUSE.pos.y = evt.clientY - rect.top
+
+  # Make the particles explode away from the mouse
+  explode_particles: (evt) =>
+    for particle in @particles
+      difference = Vector.subtract(MOUSE.pos, particle.pos)
+      dist = Math.max(difference.mag(), 20)
+
+      push_force = -1000000
+      vel_mag = push_force / dist
+      particle.vel.plus(Vector.unit(difference).s_mult(vel_mag))

   draw: =>
     start = Date.now()


payment: remove pistachio, use addSubView

--- client/Account/views/billing.coffee
+++ client/Account/views/billing.coffee
@@ -1,4 +1,4 @@
-class AccountBilling extends JView
+class AccountBilling extends KDView

   initialState: {
     subscription: {}
@@ -12,20 +12,18 @@

     @state = KD.utils.extend @initialState, options.state

-    @initViews()

+  viewAppended: ->

-  initViews: ->
-
-    @subscriptionWrapper = new KDCustomHTMLView
+    @addSubView @subscriptionWrapper = new KDCustomHTMLView
       tagName  : 'section'
       cssClass : 'subscription-wrapper clearfix'

-    @paymentMethodWrapper = new KDCustomHTMLView
+    @addSubView @paymentMethodWrapper = new KDCustomHTMLView
       tagName  : 'section'
       cssClass : 'payment-method-wrapper clearfix'

-    @paymentHistoryWrapper = new KDCustomHTMLView
+    @addSubView @paymentHistoryWrapper = new KDCustomHTMLView
       tagName  : 'section'
       cssClass : 'payment-history-wrapper clearfix'

@@ -101,10 +99,3 @@
       @paymentHistoryWrapper.addSubView @listController.getView()

-  pistachio: ->
-    """
-    {{> @subscriptionWrapper}}
-    {{> @paymentMethodWrapper}}
-    {{> @paymentHistoryWrapper}}
-    """
-


Clint: Activity: Updated prepareThreadTitle argument from thread to channel

--- client/activity/lib/util/prepareThreadTitle.coffee
+++ client/activity/lib/util/prepareThreadTitle.coffee
@@ -3,9 +3,8 @@
 getParticipantOrigins = require 'activity/util/getParticipantOrigins'
 makeProfileText       = require 'activity/util/makeProfileText'

-module.exports = prepareThreadTitle = (thread) ->
+module.exports = prepareThreadTitle = (channel) ->

-  channel = thread.get 'channel'
   name = channel.get 'name'

   if name


Client: Force chat view to bottom after each action

--- client/app/js/collections/battle_collection.coffee
+++ client/app/js/collections/battle_collection.coffee
@@ -118,6 +118,8 @@
         done()
       else
         done()
+    if wasAtBottom && !view.chatView.isAtBottom()
+      view.chatView.scrollToBottom()

   spectateBattle: (socket, id, numActive, index, teams) =>
     console.log "SPECTATING BATTLE #{id}."


reformat code

reformat code

--- client/app/templates/helpers.coffee
+++ client/app/templates/helpers.coffee
@@ -1,4 +1,5 @@
 hb = Ember.Handlebars
+get = Ember.get
 {isNull} = _
 {SafeString} = hb

@@ -9,18 +10,15 @@
     v

-do ->
-  get = Ember.get
-  EmberHandlebars = Ember.Handlebars
-  EmberHandlebars.registerHelper "group", (options) ->
-    data = options.data
-    fn = options.fn
-    view = data.view
-    childView = view.createChildView(Ember._MetamorphView,
-      context: get(view, "context")
-      template: (context, options) ->
-        options.data.insideGroup = true
-        fn context, options
-    )
-    view.appendChild childView
-    return
+hb.registerHelper 'group', (options) ->
+  data = options.data
+  fn = options.fn
+  view = data.view
+  childView = view.createChildView(Ember._MetamorphView,
+    context: get(view, 'context')
+    template: (context, options) ->
+      options.data.insideGroup = yes
+      fn context, options
+  )
+  view.appendChild childView
+  return


Used @getTitle instead of @state.title.

Used @getTitle instead of @state.title.

--- client/landing/app/CommonViews/followbutton.coffee
+++ client/landing/app/CommonViews/followbutton.coffee
@@ -47,7 +47,7 @@
     @hideLoader()

   mouseEnter:->
-    if @state.title is "Following"
+    if @getTitle() is "Following"
       @setTitle "Unfollow"

   mouseLeave:->


Cleanup: whitespace

Cleanup: whitespace

--- client/landing/Login/AppView.coffee
+++ client/landing/Login/AppView.coffee
@@ -21,10 +21,10 @@
       stop event
       KD.getSingleton('router').handleRoute route, {entryPoint}

-    homeHandler                   = handler.bind null, '/'
-    loginHandler                  = handler.bind null, '/Login'
-    registerHandler               = handler.bind null, '/Register'
-    recoverHandler                = handler.bind null, '/Recover'
+    homeHandler     = handler.bind null, '/'
+    loginHandler    = handler.bind null, '/Login'
+    registerHandler = handler.bind null, '/Register'
+    recoverHandler  = handler.bind null, '/Recover'

     @logo = new KDCustomHTMLView
       cssClass    : "logo"


Removed not-needed console logging

Removed not-needed console logging

--- client/src/Screen/GameScreen.coffee
+++ client/src/Screen/GameScreen.coffee
@@ -462,8 +462,6 @@
   ###
   drawAllocationMoveMenu: (clickedOn) ->
     @allocationMoveMenuOn = clickedOn
-    console.log "draw Allocation menu"
-    console.log clickedOn
     #Create the new allocation menu
     html = 'Required
             Optional
@@ -495,7 +493,6 @@
         #height: '70px'
       events:
         render: (event, api) ->
-          console.log "Render fired"
           #Add event listener for each of the "required" "optional" and "forbidden" buttons inside the menu
           clickedIndex = $('#unallocated li').index($(clickedOn))
           $("#mamenu-required-btn").click -> network.moveToRequired(clickedIndex)


make table filter work with dynamic table content

--- vendor/assets/javascripts/table_filter.coffee
+++ vendor/assets/javascripts/table_filter.coffee
@@ -4,7 +4,7 @@
     constructor: (element) ->
       @element = element
       @target  = $(@element.data('table-filter-target'))
-      @allRows = $('tbody tr:not(.tr-no-record)', @target)
+
       colspan = if @target.data('no-record-span')?
         @target.data('no-record-span')
       else
@@ -18,21 +18,24 @@
       @noRecordRow = $("
#{message}
")
     filter: ->
       $('.tr-no-record', @target).remove()
+      allRows = @allRows()
       keyword = @element.val().toLowerCase()

       $toShow = if keyword is ''
-        @allRows
+        allRows
       else
-        @allRows.filter ->
+        allRows.filter ->
           trText = $(this).clone().find('.btn').remove().end().text().toLowerCase()
           trText.indexOf(keyword) > -1

       $toShow.show()
-      @allRows.not($toShow).hide()
+      allRows.not($toShow).hide()

       if $toShow.length is 0
         $('tbody', @target).append(@noRecordRow)

+    allRows: ->
+      $('tbody tr:not(.tr-no-record)', @target)
   $.fn.tableFilter = ->
     @each ->
       data = $(this).data('table-filter')


Count velocity 0 as note off

Count velocity 0 as note off

--- webaudio-formant-synth/client/lib/midi.coffee
+++ webaudio-formant-synth/client/lib/midi.coffee
@@ -38,10 +38,11 @@
     channel = msg.data[0] & 0xf
     cmd = msg.data[0] >> 4

-    #return if channel == 9 and cmd != 9
-
     @_velocity = msg.data[2]
     @_note = msg.data[1]
+    if @_velocity == 0
+      # Count as note off event
+      cmd = 8
     if @_keyboard?
       switch cmd
         when 9


update map

update map

--- components/backend/modules/map/view/MapView.coffee
+++ components/backend/modules/map/view/MapView.coffee
@@ -5,12 +5,21 @@
 ], (App, Marionette, Template) ->

   map = ''
-
   class ListItemView extends Marionette.ItemView
     template: Template
-    initialize:->
+    modelEvents:
+      "change": "updateMarker"
+      "destroy": "destroyMarker"
+    render: ->
+      @createMarker()
+    destroyMarker:->
+      @marker.setMap null
+      App.google.event.removeListener @listener
+    updateMarker:->
+      @destroyMarker()
+      @createMarker()
+    createMarker:->
       @category = App.Categories.findWhere _id: @model.getValue 'category'
-    render: ->
       color = @category.getValue("color")
       @infoWindow = new App.google.InfoWindow content: @template @model.toJSON()
       @marker = new App.google.Marker
@@ -21,16 +30,14 @@
           path:App.google.SymbolPath.CIRCLE
           scale: 4
       that = @
-      App.google.event.addListener @marker, 'click', ->
+      @listener = App.google.event.addListener @marker, 'click', ->
         that.infoWindow.open map, that.marker
-
     latlng: ->
       new App.google.LatLng @model.getValue('lat'), @model.getValue('lng')

   class ListView extends Marionette.CollectionView
     childView: ListItemView
     initialize:->
-      pos = new App.google.LatLng App.position.coords.latitude, App.position.coords.longitude
       @$el.css
         height: '100%'
         width: '100%'
@@ -50,10 +57,15 @@
         scaleControlOptions:
           position: App.google.ControlPosition.RIGHT_BOTTOM
         streetViewControl: false
-
-      marker = new App.google.Marker
-        map: map,
-        position: pos
+      pos = new App.google.LatLng App.position.coords.latitude, App.position.coords.longitude
       map.setCenter(pos)
+      setInterval ->
+        marker?.setMap null
+        App.getCurrentPosition()
+        pos = new App.google.LatLng App.position.coords.latitude, App.position.coords.longitude
+        marker = new App.google.Marker
+          map: map,
+          position: pos
+      , 2000

   return ListView


Remove log

Remove log

--- plugins/bitbucket-issues/index.coffee
+++ plugins/bitbucket-issues/index.coffee
@@ -41,7 +41,6 @@
       "kind": config.kind
       "priority": config.priority

-    console.log @issuesUrl(config)
     # Send the request
     @bitbucketRequest(@request.post(@issuesUrl(config)), config)
       .send(qs.stringify(query_object))


修复Pager 控件 PageSize 调整无效的问题

修复Pager 控件 PageSize 调整无效的问题

--- src/widget/list/page.coffee
+++ src/widget/list/page.coffee
@@ -72,11 +72,9 @@
 		dom.appendChild(@_doms.goTo)

 	goTo: (pageNo)->
-#@_pageTimmer && clearTimeout(@_pageTimmer)
-		data = @_getBindItems()
-		#@_pageTimmer = setTimeout(()->
+		data = @_getBindItems()
 		data?.gotoPage(parseInt(pageNo))
-#, 100)
+

 	pageSize: (pageSize)->
 		@_pageTimmer && clearTimeout(@_pageTimmer)
@@ -85,10 +83,8 @@
 		if data?._providerInvoker?.pageSize is pageSize
 			return
 		@_pageTimmer = setTimeout(()->
-			data?._providerInvoker?.pageSize = pageSize
+			data?._providerInvoker?.ajaxService?.set("pageSize", pageSize)
 			data?._providerInvoker?.pageNo = 1
-			data?.pageSize = pageSize
-			data?.pageNo = 1
 			data && cola.util.flush(data)
 		, 100)


make getAllFullInfo method return an array instead of an obj.

--- src/scaffolding/plugins/info.coffee
+++ src/scaffolding/plugins/info.coffee
@@ -55,13 +55,13 @@
 					return callback null, plugin_data
 		getAllFullInfo: () ->
 			defer = Q.defer()
-			plugins = {}
+			plugins = []
 			info.getActiveAsync()
 				.then (names) ->
 					async.each names, (name, next) ->
 						info.getDetails process.cwd() + '/plugins/' + name, (err, data) ->
 							return next err if err
-							plugins[name] = data
+							plugins.push data
 							next()
 					, (err) ->
 						return defer.reject err if err


better buffering without pooling

better buffering without pooling

--- storage/redis/redis-streamer.coffee
+++ storage/redis/redis-streamer.coffee
@@ -29,24 +29,32 @@
 Redis::stream = (cmd, key, curry) ->
     curry = Array::slice.call arguments
     client = @
+    passes = -1
+    conn = @createConnection()
     selectCmd = parseCommand(['select', client.db])
+    stream = null
     xform = es.map (args, next) ->
+        passes = -1
         #accept arrays as data for `write`
         elems = concat [], stream.curry
         elems = concat elems, args
         parsed = parseCommand elems
+        #select db
+        parsed = selectCmd + parsed
         next null, parsed

-    conn = net.createConnection 6379, '127.0.0.1'
-    pluckSelect = ->
-        passes = -1
+    pluckSelect =
         es.map (reply, next) ->
             passes++
             return next() unless passes
             next null, reply
-    execute = es.pipeline(conn, es.split('\r\n'))
-    execute.pipe(pluckSelect())
+
+    execute = es.pipeline(es.pipeline(conn,
+        es.split('\r\n')),
+        pluckSelect)
+
+    command = es.pipeline xform, execute
 #    execute = es.map (cmd, next) ->
 #        client.pool.acquire (err, conn) ->
 #            return next err if err?
@@ -63,15 +71,15 @@
 #            conn.write cmd

     reply = replyParser ->
+        passes = -1
         stream.emit 'done'
+    stream =
+        es.pipeline(es.pipeline(xform, execute), reply)
     stream.curry = curry
     stream.error = (err) ->
         console.error 'redis-streamer', err
         stream.emit 'error', err

-    pipe =
-        es.pipeline(es.pipeline(stream, execute), reply)
-
-    pipe
+    stream


Added class model admin

Added class model admin

--- snippets/php.cson
+++ snippets/php.cson
@@ -22,6 +22,20 @@
     \t}
     }
     """
+  'Class Model Admin Silverstripe':
+    'prefix': 'classmodeladmin'
+    'body': """
+    /**
+     * ${2:Description}
+     *
+     * @package silverstripe
+     * @subpackage ${3:mysite}
+     */
+    class $1 extends ModelAdmin
+    {
+    \t${0}
+    }
+    """
   'singular_name':
     'prefix': 'singular_name '
     'body': """


Social: add private message operations and mappings

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -47,6 +47,24 @@
       return callback err if err
       return callback null, mapChannels result

+  sendPrivateMessageRequest = (name, rest..., callback)->
+    KD.remote.api.SocialMessage[name] rest..., (err, result)->
+      return callback err if err
+      return callback null, mapPrivateMessages result
+
+  mapPrivateMessages = (messages)->
+    messages = [].concat(messages)
+    return [] unless messages?.length > 0
+
+    mappedMessages = []
+
+    for messageContainer in messages
+      message = mapActivity messageContainer.lastMessage
+      message.channel = mapChannels(messageContainer)[0]
+      mappedMessages.push message
+
+    return mappedMessages
+
   mapActivities = (messages)->
     # if no result, no need to do something
     return messages unless messages
@@ -68,6 +86,7 @@
       m.repliesCount = message.replies.length or 0
       m.interactions = message.interactions

+      # todo- remove those event bindings
       m.on "MessageReplySaved", log
       m.on "update", log

@@ -88,12 +107,15 @@
     return m

   mapChannels = (channels)->
+    return channels unless channels
     revivedChannels = []
+    channels = [].concat(channels)
     {SocialChannel} = KD.remote.api
     for channel in channels
       data = channel.channel
       data.isParticipant = channel.isParticipant
       data.participantCount = channel.participantCount
+      data.participantsPreview = channel.participantsPreview

       c = new SocialChannel data
       # until we create message id's
@@ -113,6 +135,10 @@
     delete :(rest...)-> KD.remote.api.SocialMessage.delete rest...
     like   :(rest...)-> KD.remote.api.SocialMessage.like rest...
     unlike :(rest...)-> KD.remote.api.SocialMessage.unlike rest...
+    sendPrivateMessage :(rest...)->
+      sendPrivateMessageRequest 'sendPrivateMessage', rest...
+    fetchPrivateMessages :(rest...)->
+      sendPrivateMessageRequest 'fetchPrivateMessages', rest...

   channel:
     list                 : fetchChannels


Fixes #rebalance by detaching and reusing the existing DOM nodes

--- components/artwork_columns/view.coffee
+++ components/artwork_columns/view.coffee
@@ -185,15 +185,14 @@

     # Pop off the artworks that need to be removed
     $lastElements = @$(".artwork-column:eq(#{index})").find('.artwork-item').slice(-idx)
-    removedArtworks = []
-    for elem in $lastElements
+
+    removedArtworks = _.map $lastElements, (elem) =>
       id = $(elem).attr('data-artwork')
-      removedArtworks.push @collection.get(id)
-      @$("figure[data-artwork='#{id}']").remove()
+      @$("figure[data-artwork='#{id}']").detach()

     # Recalc column height
     @columns[index].height = @columnHeight(index)

     # Readd artworks to shortest columns
     for artwork in removedArtworks
-      @addToShortestColumn(artwork)+      @addToShortestColumn(artwork)


No need to block until `frameId?`.

No need to block until `frameId?`.

Now that we've moved Frame.init() back to before checkIfEnabledForUrl,
there's no longer a need to check that frameId has been initialised.  It
must have been.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -169,7 +169,7 @@
 # Wrapper to install event listeners.  Syntactic sugar.
 installListener = (element, event, callback) ->
   element.addEventListener(event, ->
-    if isEnabledForUrl and frameId? then callback.apply(this, arguments) else true
+    if isEnabledForUrl then callback.apply(this, arguments) else true
   , true)

 #


Show browser-blocking complaint in the popup for empty portForTab object

To test the difference:
* load an unblocked URL (e.g. https://www.example.com) in a tab
* open the popup, see that the exclusion rules show as expected
* navigate the tab to a blocked URL (e.g. chrome://extensions)
* open the popup again

Before this commit, the popup still shows the exclusion rules, because
there is still a portForTabs object associated with the tabId.

This commit adds a second check to see if the object is empty, and the
message shows as expected, because all of the ports have been closed and
cleared from the object.

--- pages/options.coffee
+++ pages/options.coffee
@@ -277,11 +277,8 @@
     exclusions = null
     document.getElementById("optionsLink").setAttribute "href", chrome.runtime.getURL("pages/options.html")

-    # As the active URL, we choose the most recently registered URL from a frame in the tab, or the tab's own
-    # URL.
-    url = chrome.extension.getBackgroundPage().urlForTab[tab.id] || tab.url
-
-    unless chrome.extension.getBackgroundPage().portsForTab[tab.id]
+    tabPorts = chrome.extension.getBackgroundPage().portsForTab[tab.id]
+    unless tabPorts and Object.keys(tabPorts).length > 0
       # The browser has disabled Vimium on this page. Place a message explaining this into the popup.
       document.body.innerHTML = """
         <div style="width: 400px; margin: 5px;">
@@ -300,6 +297,10 @@
       """
       return

+    # As the active URL, we choose the most recently registered URL from a frame in the tab, or the tab's own
+    # URL.
+    url = chrome.extension.getBackgroundPage().urlForTab[tab.id] || tab.url
+
     updateState = ->
       rule = bgExclusions.getRule url, exclusions.readValueFromElement()
       $("state").innerHTML = "Vimium will " +


Make sure TC state is applied to all users on load.

--- services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
+++ services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
@@ -610,10 +610,9 @@

 		_setEveryoneTCState = (newValue, isLocal = false) ->
 			$scope.reviewPanel.trackChangesOnForEveryone = newValue
-			for userId, userState of $scope.reviewPanel.trackChangesState
-				userState.value = newValue
-				userState.syncState = if isLocal then UserTCSyncState.PENDING else UserTCSyncState.SYNCED
-			$scope.editor.wantTrackChanges = newValue
+			for member in $scope.project.members
+				_setUserTCState(member._id, newValue, isLocal)
+			_setUserTCState($scope.project.owner._id, newValue, isLocal)

 		applyClientTrackChangesStateToServer = () ->
 			if $scope.reviewPanel.trackChangesOnForEveryone


Fix method call in Thenable#none.

Fix method call in Thenable#none.

--- lib/Thenable.coffee
+++ lib/Thenable.coffee
@@ -60,7 +60,7 @@
           rejects = state.getRejected().filter (e) -> typeof e isnt 'undefined'
           unless rejects.length
             rejects = state.getAborted()
-          composite.fulfill rejects[0][0] or rejects[0]
+          composite.deliver rejects[0][0] or rejects[0]
           return
       subtree.deliver data
       composite


Allow setting coords through setter

Allow setting coords through setter

--- lib/psd/node.coffee
+++ lib/psd/node.coffee
@@ -28,12 +28,24 @@
     @createProperties()

   createProperties: ->
-    Object.defineProperty @, 'top',     get: -> @coords.top + @topOffset
-    Object.defineProperty @, 'right',   get: -> @coords.right + @leftOffset
-    Object.defineProperty @, 'bottom',  get: -> @coords.bottom + @topOffset
-    Object.defineProperty @, 'left',    get: -> @coords.left + @leftOffset
-    Object.defineProperty @, 'width',   get: -> @right - @left
-    Object.defineProperty @, 'height',  get: -> @bottom - @top
+    Object.defineProperty @, 'top',
+      get: -> @coords.top + @topOffset
+      set: (val) -> @coords.top = val
+
+    Object.defineProperty @, 'right',
+      get: -> @coords.right + @leftOffset
+      set: (val) -> @coords.right = val
+
+    Object.defineProperty @, 'bottom',
+      get: -> @coords.bottom + @topOffset
+      set: (val) -> @coords.bottom = val
+
+    Object.defineProperty @, 'left',
+      get: -> @coords.left + @leftOffset
+      set: (val) -> @coords.left = val
+
+    Object.defineProperty @, 'width',  get: -> @right - @left
+    Object.defineProperty @, 'height', get: -> @bottom - @top

   get: (prop) -> if @[prop]? then @[prop] else @layer[prop]

@@ -75,7 +87,7 @@
     return if @isRoot()

     nonEmptyChildren = @children.filter((c) -> not c.isEmpty())
-    @coords.left = _.min(nonEmptyChildren.map((c) -> c.left)) or 0
-    @coords.top = _.min(nonEmptyChildren.map((c) -> c.top)) or 0
-    @coords.bottom = _.max(nonEmptyChildren.map((c) -> c.bottom)) or 0
-    @coords.right = _.max(nonEmptyChildren.map((c) -> c.right)) or 0+    @left = _.min(nonEmptyChildren.map((c) -> c.left)) or 0
+    @top = _.min(nonEmptyChildren.map((c) -> c.top)) or 0
+    @bottom = _.max(nonEmptyChildren.map((c) -> c.bottom)) or 0
+    @right = _.max(nonEmptyChildren.map((c) -> c.right)) or 0


kick travis

kick travis

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -21,6 +21,7 @@
 Object.keys(settings.config).forEach (k) ->
   settings[k] = ->
     atom.config.get('vim-mode.'+k)
+
   # work around vim-mode's settings sometimes being undefined
   # https://github.com/bronson/vim-mode-next/issues/2
   atom.config.observe 'vim-mode-next.'+k, (val) ->


Rename Task.terminate to Task.abort

Rename Task.terminate to Task.abort

--- lib/snippets.coffee
+++ lib/snippets.coffee
@@ -15,7 +15,7 @@
     rootView.on 'editor:attached', (e, editor) => @enableSnippetsInEditor(editor)

   deactivate: ->
-    @loadSnippetsTask?.terminate()
+    @loadSnippetsTask?.abort()

   loadAll: ->
     @loadSnippetsTask = new LoadSnippetsTask(this)


Use itemPath var

Use itemPath var

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -25,7 +25,7 @@

     if itemPath = @item.getPath?()
       @setTooltip
-        title: @item.getPath()
+        title: itemPath
         delay:
           show: 2000
           hide: 100


super sweet way to choose the image uploader

--- lib/uploader.coffee
+++ lib/uploader.coffee
@@ -1,13 +1,10 @@
 config = require('./config')
-S3Uploader = require('./uploaders/s3_uploader')
-FSUploader = require('./uploaders/fs_uploader')
+
+uploaders =
+  s3: require('./uploaders/s3_uploader')
+  fs: require('./uploaders/fs_uploader')

 class Uploader
-  constructor: ->
-    switch config.uploader
-      when 's3'
-        return new S3Uploader
-      else
-        return new FSUploader
+  constructor: -> uploaders[config.uploader]

 module.exports = Uploader


Remove outdated comment

Remove outdated comment

--- js/libs/circle/custom-bindings.coffee
+++ js/libs/circle/custom-bindings.coffee
@@ -8,7 +8,6 @@
     options = valueAccessor()
     $(el).slider(options)

-# If you're looking for ko.bindingHandlers.ab_test, it's in lib/ab-tests.coffee

 # Takes any kind of jQueryExtension, e.g. popover, tooltip, etc.
 # Example usage:


Prevent markers on wrapped line to get an extra char

--- lib/renderers/region-renderer.coffee
+++ lib/renderers/region-renderer.coffee
@@ -15,48 +15,60 @@
     if rowSpan is 0
       regions.push @createRegion(range.start, range.end, colorMarker)
     else
-      screenLine = displayBuffer.screenLines[range.start.row]
-
       regions.push @createRegion(
         range.start,
         {
           row: range.start.row
-          column: screenLine.clipScreenColumn(Infinity)
+          column: Infinity
         },
         colorMarker,
+        displayBuffer.screenLines[range.start.row],
         displayBuffer.screenLines[range.start.row + 1]
       )
       if rowSpan > 1
         for row in [range.start.row + 1...range.end.row]
-          screenLine = displayBuffer.screenLines[range.start.row]
-
           regions.push @createRegion(
-            {row, column: screenLine.clipScreenColumn(0)},
-            {row, column: screenLine.clipScreenColumn(Infinity)},
+            {row, column: 0},
+            {row, column: Infinity},
             colorMarker,
+            displayBuffer.screenLines[row],
             displayBuffer.screenLines[row + 1]
           )

-      screenLine = displayBuffer.screenLines[range.end.row]
       regions.push @createRegion(
-        {row: range.end.row, column: screenLine.clipScreenColumn(0)},
+        {row: range.end.row, column: 0},
         range.end,
         colorMarker,
+        displayBuffer.screenLines[range.end.row],
         displayBuffer.screenLines[range.end.row + 1]
       )

     regions

-  createRegion: (start, end, colorMarker, nextScreenLine) ->
+  createRegion: (start, end, colorMarker, screenLine, nextScreenLine) ->
     displayBuffer = colorMarker.marker.displayBuffer
     lineHeight = displayBuffer.getLineHeightInPixels()
     charWidth = displayBuffer.getDefaultCharWidth()

-    bufferRange = displayBuffer.bufferRangeForScreenRange({start, end})
-    bufferRange.end.column++ if nextScreenLine?.isSoftWrapped()
+    clippedStart = {
+      row: start.row
+      column: screenLine?.clipScreenColumn(start.column) ? start.column
+    }
+    clippedEnd = {
+      row: end.row
+      column: screenLine?.clipScreenColumn(end.column) ? end.column
+    }

-    startPosition = displayBuffer.pixelPositionForScreenPosition(start)
-    endPosition = displayBuffer.pixelPositionForScreenPosition(end)
+    bufferRange = displayBuffer.bufferRangeForScreenRange({
+      start: clippedStart
+      end: clippedEnd
+    })
+
+    if nextScreenLine?.isSoftWrapped() and end.column is Infinity
+      bufferRange.end.column++
+
+    startPosition = displayBuffer.pixelPositionForScreenPosition(clippedStart)
+    endPosition = displayBuffer.pixelPositionForScreenPosition(clippedEnd)

     text = displayBuffer.buffer.getTextInRange(bufferRange)

@@ -64,7 +76,7 @@
     css.left = startPosition.left
     css.top = startPosition.top
     css.width = endPosition.left - startPosition.left
-    css.width += charWidth if nextScreenLine?.isSoftWrapped()
+    css.width += charWidth if nextScreenLine?.isSoftWrapped() and end.column is Infinity
     css.height = lineHeight

     region = document.createElement('div')


missing utils require added

missing utils require added


Fix crossed channel and user dialogue

Fix crossed channel and user dialogue

--- scripts/dialogue.coffee
+++ scripts/dialogue.coffee
@@ -25,7 +25,7 @@
       "#{user.name}/#{user.room}"

     @get: (user) ->
-      Dialogue.dialogues[Dialogue.getKey user.name, user.room]
+      Dialogue.dialogues[Dialogue.getKey user]

     @add: (dialogue) ->
       Dialogue.dialogues[dialogue.key] = dialogue
@@ -34,7 +34,7 @@
       if user instanceof Dialogue
         key = user.key
       else
-        key = Dialogue.getKey user.name, user.room
+        key = Dialogue.getKey user
       delete Dialogue.dialogues[key]

     @listen: util.deprecate((->), "Dialogue.listen is deprecated.")
@@ -42,7 +42,7 @@
     constructor: (user, callback) ->
       @username = user.name
       @room = user.room
-      @key = Dialogue.getKey @username, @room
+      @key = Dialogue.getKey user
       @data = {}
       @listen callback
       Dialogue.add @
@@ -79,7 +79,6 @@
   # extend robot.receive
   org_receive = robot.receive
   robot.receive = (message) ->
-    console.log message.user
     dialogue = Dialogue.get message.user
     dialogue?.callback.call dialogue, message


ArrayDataSource accepts text as text or label or value attribute

--- coffee/lib/array-data-source.coffee
+++ coffee/lib/array-data-source.coffee
@@ -8,7 +8,7 @@

   add_option: (child) ->
     value = child.value || child
-    text = child.label || value
+    text = child.text || child.label || value
     @results.push
       array_index: @results.length
       text: text,


EditorView: style change

EditorView: style change

--- coffee/src/views/editor_view.coffee
+++ coffee/src/views/editor_view.coffee
@@ -52,15 +52,15 @@
       model: @model.shellModel
       eventhub: @eventhub

-    cancel = text: 'Cancel', id: 'editor-cancel-btn'
-    save = text: 'Save', id: 'editor-save-btn', className: 'btn-success'
-
     @newRemixerView = new acorn.player.RemixerView
       model: @model.shellModel
       eventhub: @eventhub

     @toolbarView = new athena.lib.ToolbarView
-      buttons: [cancel, save]
+      buttons: [
+        {text: 'Cancel', id: 'editor-cancel-btn'},
+        {text: 'Save', id: 'editor-save-btn', className: 'btn-success'},
+      ]
       eventhub: @eventhub

   render: =>


Return state via Collection.run

Return state via Collection.run

--- lib/Thenable.coffee
+++ lib/Thenable.coffee
@@ -33,7 +33,6 @@
           return unless state.isComplete()
           Collection.deliverBranches state, choice, subChoice, composite
           return
-        return state
       subtree.deliver data
       composite
     id = @tree.registerNode @id, name, 'all', callback
@@ -61,7 +60,6 @@
             rejects = state.getAborted()
           composite.reject rejects[rejects.length - 1]?[0] or rejects[rejects.length - 1]
           return
-        return state
       subtree.deliver data
       composite
     id = @tree.registerNode @id, name, 'some', callback


Change regex and cancel monitoring when url was not able to access

--- scripts/monitors.coffee
+++ scripts/monitors.coffee
@@ -83,7 +83,7 @@
       buffer += ", downed at: #{@data.downedAt} " if @data.downedAt
       buffer += ")"

-  robot.respond /(.+)を監視(?:して)?/i, (msg) ->
+  robot.respond /(.+)を監視/i, (msg) ->
     url = Monitor.adjustUrl msg.match[1]
     #registerMonitor service
     urlinfo = URL.parse url
@@ -93,7 +93,8 @@
     monitor.run (err) ->
       if err
         if monitor.data.status == "missing"
-          msg.send "#{monitor.url} へアクセスできません。"
+          msg.send "#{monitor.url} へアクセスできません。監視を解除します"
+          monitor.delete()
         else
           msg.send "#{monitor.url} でエラーが起きています" +
             "（ステータス：#{monitor.data.statusCode}）"


Code cleanup.

Code cleanup.

--- lib/sfdc_core/sfdc-controller.coffee
+++ lib/sfdc_core/sfdc-controller.coffee
@@ -82,7 +82,7 @@
     var idx = @dirtyMetadataIds.indexOf(id)
     if idx > 0
       @dirtyMetadataIds.splice(idx, 1)
-
+
   setEnvironment: (env) ->
     @environment = env

@@ -481,17 +481,6 @@
         when 'page'
           service = new ApexPageService(accessToken)

-      service.retrieve metadata.id, (record) ->
-        # Check that the record hasn't been modified
-        # by another user
-        console.log record
-        # myUserId = Config.read('user_id')
-        # if myUserId isnt record.LastModifiedById
-        #   alert """
-        #         This file has been modified by someone else.
-        #         Please refresh the file and try again
-        #         """
-
       mcs = new MetadataContainerService(accessToken)
       mcs.saveEntity metadata.type, metadata.id, fileContents, (result) ->
         loader.remove()


Adding deprecation notice to !docs

Adding deprecation notice to !docs

--- scripts/triggers.coffee
+++ scripts/triggers.coffee
@@ -18,6 +18,7 @@
   '!dontspam'     : "Please don't paste your code here. Instead, use http://laravel.io/bin"
   '!pb'           : "Please avoid using pastebin.com as it is slow and forces others to look at ads.  Please use http://laravel.io/bin.  Thanks!"
   '!rules'        : "You may review our room rules at http://goo.gl/Tl77U2"
+  '!docs'         : "The !docs syntax is deprecated, please use `Liona show <user> docs for <topic>`"

   # Helpers
   '!ugt'          : "It is always morning when someone comes into a channel. We call that Universal Greeting Time http://www.total-knowledge.com/~ilya/mips/ugt.html"


fix count

fix count

--- models/mongo.coffee
+++ models/mongo.coffee
@@ -54,16 +54,13 @@
       fn null, unpacked

   ClassMethods:
-    count: (query, options, fn) ->
-      unless fn?
-        fn = options
-        options = {}
+    count: (query, fn) ->
       unless fn?
         fn = query
         query = null
       @prototype.collection (error, collection) ->
         return fn error if error?
-        collection.count query, options, fn
+        collection.count query, fn

     firstOrCreate: (query, options, fn) ->
       unless fn?


fixed bug if computation is stopped

fixed bug if computation is stopped

resolves #1

--- server-transform.coffee
+++ server-transform.coffee
@@ -30,21 +30,21 @@
       doc = @applyTransformations cursor?._serverTransformations, doc
       doc = @transformSubCursors publication, doc
       return doc
-    computation = null
+    computations = {}

     handle = cursor.observe
       added: (doc) ->
         publication.added collectionName, doc._id, transform(doc)

-        computation.stop() if computation?
-        computation = Tracker.autorun ->
+        computations[doc._id].stop() if computations[doc._id]?
+        computations[doc._id] = Tracker.autorun ->
           publication.changed collectionName, doc._id, transform(doc)

       changed: (doc) ->
         publication.changed collectionName, doc._id, transform(doc)

-        computation.stop() if computation?
-        computation = Tracker.autorun ->
+        computations[doc._id].stop() if computations[doc._id]?
+        computations[doc._id] = Tracker.autorun ->
           publication.changed collectionName, doc._id, transform(doc)

       removed: (doc) ->
@@ -52,7 +52,8 @@

     publication.onStop ->
       handle?.stop()
-      computation?.stop()
+      for key, computation in computations
+        computation.stop()

   @transformSubCursors: (publication, obj) ->
     for key, cursor of obj when cursor?._cursorDescription?


Fix indefiniteLength error on first frame

--- app/lib/Angel.coffee
+++ app/lib/Angel.coffee
@@ -151,7 +151,7 @@
     if @work?.indefiniteLength and world.victory?
       finished = true
       world.totalFrames = world.frames.length
-    firstChangedFrame = if @work.indefiniteLength then 0 else world.findFirstChangedFrame @shared.world
+    firstChangedFrame = if @work?.indefiniteLength then 0 else world.findFirstChangedFrame @shared.world
     eventType = if finished then 'new-world-created' else 'streaming-world-updated'
     if finished
       @shared.world = world


Fixed initial team setting.

Fixed initial team setting.

--- app/lib/Angel.coffee
+++ app/lib/Angel.coffee
@@ -100,7 +100,7 @@
     world.findFirstChangedFrame @shared.world
     @shared.world = world
     errorCount = (t for t in @shared.world.thangs when t.errorsOut).length
-    Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, errorCount: errorCount, goalStates: goalStates
+    Backbone.Mediator.publish 'god:new-world-created', world: world, firstWorld: @shared.firstWorld, errorCount: errorCount, goalStates: goalStates, team: me.team
     for scriptNote in @shared.world.scriptNotes
       Backbone.Mediator.publish scriptNote.channel, scriptNote.event
     @shared.goalManager?.world = world


Solve some naming issues.

Solve some naming issues.

--- server/bw/battle.coffee
+++ server/bw/battle.coffee
@@ -104,12 +104,12 @@

     @once 'end', (winnerId) ->
       @finished = true
-      @setExpiration()
+      @resetExpiration()

     # Store when the battle was created
     @createdAt = Date.now()

-    @setExpiration()
+    @resetExpiration()

   begin: ->
     @tell(Protocol.INITIALIZE, @getTeams().map((t) -> t.toJSON(hidden: true)))
@@ -820,11 +820,11 @@
     @tell(Protocol.BATTLE_EXPIRED)
     @emit('end')  if !@finished

-  setExpiration: ->
+  resetExpiration: ->
     clearTimeout(@expirationId)  if @expirationId
-    @expirationId = setTimeout((=> @expire()  unless @expired), @getTTL())
-
-  getTTL: ->
+    @expirationId = setTimeout((=> @expire()  unless @expired), @makeTTL())
+
+  makeTTL: ->
     if @isOver()
       # 48 hours
       48 * 60 * 60 * 1000


Add labels for new buttons

Add labels for new buttons

--- app/lib/en-us.coffee
+++ app/lib/en-us.coffee
@@ -355,6 +355,8 @@
     coat: 'Coat'
     tail: 'Tail'
     build: 'Build'
+    pattern: 'Pattern'
+    horns: 'Horns'

   characteristicValues:
     likeCatdog: 'cat/dog'


Update eo.coffee. Diplomat block

Update eo.coffee. Diplomat block

--- app/locale/eo.coffee
+++ app/locale/eo.coffee
@@ -40,12 +40,12 @@
 #    page_not_found: "Page not found"

   diplomat_suggestion:
-#    title: "Help translate CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
-#    sub_heading: "We need your language skills."
+    title: "Helpu traduki CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
+    sub_heading: "Ni bezonas vian lingvokapabloj."
     pitch_body: "We develop CodeCombat in English, but we already have players all over the world. There's got to be at least one of them who wants to play in Esperanto! So if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Esperanto."
     missing_translations: "Until we can translate everything into Esperanto, you'll see English when Esperanto isn't available."
-#    learn_more: "Learn more about being a Diplomat"
-#    subscribe_as_diplomat: "Subscribe as a Diplomat"
+    learn_more: "Eksciu pli pri esti Diplomato"
+    subscribe_as_diplomat: "Aboni kiel Diplomato"

 #  play:
 #    play_as: "Play As" # Ladder page


Remove unnecessary newlines in app/locales/fr.coffee

--- app/locale/fr.coffee
+++ app/locale/fr.coffee
@@ -953,15 +953,12 @@
     nolan_title: "Directeur des Ventes"
     lisa_title: "Directeur du développement"
     david_title: "Directeur Marketing"
-
     titles_csm: "Responsable de la réussite client"
     titles_territory_manager: "Directrice régional"
-
     retrostyle_title: "Illustration"
     retrostyle_blurb: "Jeux RetroStyle"
     bryukh_title: "Designer de jeux" # {change}
     bryukh_blurb: "Construuit des puzzles"
-
     community_title: "... et notre communité open-source"
     community_subtitle: "Plus de 500 contributeurs ont aidé à construire CodeCombat, et de plus en plus nous rejoignent chaque semaine !"
     community_description_3: "CodeCombat est un"


trimming the fat (arrows)

trimming the fat (arrows)

--- test/integration/ssh_dataset.coffee
+++ test/integration/ssh_dataset.coffee
@@ -97,8 +97,8 @@
           @modalTextContent.should.include 'copy to clipboard'

         context 'when I close the modal, and reopen it', ->
-          before (done) =>
-            wd40.click '#done', =>
+          before (done) ->
+            wd40.click '#done', ->
               setTimeout done, 400

           before clickSSHButton
@@ -108,13 +108,13 @@
               @modalTextContent = text.toLowerCase()
               done()

-          it 'the modal window does not ask for my SSH key', =>
+          it 'the modal window does not ask for my SSH key', ->
             @modalTextContent.should.not.include 'add your ssh key:'

-          it 'the modal window tells me how to SSH in', =>
+          it 'the modal window tells me how to SSH in', ->
             @modalTextContent.should.include 'ssh 3006375731@localhost'

-          it 'the modal window lets me add another SSH key', =>
+          it 'the modal window lets me add another SSH key', ->
             @modalTextContent.should.include 'add another ssh key'

           context 'when I click the "Add another SSH key" button', ->


try to fix regular expression interpolation

--- app/locale/fr.coffee
+++ app/locale/fr.coffee
@@ -1395,7 +1395,7 @@
 #    instructor: "Instructor: "
 #    youve_been_invited_1: "You've been invited to join "
 #    youve_been_invited_2: ", where you'll learn "
-#    youve_been_invited_3: " with your classmates in CodeCombat."
+#    youve_been_invited_3: " w"+"ith your classmates in CodeCombat."
 #    by_joining_1: "By joining "
 #    by_joining_2: "will be able to help reset your password if you forget or lose it. You can also verify your email address so that you can reset the password yourself!"
 #    sent_verification: "We've sent a verification email to:"


Translated "contribute" page

Translated "contribute" page

--- app/locale/it.coffee
+++ app/locale/it.coffee
@@ -794,22 +794,22 @@
   classes:
     archmage_title: "Arcimago"
     archmage_title_description: "(Programmazione)"
-#    archmage_summary: "If you are a developer interested in coding educational games, become an archmage to help us build CodeCombat!"
+    archmage_summary: "Se sei uno sviluppatore interessato a programmare videogiochi educativi, diventa un Arcimago per aiutarci a costruire CodeCombat!"
     artisan_title: "Artigiano"
     artisan_title_description: "(Costruzione livelli)"
-#    artisan_summary: "Build and share levels for you and your friends to play. Become an Artisan to learn the art of teaching others to program."
+    artisan_summary: "Crea e condividi livelli con cui far giocare i tuoi amici. Diventa un Artigiano per apprendere l'arte di insegnare agli altri a programmare!"
     adventurer_title: "Avventuriero"
     adventurer_title_description: "(Prova di gioco dei livelli)"
-#    adventurer_summary: "Get our new levels (even our subscriber content) for free one week early and help us work out bugs before our public release."
+    adventurer_summary: "Ottieni i nuovi livelli (anche quelli per abbonati) gratuitamente una settimana prima e aiutaci a scovare e sistemare i bug prima della pubblicazione!"
     scribe_title: "Scriba"
     scribe_title_description: "(Scrittura articoli)"
-#    scribe_summary: "Good code needs good documentation. Write, edit, and improve the docs read by millions of players across the globe."
+    scribe_summary: "Del buon codice necessita di buona documentazione. Scrivi, modifica e migliora i documenti letti da milioni di giocatori in tutto il mondo."
     diplomat_title: "Diplomatico"
     diplomat_title_description: "(Traduzione)"
-#    diplomat_summary: "CodeCombat is localized in 45+ languages by our Diplomats. Help us out and contribute translations."
+    diplomat_summary: "CodeCombat è localizzato in più di 45 lingue dai nostri Diplomatici. Aiutaci contribuendo con le tue traduzioni."
     ambassador_title: "Ambasciatore"
     ambassador_title_description: "(Supporto)"
-#    ambassador_summary: "Tame our forum users and provide direction for those with questions. Our ambassadors represent CodeCombat to the world."
+    ambassador_summary: "Guida gli utenti del forum e dai consigli a coloro che hanno delle domande. I nostri Ambasciatori rappresentano CodeCombat nel mondo."

   editor:
     main_title: "Editor di CodeCombat"
@@ -903,8 +903,8 @@

   contribute:
     page_title: "Contribuire"
-#    intro_blurb: "CodeCombat is 100% open source! Hundreds of dedicated players have helped us build the game into what it is today. Join us and write the next chapter in CodeCombat's quest to teach the world to code!"
-#    alert_account_message_intro: "Hey there!"
+    intro_blurb: "CodeCombat è al 100% open source! Centinaia di giocatori appassionati ci hanno aiutati a rendere il gioco quello che è oggi. Unisciti a noi e scrivi il prossimo capitolo nella missione di CodeCombat per insegnare al mondo a programmare!"
+    alert_account_message_intro: "Ehilà!"
 #    alert_account_message: "To subscribe for class emails, you'll need to be logged in first."
 #    archmage_introduction: "One of the best parts about building games is they synthesize so many different things. Graphics, sound, real-time networking, social networking, and of course many of the more common aspects of programming, from low-level database management, and server administration to user facing design and interface building. There's a lot to do, and if you're an experienced programmer with a hankering to really dive into the nitty-gritty of CodeCombat, this class might be for you. We would love to have your help building the best programming game ever."
     class_attributes: "Attributi di classe"
@@ -1129,31 +1129,31 @@
 #    thang: "Thang"
 #    thangs: "Thangs"
     level_session: "La tua sessione"
-#    opponent_session: "Opponent Session"
+    opponent_session: "Sessione avversario"
     article: "Articolo"
 #    user_names: "User Names"
 #    thang_names: "Thang Names"
 #    files: "Files"
 #    top_simulators: "Top Simulators"
 #    source_document: "Source Document"
-#    document: "Document"
+    document: "Documento"
 #    sprite_sheet: "Sprite Sheet"
 #    employers: "Employers"
 #    candidates: "Candidates"
 #    candidate_sessions: "Candidate Sessions"
 #    user_remark: "User Remark"
 #    user_remarks: "User Remarks"
-#    versions: "Versions"
-#    items: "Items"
-#    hero: "Hero"
-#    heroes: "Heroes"
-#    achievement: "Achievement"
+    versions: "Versioni"
+    items: "Oggetti"
+    hero: "Eroe"
+    heroes: "Eroi"
+    achievement: "Impresa"
 #    clas: "CLAs"
 #    play_counts: "Play Counts"
-#    feedback: "Feedback"
+    feedback: "Feedback"
 #    payment_info: "Payment Info"
-#    campaigns: "Campaigns"
-#    poll: "Poll"
+    campaigns: "Campagne"
+    poll: "Sondaggio"
 #    user_polls_record: "Poll Voting History"

 #  delta:


Fix placeholder for the subscribe module

--- app/locale/ru.coffee
+++ app/locale/ru.coffee
@@ -532,9 +532,9 @@

   subscribe:
     comparison_blurb: "Отточите свое мастерство благодаря подписке на CodeCombat!"
-    feature1: "80+ основных уровней на просторах 4-х миров" # {change}
-    feature2: "7 могущественных новых героев с уникальными способностями!" # {change}
-    feature3: "60+ дополнительных уровней" # {change}
+    feature1: "$t(data.levelsCount)+ основных уровней на просторах $t(data.worldsCount)-х миров" # {change}
+    feature2: "$t(data.heroesCount) могущественных новых героев с уникальными способностями!" # {change}
+    feature3: "$t(data.bonusLevelsCount)+ дополнительных уровней" # {change}
     feature4: "{{gems}} бонусных самоцветов каждый месяц!"
     feature5: "Обучающие видеоролики"
     feature6: "Эксклюзивная поддержка по электронной почте"


Update ru.coffee

Update ru.coffee

--- app/locale/ru.coffee
+++ app/locale/ru.coffee
@@ -49,9 +49,9 @@
     blog: "Блог"
     forum: "Форум"
     account: "Аккаунт"
-#    profile: "Profile"
+    profile: "Профиль"
 #    stats: "Stats"
-#    code: "Code"
+    code: "Программный код"
     admin: "Админ"
     home: "Домой"
     contribute: "Сотрудничество"
@@ -179,14 +179,14 @@
     new_password: "Новый пароль"
     new_password_verify: "Подтверждение пароля"
     email_subscriptions: "Email-подписки"
-#    email_subscriptions_none: "No Email Subscriptions."
+    email_subscriptions_none: "Нет подписок по Email."
     email_announcements: "Оповещения"
     email_announcements_description: "Получать email-оповещения о последних новостях CodeCombat."
     email_notifications: "Уведомления"
     email_notifications_summary: "Настройки автоматических email-уведомлений, основанных на вашей активности на CodeCombat."
     email_any_notes: "Все уведомления"
     email_any_notes_description: "Отключите, чтобы больше не получать извещения."
-#    email_news: "News"
+    email_news: "Новости"
     email_recruit_notes: "Возможности для работы"
     email_recruit_notes_description: "Если вы действительно хорошо играете, то мы можем связаться с вами для предложения (лучшей) работы."
     contributor_emails: "Рассылки по классам участников"
@@ -234,20 +234,20 @@
     example_blog: "Блог"
     example_personal_site: "Персональный сайт"
     links_header: "Персональные ссылки"
-#    links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog."
-#    links_name: "Link Name"
-#    links_name_help: "What are you linking to?"
-#    links_link_blurb: "Link URL"
-#    basics_header: "Update basic info"
+    links_blurb: "Ссылки на другие сайты или профили, которые вы хотите указать Например: Аккаунт на GitHub'е, на LinkedIn'е, или на вашем блоге."
+    links_name: "Название ссылки"
+    links_name_help: "На что вы ссылаетесь?"
+    links_link_blurb: "URL ссылки"
+    basics_header: "Обновить базовую информацию."
 #    basics_active: "Open to Offers"
 #    basics_active_help: "Want interview offers right now?"
 #    basics_job_title: "Desired Job Title"
-#    basics_job_title_help: "What role are you looking for?"
+    basics_job_title_help: "Какую роль вы хотите?"
     basics_city: "Город"
 #    basics_city_help: "City you want to work in (or live in now)."
     basics_country: "Страна"
 #    basics_country_help: "Country you want to work in (or live in now)."
-#    basics_visa: "US Work Status"
+    basics_visa: "Статус работы в США"
 #    basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship? (If you live in Canada or Australia, mark authorized.)"
 #    basics_looking_for: "Looking For"
     basics_looking_for_full_time: "Полная занятость"
@@ -311,18 +311,18 @@

   employers:
 #    hire_developers_not_credentials: "Hire developers, not credentials."
-#    get_started: "Get Started"
+    get_started: "Начнем"
 #    already_screened: "We've already technically screened all our candidates"
 #    filter_further: ", but you can also filter further:"
-#    filter_visa: "Visa"
+    filter_visa: "Visa"
 #    filter_visa_yes: "US Authorized"
 #    filter_visa_no: "Not Authorized"
 #    filter_education_top: "Top School"
 #    filter_education_other: "Other"
-#    filter_role_web_developer: "Web Developer"
+    filter_role_web_developer: "Веб-разработчик"
 #    filter_role_software_developer: "Software Developer"
 #    filter_role_mobile_developer: "Mobile Developer"
-#    filter_experience: "Experience"
+    filter_experience: "Опыт"
 #    filter_experience_senior: "Senior"
 #    filter_experience_junior: "Junior"
 #    filter_experience_recent_grad: "Recent Grad"
@@ -358,7 +358,7 @@
     grid: "Сетка"
     customize_wizard: "Настройки волшебника"
     home: "На главную"
-#    game_menu: "Game Menu"
+    game_menu: "Меню игры"
     guide: "Руководство"
     restart: "Перезапустить"
     goals: "Цели"


replace C++11 extensions in Darwin to use C++14 standard.

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -128,7 +128,7 @@
     if GrammarUtils.OperatingSystem.isDarwin()
       "File Based":
         command: "bash"
-        args: (context) -> ['-c', "xcrun g++ -fcolor-diagnostics -Wc++11-extensions -Wall -include stdio.h -include iostream '" + context.filepath + "' -o /tmp/cpp.out && /tmp/cpp.out"]
+        args: (context) -> ['-c', "xcrun g++ -fcolor-diagnostics -std=c++14 -Wall -include stdio.h -include iostream '" + context.filepath + "' -o /tmp/cpp.out && /tmp/cpp.out"]
     else if GrammarUtils.OperatingSystem.isLinux()
       "Selection Based":
         command: "bash"


Update uk.coffee (#3645)

Update uk.coffee (#3645)

Add translation of lines 185-233 ("code" section)

--- app/locale/uk.coffee
+++ app/locale/uk.coffee
@@ -102,7 +102,7 @@
     blog: "Блоґ"
     forum: "Форум"
     account: "Акаунт"
-#    my_account: "My Account"
+    my_account: "Мій Акаунт"
     profile: "Профіль"
     stats: "Статистика"
     code: "Код"
@@ -115,8 +115,8 @@
     students: "Учням"
     teachers: "Учителям"
     careers: "Робота"
-#    facebook: "Facebook"
-#    twitter: "Twitter"
+    facebook: "Facebook"
+    twitter: "Twitter"
 #    create_a_class: "Create a Class"
     other: "Інше"
 #    learn_to_code: "Learn to Code!"
@@ -182,55 +182,55 @@
     campaign_old_multiplayer: "(Застаріло) Стара багатокористувацька арена"
 #    campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."

-#  code:
-#    if: "if" # Keywords--these translations show up on hover, so please translate them all, even if it's kind of long. (In the code editor, they will still be in English.)
-#    else: "else"
-#    elif: "else if"
-#    while: "while"
-#    loop: "loop"
-#    for: "for"
-#    break: "break"
-#    continue: "continue"
-#    pass: "pass"
-#    return: "return"
-#    then: "then"
-#    do: "do"
-#    end: "end"
-#    function: "function"
-#    def: "define"
-#    var: "variable"
-#    self: "self"
-#    hero: "hero"
-#    this: "this"
-#    or: "or"
-#    "||": "or"
-#    and: "and"
-#    "&&": "and"
-#    not: "not"
-#    "!": "not"
-#    "=": "assign"
-#    "==": "equals"
-#    "===": "strictly equals"
-#    "!=": "does not equal"
-#    "!==": "does not strictly equal"
-#    ">": "is greater than"
-#    ">=": "is greater than or equal"
-#    "<": "is less than"
-#    "<=": "is less than or equal"
-#    "*": "multiplied by"
-#    "/": "divided by"
-#    "+": "plus"
-#    "-": "minus"
-#    "+=": "add and assign"
-#    "-=": "subtract and assign"
-#    True: "True"
-#    true: "true"
-#    False: "False"
-#    false: "false"
-#    undefined: "undefined"
-#    null: "null"
-#    nil: "nil"
-#    None: "None"
+  code:
+    if: "якщо" # Keywords--these translations show up on hover, so please translate them all, even if it's kind of long. (In the code editor, they will still be in English.)
+    else: "інакше"
+    elif: "інакше якщо"
+    while: "поки"
+    loop: "цикл"
+    for: "для"
+    break: "перервати цикл"
+    continue: "розпочати виконання наступної ітерації циклу"
+    pass: "передати"
+    return: "повернути"
+    then: "то"
+    do: "чинити"
+    end: "кінець"
+    function: "функція"
+    def: "визначити"
+    var: "змінна"
+    self: "'сам' - вказує на об'єкт, функція якого викликається"
+    hero: "герой"
+    this: "'це' - вказує на об'єкт, функція якого викликається"
+    or: "або"
+    "||": "або"
+    and: "та"
+    "&&": "та"
+    not: "не"
+    "!": "не"
+    "=": "присвоїти"
+    "==": "дорівнює"
+    "===": "строго дорівнює"
+    "!=": "не дорівнює"
+    "!==": "строго не дорівнює"
+    ">": "більше"
+    ">=": "більше або дорівнює"
+    "<": "менше"
+    "<=": "менше або дорівнює"
+    "*": "помножити"
+    "/": "поділити"
+    "+": "додати"
+    "-": "відняти"
+    "+=": "додати та присвоїти"
+    "-=": "відняти та присвоїти"
+    True: "Істинний"
+    true: "істинний"
+    False: "Хибний"
+    false: "хибний"
+    undefined: "невизначений"
+    null: "нуль"
+    nil: "нуль"
+    None: "Жоден"

   share_progress_modal:
     blurb: "У тебе гарно виходить! Розкажи своїм батькам як багато ти знаєш завдяки CodeCombat."


Fix #141, let Change judge whether its linewise or not by detecting selection range

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -1051,7 +1051,8 @@
       @activateMode('normal')
       return

-    text = if @target.isLinewise?() then "\n" else ''
+    text = ''
+    text = "\n" if swrap.detectVisualModeSubmode(@editor) is 'linewise'
     @editor.transact =>
       for selection in @editor.getSelections()
         @setTextToRegisterForSelection(selection)


no more ";"

no more ";"

--- site/coffee/main.coffee
+++ site/coffee/main.coffee
@@ -43,18 +43,18 @@
       data: {'code': input},
       success: (result) ->
         PyCodeMirror.setValue(result)
-        now = new Date().getTime();
+        now = new Date().getTime()
         $("#build-msgs").text(now + " Updated.")
         $("#repl-root").removeClass("error")
         $("#repl-root").addClass("ok")
       statusCode: {
         500: (response) ->
-          now = new Date().getTime();
+          now = new Date().getTime()
           $("#build-msgs").text(now + " " + response.responseText)
           $("#repl-root").removeClass("ok")
           $("#repl-root").addClass("error")
       }
-  });
+  })

 $(document).ready(->


Use new getPath() method

Use new getPath() method

--- lib/image-editor-view.coffee
+++ lib/image-editor-view.coffee
@@ -21,7 +21,7 @@
       @originalWidth = @image.width()
       @loaded = true
       @centerImage()
-      @imageEditorStatusView = new ImageEditorStatusView(editor.getUri(), @image)
+      @imageEditorStatusView = new ImageEditorStatusView(editor.getPath(), @image)

     @subscribe $(window), 'resize', _.debounce((=> @centerImage()), 300)
     @command 'image-view:zoom-in', => @zoomIn()


Add keybindings to placeholder text

Add keybindings to placeholder text

--- lib/keybindings-panel.coffee
+++ lib/keybindings-panel.coffee
@@ -36,7 +36,7 @@
       atom.workspaceView.trigger('application:open-your-keymap')
       false

-    @filter.setPlaceholderText('Search')
+    @filter.setPlaceholderText('Search keybindings')
     @keyBindings = _.sortBy(atom.keymap.getKeyBindings(), 'keystroke')
     @appendKeyBindings(@keyBindings)


Correct missing dependency on the collection.

--- lib/models/collection.coffee
+++ lib/models/collection.coffee
@@ -3,6 +3,7 @@
   # Filename: models/model.coffee
   NS = NS or {}
   isInBrowser = typeof module is 'undefined' and typeof window isnt 'undefined'
+  metadataBuilder = if isInBrowser then NS.Helpers.metadataBuilder else require("../helpers/metadata_builder").metadataBuilder
   # Base class for all models. Define all transverses methods on the model.
   class Collection extends Backbone.Collection
     # The model name can be define.


:lipstick: git commit message

:lipstick: git commit message

--- lib/models/git-commit.coffee
+++ lib/models/git-commit.coffee
@@ -23,15 +23,16 @@
   watcher.close() if watcher?
   # format the text to be ignored in the commit message
   text = text.replace(/\s*\(.*\)\n/g, '')
-  text = text.replace(/\n/g, "\n# ")
+  text = text.trim().replace(/\n/g, "\n# ")
   # in order to make sure each line doesn't start with a space, the preceding
   #   line should end with a backslash
   fs.writeFileSync commitFilePath(),
-     "#{amendMsg}\n\
-      # Please enter the commit message for your changes. Lines starting\n\
-      # with '#' will be ignored, and an empty message aborts the commit.\n\
-      # Remove hyphen(-) and update commit message as necessary for amend.\n\
-      # #{text}",
+     """#{amendMsg}
+      # Please enter the commit message for your changes. Lines starting
+      # with '#' will be ignored, and an empty message aborts the commit.
+      # Remove hyphen(-) and update commit message as necessary for amend.
+      #
+      # #{text}""",
     flag: 'w+'
   showFile()


new swrap util to get normalized position

--- lib/selection-wrapper.coffee
+++ lib/selection-wrapper.coffee
@@ -22,6 +22,16 @@

   getBufferRange: ->
     @selection.getBufferRange()
+
+  getNormalizedBufferPosition: ->
+    point = @selection.getHeadBufferPosition()
+    editor = @selection.editor
+    if @isForwarding()
+      screenPoint = editor.screenPositionForBufferPosition(point)
+      point = editor.bufferPositionForScreenPosition screenPoint.translate([0, -1]),
+        clip: 'backward'
+        wrapBeyondNewlines: true
+    point

   getBufferPositionFor: (which, {fromProperty}={}) ->
     fromProperty ?= false


Fix script escaping

Fix script escaping

--- lib/skeleton/template.coffee
+++ lib/skeleton/template.coffee
@@ -196,7 +196,7 @@
           <script>
           document.write('<script src=' +
           ('__proto__' in {} ? 'http://zeptojs.com/zepto.min.js' : 'http://code.jquery.com/jquery-1.7.2.min.js') +
-          '.js><\/script>')
+          '><\\/script>')
           </script>
           <%- js('scripts.js') %>
         </body>


Add support for scoped settings

Add support for scoped settings

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -1,21 +1,6 @@
-_ = require 'underscore-plus'
-
 module.exports =
-class Settings
-  update: (settings={}) ->
-    @load(settings)
-
-  load: (settings={}) ->
-    flatSettings = {}
-    @flattenSettings flatSettings, settings
-    for setting, value of flatSettings
-      if _.isArray value
-        currentValue = atom.config.get setting
-        value = _.union currentValue, value
-      atom.config.setRawValue setting, value
-    # atom.config.emit 'updated'
-
-  flattenSettings: (root, dict, path) ->
+  flatten: (root, dict, path) ->
+    _ = require 'underscore-plus'
     for key, value of dict
       dotPath = key
       dotPath = "#{path}.#{key}" if path?
@@ -23,4 +8,32 @@
       if not isObject
         root[dotPath] = value
       else
-        @flattenSettings root, dict[key], dotPath
+        @flatten root, dict[key], dotPath
+
+  resetUserSettings: (settings, scope) ->
+    _ = require 'underscore-plus'
+    flatSettings = {}
+    options = if scope then {scopeSelector: scope} else {}
+    options.save = false
+
+    @flatten flatSettings, settings
+    for setting, value of flatSettings
+      if _.isArray value
+        valueOptions = if scope then {scope: scope} else {}
+        currentValue = atom.config.get setting, valueOptions
+        value = _.union currentValue, value
+      atom.config.set setting, value, options
+
+  enable: (settings) ->
+    if settings.global?
+      settings['*'] = settings.global
+      delete settings.global
+
+    if settings['*']?
+      scopedSettings = settings
+      settings = settings['*']
+      delete scopedSettings['*']
+
+      @resetUserSettings setting, scope for scope, setting of scopedSettings
+
+    @resetUserSettings settings


:bomb: vmpAutoChangeModeInUI set true by default again! since usability improved further

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -68,7 +68,7 @@
     enum: ['smartcase', 'sensitive', 'insensitive']
     description: "Case sensitivity of your query in narrow-editor"
   vmpAutoChangeModeInUI:
-    default: false
+    default: true
     description: "Automatically change mode on narrow-editor, insert-mode(=prompt), normal-mode(=item-area)"
   vmpStartInInsertModeForUI:
     default: true


Don't barf if the pid is no longer present on the slave

--- lib/surveyor.coffee
+++ lib/surveyor.coffee
@@ -148,6 +148,7 @@
           routes[service.repo][k] = v

         routes[service.repo].routes ?= []
+        continue if !model.slaves[name].processes[pid]?
         if model.slaves[name].processes[pid].status is 'running'
           routes[service.repo].routes.push
             host: model.slaves[name].ip


Defer tooltips until a mouseenter occurs

Tooltips take about 3ms to create so creating one for every
tab at startup slows things down when reopening with many editors
open.

--- lib/tab-view.coffee
+++ lib/tab-view.coffee
@@ -27,9 +27,16 @@
     @updateTitle()
     @updateIcon()
     @updateModifiedStatus()
-    @updateTooltip()
+
+    # Defer creating the tooltip until the tab is moused over
+    @one 'mouseenter', =>
+      @hasBeenMousedOver = true
+      @updateTooltip()
+      @trigger 'mouseenter' # Trigger again so the tooltip shows

   updateTooltip: ->
+    return unless @hasBeenMousedOver
+
     @destroyTooltip()

     if itemPath = @item.getPath?()


Fixed hotkeys

Fixed hotkeys

--- def/fr/menu_linux.cson
+++ def/fr/menu_linux.cson
@@ -3,7 +3,7 @@
     value: "&Fichier"
     submenu:
       "New &Window":
-        value: "Nouvelle fenêtre (&W)"
+        value: "Nouvelle &fenêtre"
       "&New File":
         value: "&Nouveau fichier"
       "&Open File…":
@@ -13,24 +13,24 @@
       "Add Project Folder…":
         value: "Ajouter un dossier au projet..."
       "Reopen Project":
-        value: "Ouvrir un projet récent"
+        value: "Rouvrir un projet"
         submenu:
           "Clear Project History":
             value: "Effacer l'historique du projet"
       "Reopen Last &Item":
-        value: "Rouvr&ir le dernier élément"
+        value: "Rouvrir le &dernier élément"
       "&Save":
-        value: "Enregi&strer"
+        value: "&Enregistrer"
       "Save &As…":
-        value: "Enregistrer sous... (&A)"
+        value: "Enregistrer &sous..."
       "Save A&ll":
-        value: "Enregistrer tout (&L)"
+        value: "Enre&gistrer tout"
       "&Close Tab":
-        value: "Fermer l'onglet (&C)"
+        value: "Fer&mer l'onglet"
       "Close &Pane":
         value: "Fermer le &panneau"
       "Clos&e Window":
-        value: "F&ermer la fenêtre"
+        value: "Fermer la fenêt&re"
       "Quit":
         value: "Quitter"
       "Close All Tabs":
@@ -41,73 +41,73 @@
       "&Undo":
         value: "Ann&uler"
       "&Redo":
-        value: "&Refaire"
+        value: "Re&faire"
       "&Cut":
-        value: "&Couper"
+        value: "Cou&per"
       "C&opy":
-        value: "C&opier"
+        value: "&Copier"
       "Copy Pat&h":
         value: "Copier le c&hemin"
       "&Paste":
-        value: "Coller (&P)"
+        value: "C&oller"
       "Select &All":
-        value: "Sélectionner tout (&A)"
+        value: "&Sélectionner tout"
       "&Toggle Comments":
-        value: "Commen&ter/Décommenter"
+        value: "Commenter/&Décommenter"
       Lines:
         value: "Lignes"
         submenu:
           "&Indent":
             value: "&Indenter"
           "&Outdent":
-            value: "Désindenter (&O)"
+            value: "&Désindenter"
           "&Auto Indent":
-            value: "Indentation &automatique"
+            value: "Indentation automati&que"
           "Move Line &Up":
-            value: "Remonter la ligne (&U)"
+            value: "&Remonter la ligne"
           "Move Line &Down":
-            value: "&Descendre la ligne"
+            value: "Des&cendre la ligne"
           "Du&plicate Lines":
-            value: "Du&pliquer les lignes"
+            value: "Dupliquer les li&gnes"
           "D&elete Line":
-            value: "Supprimer la lign&e"
+            value: "&Supprimer la ligne"
           "&Join Lines":
-            value: "Fusionner les lignes (&J)"
+            value: "&Fusionner les lignes"
       Columns:
         value: "Colonnes"
         submenu:
           "Move Selection &Left":
-            value: "Dép&lacer la sélection à gauche"
+            value: "Déplacer la sélection à &gauche"
           "Move Selection &Right":
-            value: "Déplacer la sélection à d&roite"
+            value: "Déplacer la sélection à &droite"
       Text:
         value: "Texte"
         submenu:
           "&Upper Case":
-            value: "Mettre en maj&uscule"
+            value: "Mettre en m&ajuscule"
           "&Lower Case":
-            value: "Mettre en minuscu&le"
+            value: "Mettre en m&inuscule"
           "Delete to End of &Word":
-            value: "Retirer la fin du mot (&W)"
+            value: "Retirer la fin du &mot"
           "Delete to Previous Word Boundary":
             value: "Retirer le début du mot"
           "Delete to Next Word Boundary":
             value: "Supprimer jusqu'au prochain mot"
           "&Delete Line":
-            value: "Supprimer la ligne (&D)"
+            value: "&Supprimer la ligne"
           "&Transpose":
-            value: "In&tervertir les caractères"
+            value: "Intervertir les &caractères"
       Folding:
         value: "Pliage"
         submenu:
           "&Fold":
-            value: "Plier (&F)"
+            value: "&Plier"
           "&Unfold":
-            value: "Déplier (&U)"
+            value: "&Déplier"
           "Unfold &All":
-            value: "Déplier tout (&A)"
+            value: "Déplier t&out"
           "Fol&d All":
-            value: "Plier tout (&D)"
+            value: "Plier to&ut"
           "Fold Level 1":
             value: "Plier au niveau 1"
           "Fold Level 2":
@@ -127,7 +127,7 @@
           "Fold Level 9":
             value: "Plier au niveau 9"
       "&Preferences":
-        value: "&Préférences"
+        value: "Préférenc&es"
       "Config…":
         value: "Paramètres..."
       "Init Script…":
@@ -158,10 +158,10 @@
       "Select Grammar":
         value: "Choisir le langage"
   "&View":
-    value: "Affichage (&V)"
+    value: "&Affichage"
     submenu:
       "Toggle &Full Screen":
-        value: "Activer/Désactiver le mode plein écran (&F)"
+        value: "Activer/Désactiver le mode &plein écran"
       "Toggle Menu Bar":
         value: "Activer/Désactiver la barre de menu"
       Panes:
@@ -197,19 +197,19 @@
           "&Reload Window":
             value: "&Recharger la fenêtre"
           "Run Package &Specs":
-            value: "Lancer le&s tests unitaires du package"
+            value: "Lancer les tests &unitaires du package"
           "Run &Benchmarks":
-            value: "Lancer les tests de performance (&B)"
+            value: "Lancer les tests de &performance"
           "Toggle Developer &Tools":
-            value: "Afficher/Masquer les ou&tils de développement"
+            value: "Afficher/Masquer les &outils de développement"
       "&Increase Font Size":
-        value: "Augmenter la ta&ille de la police"
+        value: "&Augmenter la taille de la police"
       "&Decrease Font Size":
         value: "&Diminuer la taille de la police"
       "Re&set Font Size":
-        value: "Réinitiali&ser la taille de la police"
+        value: "&Réinitialiser la taille de la police"
       "Toggle Soft &Wrap":
-        value: "Activer/Désactiver le retour à la ligne souple (&W)"
+        value: "Activer/Désactiver le retour à la li&gne souple"
       "Toggle Command Palette":
         value: "Afficher/Masquer la liste des commandes"
       "Toggle Tree View":
@@ -218,35 +218,35 @@
     value: "&Sélection"
     submenu:
       "Add Selection &Above":
-        value: "Étendre la sélection &au-dessus"
+        value: "Étendre la sélection au-dess&us"
       "Add Selection &Below":
-        value: "Étendre la sélection en dessous (&B)"
+        value: "Étendre la sélection en dess&ous"
       "S&plit into Lines":
         value: "Sé&parer en lignes"
       "Single Selection":
         value: "Sélection unique"
       "Select to &Top":
-        value: "É&tendre la sélection au début"
+        value: "Étendre la sélection au &début"
       "Select to Botto&m":
-        value: "Étendre la sélection à la fin (&M)"
+        value: "Étendre la sélection à la &fin"
       "Select &Line":
-        value: "Sélectionner toute la &ligne"
+        value: "Sélectionner toute la li&gne"
       "Select &Word":
-        value: "Sélectionner le mot (&W)"
+        value: "Sélectionner le &mot"
       "Select to Beginning of W&ord":
-        value: "Étendre la sélection au début du m&ot"
+        value: "Étendre la sélection au dé&but du mot"
       "Select to Beginning of L&ine":
-        value: "Étendre la sélection au début de la l&igne"
+        value: "Étendre la sélection au début de la lig&ne"
       "Select to First &Character of Line":
         value: "Étendre la sélection au premier &caractère de la ligne"
       "Select to End of Wor&d":
-        value: "Étendre la sélection à la fin &du mot"
+        value: "Étendre la sélection à la fin du mo&t"
       "Select to End of Lin&e":
-        value: "Étendre la sélection à la fin de la ligne&"
+        value: "Étendre la sélection à la fin de la lign&e"
       "Select Inside Brackets":
         value: "Sélectionner l'intérieur des parenthèses"
   "F&ind":
-    value: "Chercher (&I)"
+    value: "&Recherche"
     submenu:
       "Find in Buffer":
         value: "Chercher dans le fichier courant"
@@ -283,12 +283,12 @@
   "&Packages":
     value: "&Packages"
   "&Help":
-    value: "Aide (&H)"
+    value: "Ai&de"
     submenu:
       "View &Terms of Use":
-        value: "Conditions d'u&tilisation"
+        value: "&Conditions d'utilisation"
       "View &License":
-        value: "Voir la &licence"
+        value: "&Voir la licence"
       "&Documentation":
         value: "&Documentation"
       "Frequently Asked Questions":


reload source when vlc suspended

reload source when vlc suspended

--- lib/video-player-view.coffee
+++ lib/video-player-view.coffee
@@ -64,10 +64,9 @@
     self = this
     streamServer = 'http://localhost:' + vlc.port
     video.attr 'src', streamServer
-    vlc.streaming files, (data) ->
-      self.reloadSrc()
-    video.on 'ended', () ->
-      self.reloadSrc()
+    vlc.streaming files, (data) -> self.reloadSrc()
+    video.on 'ended', () -> self.reloadSrc()
+    video.on 'suspend', () -> self.reloadSrc()

   _playWithHtml5Video: (video, files) ->
     counter = 0


Avoid popup blockers by using redirection

--- assets/js/app.coffee
+++ assets/js/app.coffee
@@ -121,7 +121,8 @@
             license = repositoryInfo.license
             @setStatus "Error", @repositoryLicense repositoryFullName, license
           else # The repository is unlicensed
-            window.open "https://github.com/#{repositoryFullName}/community/license/new?template=#{@licenseId}"
+            window.location.href =
+              "https://github.com/#{repositoryFullName}/community/license/new?template=#{@licenseId}"
             @setStatus ""
             @inputEl.val("")


Proper handling of localhost for testing

--- src/Carrot.coffee
+++ src/Carrot.coffee
@@ -36,6 +36,7 @@
     @appSecret = appSecret
     @status = Carrot.Status.Unknown
     @hostname = hostname or "gocarrot.com"
+    @scheme = ("http" if hostname?.match(/^localhost/)) or "https"

   ajaxGet: (url, callback) ->
     if @request
@@ -68,7 +69,7 @@
     true

   validateUser: (callback) ->
-    @ajaxGet("https://#{@hostname}/games/#{@appId}/users.json?id=#{encodeURIComponent(@udid)}",
+    @ajaxGet("#{@scheme}://#{@hostname}/games/#{@appId}/users.json?id=#{encodeURIComponent(@udid)}",
       (statusCode) =>
         switch statusCode
           when 200
@@ -85,7 +86,7 @@
     )

   createUser: (accessToken, callback) ->
-    @ajaxPost("https://#{@hostname}/games/#{@appId}/users.json",
+    @ajaxPost("#{@scheme}://#{@hostname}/games/#{@appId}/users.json",
       {'access_token': accessToken, 'api_key': @udid},
       (statusCode) =>
         switch statusCode
@@ -153,11 +154,11 @@
       url_string = url_string + "#{k}=#{url_params[k]}&"
     url_string = url_string.slice(0, url_string.length - 1);

-    sign_string = "POST\n#{@hostname}\n#{endpoint}\n#{url_string}"
+    sign_string = "POST\n#{@hostname.split(':')[0]}\n#{endpoint}\n#{url_string}"
     digest = CryptoJS.HmacSHA256(sign_string, @appSecret).toString(CryptoJS.enc.Base64)
     url_params.sig = digest

-    @ajaxPost("https://#{@hostname}#{endpoint}", url_params, callback)
+    @ajaxPost("#{@scheme}://#{@hostname}#{endpoint}", url_params, callback)

   GUID: ->
     S4 = () => return Math.floor(Math.random() * 0x10000).toString(16)


Switch to images

Switch to images

--- src/Carrot.coffee
+++ src/Carrot.coffee
@@ -27,9 +27,8 @@
     Error: 'Operation unsuccessful.'

   @trackLoad: (appId, signedRequest) ->
-    req = new XMLHttpRequest()
-    req.open 'GET', 'https://gocarrot.com/tracking?app_id=' + appId + '&signed_request=' + signedRequest
-    req.send()
+    img = new Image()
+    img.src = 'https://gocarrot.com/tracking?app_id=' + appId + '&signed_request=' + signedRequest

   constructor: (appId, udid, appSecret, hostname) ->
     try


Use Xapi#createVirtualInterface in vm.create().

--- src/api/vm.coffee
+++ src/api/vm.coffee
@@ -51,19 +51,9 @@
   # free device number.
   deviceId = 0
   yield Bluebird.all(map(VIFs, (VIF) =>
-    network = @getObject VIF.network, 'network'
-
-    return xapi.call 'VIF.create', {
-
-      device: String(deviceId++)
-      MAC: VIF.MAC ? ''
-      MTU: '1500'
-      network: network.ref
-      other_config: {}
-      qos_algorithm_params: {}
-      qos_algorithm_type: ''
-      VM: ref
-    }
+    return xapi.createVirtualInterface(ref, VIF.network, {
+      position: deviceId++
+    })
   ))

   # TODO: ? yield xapi.call 'VM.set_PV_args', ref, 'noninteractive'


Rename the asset mutator prop

Rename the asset mutator prop

--- src/assets.coffee
+++ src/assets.coffee
@@ -16,7 +16,7 @@
 		fallback:        [String, Object]
 		posterFromImage: { type: Boolean, default: false }
 		requireAutoplay: { type: Boolean, default: true }
-		mutateAsset:     Function
+		assetMutator:     Function

 	##############################################################################
 	mounted: ->
@@ -71,8 +71,8 @@

 		# Apply mutations if they were defined
 		applyAssetMutation: (asset, src) ->
-			if @mutateAsset
-			then @mutateAsset
+			if @assetMutator
+			then @assetMutator
 				asset: asset
 				src: src
 				vm: @


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/camera.coffee
+++ src/camera.coffee
@@ -40,7 +40,7 @@
       I.scroll.y.clamp(centerRect.top, centerRect.bottom).clamp(I.cameraBounds.top, I.cameraBounds.bottom - I.screen.height)
     )

-    I.scroll.x = I.scro
+    I.scroll.x = I.scroll.x.clamp(I.cameraBounds.left, I.cameraBounds.right - I.screen.width)

   followTypes =
     centered: (object) ->


for safety

for safety

--- src/client.coffee
+++ src/client.coffee
@@ -156,6 +156,7 @@

     constructor = (data={}, params={}) ->

+      new_url = null
       # resource("http://something.com/foo")
       if params?.constructor == String
         new_url = params
@@ -166,7 +167,8 @@

       for key, value of data
         @[key] = value
-      @url = new_url
+      if new_url
+        @url = new_url
       return @

     constructor.prototype._actions = {}


do not save file to disk when storing an attachment

--- server/controllers/attachments.coffee
+++ server/controllers/attachments.coffee
@@ -1,33 +1,56 @@
 fs = require "fs"
+multiparty = require 'multiparty'
+log =  require('printit')
+    date: true
+    prefix: 'attachment'
+Readable = require('stream').Readable
+
 db = require('../helpers/db_connect_helper').db_connect()
 deleteFiles = require('../helpers/utils').deleteFiles
-multiparty = require 'multiparty'

 ## Actions

 # POST /data/:id/attachments/
+# Add an attachment via uploading a file through a multipart form.
 module.exports.add = (req, res, next) ->
     files = {}

     # Parse given form to extract image blobs.
-    form = new multiparty.Form
-        uploadDir: __dirname + '../../uploads'
-        keepExtensions: true
-        maxFilesSize: 10 * 1024 * 1024 * 1024
+    form = new multiparty.Form()
     form.parse req

-    # Get fields from form.
-    form.on 'field', (name, value) ->
-        req.body[name] = value
-        cid = value if name is 'cid'
+    # We read part one by one to avoid writing the full file to the disk
+    # and send it directly as a stream.
+    form.on 'part', (part) ->

-    # Get files from form.
-    form.on 'file', (name, val) ->
-        val.name = val.originalFilename
-        val.type = val.headers['content-type'] or null
-        files[name] = val
+        # It's a field
+        unless part.filename?
+            part.resume()
+
+        # It's a file, we pipe it directly to Couch to avoid too much memory
+        # consumption.
+        # The 'file' event stores the file to the disk and we don't want that.
+        else
+            fileData =
+                name: part.filename
+                "content-type": part.headers['content-type']
+
+            log.info "attachment #{fileData.name} ready for storage"
+
+            stream = db.saveAttachment req.doc, fileData, (err) ->
+                if err
+                    console.log "[Attachment] err: " + JSON.stringify err
+                    next new Error err.error
+                else
+                    # We end the request because we expect to have only one
+                    # file.
+                    res.send 201, success: true
+                    next()
+
+            part.pipe stream
+

     form.on 'progress', (bytesReceived, bytesExpected) ->
         # TODO handle progress
@@ -35,35 +58,13 @@
     form.on 'error', (err) ->
         next err

-    # When form is fully parsed, data are saved into CouchDB.
     form.on 'close', ->
-        if files.file?
-            file = files.file
-            if req.body.name? then name = req.body.name else name = file.name
-
-            fileData =
-                name: name
-                "content-type": file.type
-
-            stream = db.saveAttachment req.doc, fileData, (err) ->
-                if err
-                    console.log "[Attachment] err: " + JSON.stringify err
-                    deleteFiles req.files
-                    next new Error err.error
-                else
-                    deleteFiles req.files
-                    res.send 201, success: true
-                    next()
-
-            fs.createReadStream(file.path).pipe stream
-
-        else
-            err = new Error "No file sent"
-            err.status = 400
-            next err
+        log.info 'attachement form fully parsed'

 # GET /data/:id/attachments/:name
+# Download given attachment (represented by name) linked to given document
+# (represented by id).
 module.exports.get = (req, res, next) ->
     name = req.params.name

@@ -83,8 +84,9 @@
     stream.pipe res

-
 # DELETE /data/:id/attachments/:name
+# Remove given attachment (represented by name) from given document
+# (represented by id).
 module.exports.remove = (req, res, next) ->
     name = req.params.name


:memo: Clean up docs

:memo: Clean up docs

--- src/config.coffee
+++ src/config.coffee
@@ -88,7 +88,7 @@
     _.extend hash, defaults
     @emit 'updated'

-  # Public: Get the path to the config file being used.
+  # Public: Get the {String} path to the config file being used.
   getUserConfigPath: ->
     @configFilePath

@@ -98,10 +98,10 @@

   # Public: Retrieves the setting for the given key.
   #
-  # keyPath - The {String} name of the key to retrieve
-  #
-  # Returns the value from Atom's default settings, the user's configuration file,
-  # or `null` if the key doesn't exist in either.
+  # keyPath - The {String} name of the key to retrieve.
+  #
+  # Returns the value from Atom's default settings, the user's configuration
+  # file, or `null` if the key doesn't exist in either.
   get: (keyPath) ->
     value = _.valueForKeyPath(@settings, keyPath) ? _.valueForKeyPath(@defaultSettings, keyPath)
     _.deepClone(value)
@@ -110,8 +110,8 @@
   #
   # keyPath - The {String} name of the key to retrieve
   #
-  # Returns the value from Atom's default settings, the user's configuration file,
-  # or `NaN` if the key doesn't exist in either.
+  # Returns the value from Atom's default settings, the user's configuration
+  # file, or `NaN` if the key doesn't exist in either.
   getInt: (keyPath) ->
     parseInt(@get(keyPath))

@@ -121,8 +121,8 @@
   # defaultValue - The integer {Number} to fall back to if the value isn't
   #                positive, defaults to 0.
   #
-  # Returns the value from Atom's default settings, the user's configuration file,
-  # or `defaultValue` if the key value isn't greater than zero.
+  # Returns the value from Atom's default settings, the user's configuration
+  # file, or `defaultValue` if the key value isn't greater than zero.
   getPositiveInt: (keyPath, defaultValue=0) ->
     Math.max(@getInt(keyPath), 0) or defaultValue

@@ -130,8 +130,8 @@
   #
   # This value is stored in Atom's internal configuration file.
   #
-  # keyPath - The {String} name of the key
-  # value - The value of the setting
+  # keyPath - The {String} name of the key.
+  # value - The value of the setting.
   #
   # Returns the `value`.
   set: (keyPath, value) ->
@@ -147,6 +147,8 @@
   # The new value will be `true` if the value is currently falsy and will be
   # `false` if the value is currently truthy.
   #
+  # keyPath - The {String} name of the key.
+  #
   # Returns the new value.
   toggle: (keyPath) ->
     @set(keyPath, !@get(keyPath))
@@ -170,6 +172,8 @@

   # Public: Is the key path value its default value?
   #
+  # keyPath - The {String} name of the key.
+  #
   # Returns a {Boolean}, `true` if the current value is the default, `false`
   # otherwise.
   isDefault: (keyPath) ->
@@ -180,7 +184,7 @@
   # keyPath - The {String} key path.
   # value - The value to push to the array.
   #
-  # Returns the new array length of the setting.
+  # Returns the new array length {Number} of the setting.
   pushAtKeyPath: (keyPath, value) ->
     arrayValue = @get(keyPath) ? []
     result = arrayValue.push(value)
@@ -192,7 +196,7 @@
   # keyPath - The {String} key path.
   # value - The value to shift onto the array.
   #
-  # Returns the new array length of the setting.
+  # Returns the new array length {Number} of the setting.
   unshiftAtKeyPath: (keyPath, value) ->
     arrayValue = @get(keyPath) ? []
     result = arrayValue.unshift(value)
@@ -242,9 +246,9 @@
     callback(value) if options.callNow ? true
     subscription

-  # Public: Unobserve all callbacks on a given key
-  #
-  # keyPath - The {String} name of the key to unobserve
+  # Public: Unobserve all callbacks on a given key.
+  #
+  # keyPath - The {String} name of the key to unobserve.
   unobserve: (keyPath) ->
     @off("updated.#{keyPath.replace(/\./, '-')}")


Grab both parts of key=value. Do not check lhs part here.

--- src/config.coffee
+++ src/config.coffee
@@ -2,7 +2,7 @@
 path = require 'path'

 Config =
-  SETTING_RE: /^(\w[-\.\w]*)=(.*)$/
+  SETTING_RE: /^(.*)=(.*)$/
   TASK_REGEX: /^[a-z][-a-z0-9_]*$/
   DEFAULT_TASK: 'install'


cleanup config

cleanup config

--- src/config.coffee
+++ src/config.coffee
@@ -1,17 +1,37 @@
-Mongoose = require 'mongoose'
+C = {}

-config = {}
-
-config.mongoURI  or= 'mongodb://localhost:27018/test'
-config.mongoServerOptions or= {
+C.mongoURI = 'mongodb://localhost:27018/test'
+C.mongoServerOptions = {
 	server:
 		socketOptions:
 			# The time in milliseconds to attempt a connection before timing out.
 			connectTimeoutMS: 5000
 }
-config.port          or= 3000
-# config.baseURI       or= "http://localhost:#{config.port}"
-# config.apiPrefix     or= '/api'
-# config.schemaPrefix  or= '/schema'
+C.backendURI   = 'http://localhost:8081/infoLink/infolis-api'
+C.port         = 3000
+# C.baseURI      = "http://www-test.bib.uni-mannheim.de/infolis/ws"
+C.baseURI      = "http://localhost:#{C.port}"
+C.apiPrefix    = '/api'
+C.schemaPrefix = '/schema'
+C.expandContexts = ['basic', {
+	# infolis: 'http://localhost:3000/schema/'
+	# infolis: 'http://www-test.bib.uni-mannheim.de/infolis/schema/'
+	infolis: "#{C.baseURI}#{C.schemaPrefix}/"
+	bibo: 'http://purl.org/ontology/bibo/'
+	dc: 'http://purl.org/dc/elements/1.1/'
+	dcterms: 'http://purl.org/dc/terms/'
+	dm2e: 'http://onto.dm2e.eu/schema/dm2e/'
+	dqm: 'http://purl.org/dqm-vocabulary/v1/dqm#'
+	foaf: 'http://xmlns.com/foaf/0.1/'
+	omnom: 'http://onto.dm2e.eu/schema/omnom/'
+	owl: 'http://www.w3.org/2002/07/owl#'
+	rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
+	rdfs: 'http://www.w3.org/2000/01/rdf-schema#'
+	schema: 'http://schema.org/'
+	science: 'http://semanticscience.org/resource/'
+	skos: 'http://www.w3.org/2004/02/skos/core#'
+	uri4uri: 'http://uri4uri.net/vocab#'
+	xsd: 'http://www.w3.org/2001/XMLSchema#'
+}]

-module.exports = config
+module.exports = C


Copy edits

Copy edits

--- lib/react_components/hello_world.cjsx
+++ lib/react_components/hello_world.cjsx
@@ -12,8 +12,8 @@

You're looking at the Coffeescript React Quickstart project by Kyle Mathews.

It has a number of nice goodies baked in including:

-
Live reloading for both CSS and Javascript! This really speeds up your development. Live reloading is powered by the Webpack module bundler and the react-hot-loader projects.

-
Full JSX with Coffeescript support provided by coffee-react-transform.

+
Live reloading while developing for both CSS and Javascript! This really speeds up development. Live reloading is powered by the Webpack module bundler and react-hot-loader projects.

+
Write your JSX in Coffeescript thanks to coffee-react-transform.

Amazing URL-driven-development (UDD) with the react-router project.

Uses Gulp for building CSS and Javascript. Run cult watch for rebuilding css/js on the fly while developing and cult build to create minified versions for deploying to production.

Starter Sass project with sensible defaults. See the <Link to="styleguide">styleguide page</Link> for more.


Fix linter error

Fix linter error

--- src/editor.coffee
+++ src/editor.coffee
@@ -294,7 +294,7 @@
   onDidChangeSoftWrapped: (callback) ->
     @displayBuffer.onDidChangeSoftWrapped(callback)

-  onDidChangeGrammar: (callback)->
+  onDidChangeGrammar: (callback) ->
     @displayBuffer.onDidChangeGrammar(callback)

   onDidStopChanging: (callback) ->