Serialize logged in username with view

Serialize logged in username with view

--- src/packages/github-sign-in/lib/sign-in-view.coffee
+++ src/packages/github-sign-in/lib/sign-in-view.coffee
@@ -3,11 +3,7 @@
 ScrollView = require 'scroll-view'
 keytar = require 'keytar'

-module.exports =
 class SignInView extends ScrollView
-  @activate: ->
-    new SignInView()
-
   @content: ->
     @div class: 'sign-in-view overlay from-top', =>
       @h4 'Sign in to GitHub'
@@ -19,7 +15,7 @@
         @button outlet: 'cancel', class: 'btn', tabindex: 4, 'Cancel'
       @div outlet: 'alert', class: 'alert alert-error'

-  initialize: ->
+  initialize: ({@signedInUser}={})->
     rootView.command 'github:sign-in', => @attach()

     @username.on 'core:confirm', => @generateOAuth2Token()
@@ -38,6 +34,8 @@

     @subscribe $(document.body), 'click focusin', (e) =>
       @detach() unless $.contains(this[0], e.target)
+
+  serialize: -> {@signedInUser}

   validate: ->
     canSignIn = $.trim(@username.val()).length > 0 and @password.val().length > 0
@@ -60,7 +58,8 @@
     @setElementEnabled(@password, false)
     @setElementEnabled(@signIn, false)

-    credentials = btoa("#{$.trim(@username.val())}:#{@password.val()}")
+    username = $.trim(@username.val())
+    credentials = btoa("#{username}:#{@password.val()}")
     request =
       scopes: ['user', 'repo', 'gist']
       note: 'GitHub Atom'
@@ -77,6 +76,7 @@

       success: ({token}={}) =>
         if token?.length > 0
+          @signedInUser = username
           unless keytar.replacePassword('github.com', 'github', token)
             console.warn 'Unable to save GitHub token to keychain'
         @detach()
@@ -91,10 +91,34 @@
         @alert.text(message).show()

   attach: ->
-    @username.val('')
+    if @signedInUser?
+      @username.val(@signedInUser)
+    else
+      @username.val('')
+
     @password.val('')
     @setElementEnabled(@username, true)
     @setElementEnabled(@password, true)
     @alert.hide()
     rootView.append(this)
-    @username.focus()
+
+    if @signedInUser?
+      @password.focus()
+    else
+      @username.focus()
+
+module.exports =
+  signInView: null
+
+  activate: (state) ->
+    @signInView = new SignInView(state)
+
+  deactivate: ->
+    @signInView?.remove()
+    @signInView = null
+
+  serialize: ->
+    if @signInView?
+      @signInView.serialize()
+    else
+      @state


:art: make split with '\\n' easy by Enter

--- lib/operator.coffee
+++ lib/operator.coffee
@@ -440,6 +440,10 @@
     @onDidChangeInput (input) =>
       @vimState.hover.add(input[-1..])
     @focusInput(charsMax: 10)
+
+  isComplete: ->
+    @input = "\\n" if @input is ''
+    super

   getNewText: (text) ->
     regex = ///#{_.escapeRegExp(@input)}///g


Fix stranhe null.constructor() error

Fix stranhe null.constructor() error

--- lib/prefixer.coffee
+++ lib/prefixer.coffee
@@ -11,6 +11,8 @@
     if i == 'parent' and typeof(value) == 'object'
       cloned[i] = parent if parent
     else if i == 'source'
+      cloned[i] = value
+    else if i == null
       cloned[i] = value
     else if value instanceof Array
       cloned[i] = value.map (i) -> clone(i, cloned)


Add support for !

Add support for !

Closes #1

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -21,6 +21,25 @@
       description: 'Add 1 whitespace to the right'
       type: 'boolean'
       default: true
+    '!-enabled':
+      title: 'Enable aligning !'
+      type: 'boolean'
+      default: false
+    '!-alignment':
+      title: 'Padding for !'
+      description: 'Pad left or right of the character'
+      type: 'string'
+      default: 'left'
+    '!-leftSpace':
+      title: 'Left space for !'
+      description: 'Add 1 whitespace to the left'
+      type: 'boolean'
+      default: true
+    '!-rightSpace':
+      title: 'Right space for !'
+      description: 'Add 1 whitespace to the right'
+      type: 'boolean'
+      default: false
     '{-enabled':
       title: 'Enable aligning {'
       type: 'boolean'
@@ -41,5 +60,6 @@
       type: 'boolean'
       default: true
   privateConfig:
+    '!-scope': 'punctuation'
     ':-scope': 'key-value|property-name|operator'
     '{-scope': 'property-list.begin'


Update user vars and functions when pass 1 min

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -43,18 +43,24 @@
         @userFuncs = JSON.parse(stdout)

       @lastPath = editor.getPath()
+      @lastTimeEx = new Date();

   # Required: Return a promise, an array of suggestions, or null.
   # {editor, bufferPosition, scopeDescriptor, prefix}
   getSuggestions: (request) ->
     new Promise (resolve) =>
+      if @lastTimeEx? and Math.floor((new Date() - @lastTimeEx) / 60000) < 1
+        typeEx = false
+      else
+        typeEx = true
+
       if @notShowAutocomplete(request)
         resolve([])
       else if @isVariable(request)
-        @execute(true, request)
+        @execute(true, request, typeEx)
         resolve(@getVarsCompletions(request))
       else if @isFunCon(request)
-        @execute(false, request)
+        @execute(false, request, typeEx)
         resolve(@getCompletions(request))
       else
         resolve([])


Fix for scopes support and storages

Fix for scopes support and storages

--- lib/provider.coffee
+++ lib/provider.coffee
@@ -44,7 +44,8 @@
     scopes = scopeDescriptor.getScopesArray()
     return true if scopes.indexOf('constant.other.php') isnt -1 or
       scopes.indexOf('keyword.control.php') isnt -1 or
-      scopes.indexOf('storage.type.php') isnt -1
+      scopes.indexOf('storage.type.php') isnt -1 or
+      scopes.indexOf('support.function.construct.php')

   getCompletions: ({prefix}) ->
     completions = []
@@ -86,6 +87,6 @@
     text: suggestion.text
     type: suggestion.type
     snippet: suggestion.snippet ?= null
-    # leftLabel: suggestion.leftLabel ?= ''
+    leftLabel: suggestion.leftLabel ?= null
     description: suggestion.description ?= "PHP <#{suggestion.text}> #{suggestion.type}"
-    descriptionMoreURL: suggestion.descriptionMoreURL ?= ''
+    descriptionMoreURL: suggestion.descriptionMoreURL ?= null


Track ReactEditor config files

Track ReactEditor config files

--- lib/reporter.coffee
+++ lib/reporter.coffee
@@ -26,9 +26,9 @@

     @viewNameForPaneItem: (item) ->
       name = item.getViewClass?().name ? item.constructor.name
-      return name unless name is 'EditorView'
+      return name unless item.getPath

-      itemPath = item.getPath?()
+      itemPath = item.getPath()
       return name unless path.dirname(itemPath) is atom.getConfigDirPath()

       extension = path.extname(itemPath)


fix send status

fix send status

--- lib/response.coffee
+++ lib/response.coffee
@@ -24,7 +24,7 @@

   unless @get('Content-Type')
     @set 'Content-Type', 'text/html; charset=utf-8'
-  @status = status if status
+  @statusCode = status if status

   @end data
   @


Normalize route paths

Normalize route paths

Fixes #257

--- lib/restivus.coffee
+++ lib/restivus.coffee
@@ -74,6 +74,7 @@
   ###
   addRoute: (path, options, endpoints) ->
     # Create a new route and add it to our list of existing routes
+    path = path.replace /^\//, ''
     route = new share.Route(this, path, options, endpoints)
     @_routes.push(route)


Rename add() to addRoute() for clarity

Rename add() to addRoute() for clarity

Now that we have an addCollection() method in Restivus, having an add()
method seems ambiguous. This is an API-breaking change that will require
a minor version bump.

--- lib/restivus.coffee
+++ lib/restivus.coffee
@@ -53,7 +53,7 @@
   ###*
     Add endpoints for the given HTTP methods at the given path
   ###
-  add: (path, options, methods) ->
+  addRoute: (path, options, methods) ->
     # Create a new route and add it to our list of existing routes
     route = new Route(this, path, options, methods)
     @routes.push(route)
@@ -127,8 +127,8 @@
       , this

     # Add the routes to the API
-    @add path, defaultOptions, collectionRouteEndpoints
-    @add "#{path}/:id", defaultOptions, entityRouteEndpoints
+    @addRoute path, defaultOptions, collectionRouteEndpoints
+    @addRoute "#{path}/:id", defaultOptions, entityRouteEndpoints

     return

@@ -253,7 +253,7 @@

       After the user is logged in, the onLoggedIn hook is called (see Restfully.configure() for adding hook).
     ###
-    @add 'login', {authRequired: false},
+    @addRoute 'login', {authRequired: false},
       post: ->
         # Grab the username or email that the user is logging in with
         user = {}
@@ -288,7 +288,7 @@

       After the user is logged out, the onLoggedOut hook is called (see Restfully.configure() for adding hook).
     ###
-    @add 'logout', {authRequired: true},
+    @addRoute 'logout', {authRequired: true},
       get: ->
         # Remove the given auth token from the user's account
         authToken = @request.headers['x-auth-token']


shorten function

shorten function

--- workers/social/lib/social/models/graph/graph.coffee
+++ workers/social/lib/social/models/graph/graph.coffee
@@ -1,3 +1,4 @@
+_ = require 'underscore'
 neo4j = require "neo4j"
 {race} = require 'sinkrow'
 {Base, ObjectId, race} = require 'bongo'
@@ -50,15 +51,27 @@
       }
       collectObjects({klass:klass, selector:selector, modelName:modelName})

+  # returns object ids from a result set as array
+  # returns dict {colections: {'users':[id1,id2,id3]},
+  #               wantedOrder: ['users_id1', 'users_id2']
+  #             }
+  # this is needed for fetchObjectsFromMongo()
+  getIdsFromAResultSet: (resultSet)->
+    collections = {}
+    wantedOrder = []
+    for obj in resultSet
+      console.log "-------", obj
+      collections[obj.name] ||= []
+      collections[obj.name].push obj.id
+      wantedOrder.push idx: obj.id+'_'+obj.name
+    collections: collections, wantedOrder: wantedOrder
+
   runQuery:(query, options, callback)->
     {startDate, client} = options
-    if options.group?
-      {groupName, groupId} = options.group
-
+    {groupName, groupId} = options.group if options.group?
     @db.query query, {}, (err, results)=>
       tempRes = []
-      if err
-        callback err
+      if err then callback err
       else if results.length is 0 then callback null, []
       else
         collectRelations = race (i, res, fin)=>
@@ -68,16 +81,10 @@
               callback err
               fin()
             else
-                wantedOrder = []
-                collections = {}
                 if relatedResult.reply?
-                  for obj in relatedResult.reply
-                    collections[obj.name] ||= []
-                    collections[obj.name].push(obj.id)
-                    wantedOrder.push({id: obj.id, collection: obj.name, idx: obj.id+'_'+obj.name})
+                  {collections, wantedOrder} = @getIdsFromAResultSet relatedResult.reply
                   @fetchObjectsFromMongo collections, wantedOrder, (err, dbObjects)->
-                    for dbObj in dbObjects
-                      res.replies.push dbObj
+                    res.replies.push dbObj for dbObj in dbObjects
                     tempRes.push res
                     fin()
                 else
@@ -90,17 +97,10 @@
             callback null, tempRes

         resultData = []
-        wantedOrder = []
-        collections = {}
-        for result in results
-          obj = result.content.data
-          collections[obj.name] ||= []
-          collections[obj.name].push(obj.id)
-          wantedOrder.push({id: obj.id, collection: obj.name, idx: obj.id+'_'+obj.name})
+        {collections, wantedOrder} = @getIdsFromAResultSet _.map(results, (e)->e.content.data)
         @fetchObjectsFromMongo collections, wantedOrder, (err, dbObjects)->
           for dbObj in dbObjects
             collectRelations dbObj
-          #callback err, dbObjects

   objectify = (incomingObjects, callback)->


Scripts: second options parameter passed to ...

avoid the possible bug

--- workers/social/lib/social/render/scriptblock.coffee
+++ workers/social/lib/social/render/scriptblock.coffee
@@ -139,7 +139,7 @@
             campaignData = campaignData_.data
           if group
             currentGroup = group
-          bongoModels.JVM.fetchVmsByContext client, (err, vms) ->
+          bongoModels.JVM.fetchVmsByContext client, {}, (err, vms) ->
             console.log err  if err
             userVMs = vms or []
             kallback()


Don't use a class for module's functions

--- app/assets/javascripts/misc/utils.js.coffee
+++ app/assets/javascripts/misc/utils.js.coffee
@@ -1,9 +1,9 @@
-class SublimeVideo.Misc.Utils
-  @topDomainHost: ->
+SublimeVideo.Misc.Utils =
+  topDomainHost: ->
     document.location.host.split('.').slice(-2).join('.')

-  @iOS: ->
+  iOS: ->
     /i(p[oa]d|phone)/i.test(navigator.userAgent)

-  @capitalize: (str) ->
+  capitalize: (str) ->
     str.replace(/^\w/, ($0) -> $0.toUpperCase())


Destroy select2 before cache happens to avoid duplication

--- app/assets/javascripts/select2-rails.coffee
+++ app/assets/javascripts/select2-rails.coffee
@@ -1,9 +1,12 @@
 window.Binco.Select2 =
   load: (selector) ->
     selector = if typeof selector == 'string' then selector else '.select2-rails'
+    $(selector).select2()
+  destroy: (selector) ->
+    selector = if typeof selector == 'string' then selector else '.select2-rails'
     $(selector).each((i,e) ->
-      $(e).select2('destroy') if $(e).hasClass("select2-hidden-accessible")
-      $(e).select2()
+      $(e).select2('destroy')
     )

 $(document).on 'turbolinks:load', window.Binco.Select2.load
+$(document).on 'turbolinks:before-cache', window.Binco.Select2.destroy


User story edit lightbox, on close revert changes of us

--- app/coffee/modules/common/lightboxes.coffee
+++ app/coffee/modules/common/lightboxes.coffee
@@ -314,6 +314,19 @@
                 if data._error_message
                     $confirm.notify("error", data._error_message)

+        $el.on "click", ".close", (event) ->
+            event.preventDefault()
+            $scope.$apply ->
+                $scope.us.revert()
+            lightboxService.close($el)
+
+        $el.keydown (event) ->
+            code = if event.keyCode then event.keyCode else event.which
+            if code == 27
+                lightboxService.close($el)
+                $scope.$apply ->
+                    $scope.us.revert()
+
         $scope.$on "$destroy", ->
             $el.off()


Fixed lineJoin buglet.

Fixed lineJoin buglet.

--- bokehjs/src/coffee/common/properties.coffee
+++ bokehjs/src/coffee/common/properties.coffee
@@ -253,7 +253,7 @@
     ctx.strokeStyle = @color.value()
     ctx.globalAlpha = @alpha.value()
     ctx.lineWidth   = @width.value()
-    ctx.lineCap     = @join.value()
+    ctx.lineJoin    = @join.value()
     ctx.lineCap     = @cap.value()
     ctx.setLineDash(@dash.value())
     ctx.setLineDashOffset(@dash_offset.value())


fix limit option for findByName

fix limit option for findByName

--- src/client.coffee
+++ src/client.coffee
@@ -633,7 +633,7 @@
     params = { query: namePattern }
     if options
       if options.limit?
-        params.file_limit = limit
+        params.file_limit = options.limit
       if options.removed or options.deleted
         params.include_deleted = true
     @oauth.addAuthParams 'GET', url, params


Revert "Implement star_added and star_removed"

--- src/client.coffee
+++ src/client.coffee
@@ -341,14 +341,6 @@

       when "error"
         @emit 'error', message.error
-
-      when "star_added"
-        m = new Message @, message
-        @emit 'star_added', m
-
-      when "star_removed"
-        m = new Message @, message
-        @emit 'star_removed', m

       when "message"
         # is this the special message we get on reconnect?


Document client use of Socket.IO() with newer versions.

--- src/client.coffee
+++ src/client.coffee
@@ -50,6 +50,9 @@
           action.apply ctx, data

     context.connect = ->
+      # Socket.IO 1.1 would say: socket = io arguments...
+      # io() locates or create a manager and returns manager.socket(..).
+      # Manager.socket() locates or create a socket and returns it.
       context.socket = io.connect.apply io, arguments

     context.emit = ->
@@ -61,6 +64,9 @@

     context.share = (channel,socket,cb) ->
       zappa_prefix = settings.zappa_prefix ? ""
+      # socket.io points to the Manager for the socket.
+      # socket.io.engine is the engine.io-client; engine.id is set to the engine.io handshake sid (session id).
+      # socket.socket.sessionid is the old (0.9) Socket.IO sessionid.
       sessionid = socket.io?.engine.id ? socket.socket?.sessionid
       if sessionid?
         $.getJSON "#{zappa_prefix}/socket/#{channel}/#{sessionid}", cb


flashOnMoveToOccurrence  is default false

--- lib/settings.coffee
+++ lib/settings.coffee
@@ -109,7 +109,7 @@
     Unlike pure-Vim, `d`, `<<`, `>>` are not affected by this option, use independent `stayOn` options.
     """
   flashOnUndoRedo: true
-  flashOnMoveToOccurrence: true
+  flashOnMoveToOccurrence: false
   flashOnOperate: true
   flashOnOperateBlacklist:
     default: []


detect project from open project folders

--- lib/wakatime.coffee
+++ lib/wakatime.coffee
@@ -287,18 +287,30 @@
         callback()

 sendHeartbeat = (file, lineno, isWrite) ->
+  if not file.path? or file.path is undefined or fileIsIgnored(file.path)
+    return
+
   time = Date.now()
-  if isWrite or enoughTimePassed(time) or lastFile isnt file.path
-    if not file.path? or file.path is undefined or fileIsIgnored(file.path)
-      return
+  currentFile = file.path
+  if isWrite or enoughTimePassed(time) or lastFile isnt currentFile
     pythonLocation (python) ->
       return unless python? && apiKey?
-      args = [cliLocation(), '--file', file.path, '--key', apiKey, '--plugin', 'atom-wakatime/' + packageVersion]
+      args = [cliLocation(), '--file', currentFile, '--key', apiKey, '--plugin', 'atom-wakatime/' + packageVersion]
       if isWrite
         args.push('--write')
       if lineno?
         args.push('--lineno')
         args.push(lineno)
+
+      if atom.project.contains(file.path)
+        currentFile = file.path
+        for rootDir in atom.project.rootDirectories
+          realPath = rootDir.realPath
+          if currentFile.indexOf(realPath) > -1
+            args.push('--alternate-project')
+            args.push(path.basename(realPath))
+            break
+
       proc = execFile(python, args, (error, stdout, stderr) ->
         if error?
           if stderr? and stderr != ''


FIX: fullscreenapp shouldn't fail if there are no special-fonts specified

--- source/Art/Engine/FullScreenApp.coffee
+++ source/Art/Engine/FullScreenApp.coffee
@@ -63,7 +63,7 @@
     {fonts} = config

     @writeDom config
-    FontLoader.loadFonts fonts
+    FontLoader.loadFonts fonts if fonts
     @getDomReadyPromise()
     .then ->
       FontLoader.allFontsLoaded fonts


Remove superfluous console loging

Remove superfluous console loging

--- src/legacy/blueprint-parser.coffee
+++ src/legacy/blueprint-parser.coffee
@@ -16,7 +16,6 @@
 # Default async parser timeout
 process.env.PARSER_TIMEOUT ?= 10000
 PARSER_TIMEOUT = parseInt process.env.PARSER_TIMEOUT, 10
-console.log '\nTIMEOUT: ' + PARSER_TIMEOUT + '\n\n'

 countLines = (code, index) ->
   if index > 0


:lipstick:

:lipstick:

--- spec/app/text-mate-grammar-spec.coffee
+++ spec/app/text-mate-grammar-spec.coffee
@@ -242,12 +242,12 @@
       expect(tokens[0].value).toBe "//"
       expect(tokens[1].value).toBe " a singleLineComment"

-    it "does not loop infinitley (regression)", ->
+    it "does not loop infinitely (regression)", ->
       grammar = TextMateBundle.grammarForFilePath("hello.js")
       {tokens, ruleStack} = grammar.tokenizeLine("// line comment")
       {tokens, ruleStack} = grammar.tokenizeLine(" // second line comment with a single leading space", ruleStack)

-    describe "when inside an C block", ->
+    describe "when inside a C block", ->
       it "correctly parses a method. (regression)", ->
         grammar = TextMateBundle.grammarForFilePath("hello.c")
         {tokens, ruleStack} = grammar.tokenizeLine("if(1){m()}")


Avoid max_line_length warning in coffeelint

--- spec/chinese-translator-spec.coffee
+++ spec/chinese-translator-spec.coffee
@@ -3,7 +3,7 @@

   hasCommand = (element, name) ->
     commands = atom.commands.findCommands(target: element)
-    for command in commands when command.name is name
+    for command in commands when command.name is "chinese-translator:#{name}"
       return true

   translate = (command, callback) ->
@@ -28,31 +28,31 @@

   describe 'when the package activates', ->
     it 'creates the commands', ->
-      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-simplified-chinese')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-taiwan-standard')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-hong-kong-standard')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-traditional-chinese')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard-with-phrases')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-hong-kong-standard')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese-with-phrases')).toBeTruthy()
-      expect(hasCommand(editorView, 'chinese-translator:hong-kong-standard-to-simplified-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'traditional-chinese-to-simplified-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'traditional-chinese-to-taiwan-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'traditional-chinese-to-hong-kong-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-traditional-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-taiwan-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-taiwan-standard-with-phrases')).toBeTruthy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-hong-kong-standard')).toBeTruthy()
+      expect(hasCommand(editorView, 'taiwan-standard-to-simplified-chinese')).toBeTruthy()
+      expect(hasCommand(editorView, 'taiwan-standard-to-simplified-chinese-with-phrases')).toBeTruthy()
+      expect(hasCommand(editorView, 'hong-kong-standard-to-simplified-chinese')).toBeTruthy()

   describe 'when the package deactivates', ->
     beforeEach ->
       atom.packages.deactivatePackage('chinese-translator')
     it 'removes all commands', ->
-      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-simplified-chinese')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-taiwan-standard')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:traditional-chinese-to-hong-kong-standard')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-traditional-chinese')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-taiwan-standard-with-phrases')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:simplified-chinese-to-hong-kong-standard')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:taiwan-standard-to-simplified-chinese-with-phrases')).toBeFalsy()
-      expect(hasCommand(editorView, 'chinese-translator:hong-kong-standard-to-simplified-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'traditional-chinese-to-simplified-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'traditional-chinese-to-taiwan-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'traditional-chinese-to-hong-kong-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-traditional-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-taiwan-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-taiwan-standard-with-phrases')).toBeFalsy()
+      expect(hasCommand(editorView, 'simplified-chinese-to-hong-kong-standard')).toBeFalsy()
+      expect(hasCommand(editorView, 'taiwan-standard-to-simplified-chinese')).toBeFalsy()
+      expect(hasCommand(editorView, 'taiwan-standard-to-simplified-chinese-with-phrases')).toBeFalsy()
+      expect(hasCommand(editorView, 'hong-kong-standard-to-simplified-chinese')).toBeFalsy()

   describe 'when no text is selected', ->
     it 'translates all text in the editor', ->


Real pencilcode function name lists

Real pencilcode function name lists

--- src/coffee.coffee
+++ src/coffee.coffee
@@ -19,17 +19,70 @@
     'bk'
     'rt'
     'lt'
+    'slide'
+    'movexy'
+    'moveto'
+    'jump'
+    'jumpto'
+    'turnto'
+    'home'
+    'pen'
+    'fill'
     'dot'
-    'jumpto'
-    'moveto'
-    'pen'
+    'box'
+    'mirror'
+    'twist'
+    'scale'
+    'pause'
+    'st'
+    'ht'
+    'pu'
+    'pd'
+    'pe'
+    'pf'
+    'play'
+    'tone'
+    'silence'
+    'speed'
+    'wear'
+    'drawon'
+    'label'
+    'reload'
   ]

   VALUE_FUNCTIONS = [
+    'abs'
+    'acos'
+    'asin'
+    'atan'
+    'atan2'
+    'cos'
     'sin'
-    'cos'
+    'tan'
+    'ceil'
+    'floor'
+    'round'
+    'exp'
+    'ln'
+    'log10'
+    'pow'
+    'sqrt'
+    'max'
+    'min'
+    'random'
+    'pagexy'
+    'getxy'
+    'direction'
+    'distance'
+    'shown'
+    'hidden'
+    'inside'
     'touches'
+    'within'
+    'notwithin'
+    'nearest'
     'pressed'
+    'canvas'
   ]

   OPERATOR_PRECEDENCES =


native support for shortname

native support for shortname

--- src/config.coffee
+++ src/config.coffee
@@ -25,6 +25,7 @@
   config = merge {}, configs...
   config.servers = for k, v of config.servers
     v.host ?= k
+    v.shortname ?= k.split('.')[0]
     v
   for server in config.servers
     config.servers[server.host] = server


Optimizations by removing functions

Optimizations by removing functions

--- src/cursor.coffee
+++ src/cursor.coffee
@@ -70,7 +70,7 @@
         if keys.length or !ins_is_empty or !nins_is_empty
           if @_cursor.$ids
             for model_json in @store
-              json.push(JSONUtils.deepClone(model_json)) if _.contains(@_cursor.$ids, model_json.id) and _.isEqual(_.pick(model_json, keys), find_query)
+              json.push(JSONUtils.deepClone(model_json)) if (model_json.id in @_cursor.$ids) and _.isEqual(_.pick(model_json, keys), find_query)
             callback()

           else
@@ -92,7 +92,7 @@
         else
           # filter by ids
           if @_cursor.$ids
-            json = (JSONUtils.deepClone(model_json) for model_json in @store when _.contains(@_cursor.$ids, model_json.id))
+            json = (JSONUtils.deepClone(model_json) for model_json in @store when (model_json.id in @_cursor.$ids))
           else
             json = (JSONUtils.deepClone(model_json) for model_json in @store)
           callback()
@@ -134,7 +134,7 @@
         return callback(null, (if _.isArray(json) then !!json.length else json)) if exists

         if @hasCursorQuery('$page')
-          count_cursor = new MemoryCursor(_.extend(_.pick(@_cursor, '$unique'), @_find), _.extend(_.pick(@, ['model_type', 'store'])))
+          count_cursor = new MemoryCursor(_.extend(_.pick(@_cursor, '$unique'), @_find), _.pick(@, ['model_type', 'store']))
           count_cursor.count (err, count) =>
             return callback(err) if err
             callback(null, {
@@ -164,7 +164,7 @@
             (related_query = {}).id = value
             reverse_relation.model_type.cursor(related_query).toJSON (err, models_json) =>
               return callback(err) if err
-              mergeQuery(find_query, '_json', _.map(models_json, (test) -> test[reverse_relation.key]))
+              mergeQuery(find_query, '_json', (model_json[reverse_relation.key] for model_json in models_json))
               callback()
           else
             (related_query = {})[key] = value


fix bug when text inserted next to tab

fix bug when text inserted next to tab

--- src/editor.coffee
+++ src/editor.coffee
@@ -354,7 +354,7 @@
     position = Tandem.Position.makePosition(this, startIndex)
     startIndex = position.getIndex()
     leaf = position.getLeaf()
-    if _.keys(leaf.attributes).length > 0
+    if _.keys(leaf.attributes).length > 0 || Tandem.Utils.isIgnoreNode(leaf.node)
       [lineNode, lineOffset] = Tandem.Utils.getChildAtOffset(@doc.root, startIndex)
       line = @doc.findLine(lineNode)
       [beforeNode, afterNode] = line.splitContents(lineOffset)


Reorganize the Syntatic Queries section

Reorganize the Syntatic Queries section

--- src/editor.coffee
+++ src/editor.coffee
@@ -882,6 +882,14 @@
   lowerCase: ->
     @replaceSelectedText selectWordIfEmpty:true, (text) -> text.toLowerCase()

+  # Extended: Toggle line comments for rows intersecting selections.
+  #
+  # If the current grammar doesn't support comments, does nothing.
+  #
+  # Returns an {Array} of the commented {Range}s.
+  toggleLineCommentsInSelection: ->
+    @mutateSelectedText (selection) -> selection.toggleLineComments()
+
   # Convert multiple lines to a single line.
   #
   # Operates on all selections. If the selection is empty, joins the current
@@ -1376,7 +1384,7 @@
   Section: Syntatic Queries
   ###

-  # Public: Get the syntactic scopes for the given position in buffer
+  # Essential: Get the syntactic scopes for the given position in buffer
   # coordinates.
   #
   # For example, if called with a position inside the parameter list of an
@@ -1388,7 +1396,7 @@
   # Returns an {Array} of {String}s.
   scopesForBufferPosition: (bufferPosition) -> @displayBuffer.scopesForBufferPosition(bufferPosition)

-  # Public: Get the range in buffer coordinates of all tokens surrounding the
+  # Essential: Get the range in buffer coordinates of all tokens surrounding the
   # cursor that match the given scope selector.
   #
   # For example, if you wanted to find the string surrounding the cursor, you
@@ -1398,39 +1406,27 @@
   bufferRangeForScopeAtCursor: (selector) ->
     @displayBuffer.bufferRangeForScopeAtPosition(selector, @getCursorBufferPosition())

+  # Public: Get the syntactic scopes for the most recently added cursor's
+  # position. See {::scopesForBufferPosition} for more information.
+  #
+  # Returns an {Array} of {String}s.
+  scopesAtCursor: -> @getLastCursor().getScopes()
+  getCursorScopes: ->
+    deprecate 'Use Editor::scopesAtCursor() instead'
+    @scopesAtCursor()
+
+  logCursorScope: ->
+    console.log @getCursorScopes()
+
   # {Delegates to: DisplayBuffer.tokenForBufferPosition}
   tokenForBufferPosition: (bufferPosition) -> @displayBuffer.tokenForBufferPosition(bufferPosition)

-  # Public: Get the syntactic scopes for the most recently added cursor's
-  # position. See {::scopesForBufferPosition} for more information.
-  #
-  # Returns an {Array} of {String}s.
-  getCursorScopes: -> @getLastCursor().getScopes()
-
-  logCursorScope: ->
-    console.log @getCursorScopes()
-
-
-  # Public: Determine if the given row is entirely a comment
+  # Extended: Determine if the given row is entirely a comment
   isBufferRowCommented: (bufferRow) ->
     if match = @lineTextForBufferRow(bufferRow).match(/\S/)
       scopes = @tokenForBufferPosition([bufferRow, match.index]).scopes
       @commentScopeSelector ?= new TextMateScopeSelector('comment.*')
       @commentScopeSelector.matches(scopes)
-
-  # Public: Toggle line comments for rows intersecting selections.
-  #
-  # If the current grammar doesn't support comments, does nothing.
-  #
-  # Returns an {Array} of the commented {Range}s.
-  toggleLineCommentsInSelection: ->
-    @mutateSelectedText (selection) -> selection.toggleLineComments()
-
-
-
-
-
-

   ###
   Section: Clipboard Operations


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine.coffee
+++ src/engine.coffee
@@ -271,7 +271,7 @@

     self.include Bindable

-    defaultModules = ["Keyboard", "Mouse", "Ba", "Delay", "GameState", "Selector", "Collision"]
+    defaultModules = ["Keyboard", "Mouse", "Background", "Delay", "GameState", "Selector", "Collision"]
     modules = defaultModules.concat(I.includedModules)
     modules = modules.without([].concat(I.excludedModules))


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/follow.coffee
+++ src/follow.coffee
@@ -1,6 +1,6 @@
 ###*
 The Follow module provides a simple method to set an object's
-so that it will approach ano
+so that it will approach another

 # Health regeneration


follow docs

follow docs

--- src/follow.coffee
+++ src/follow.coffee
@@ -3,7 +3,7 @@
 velocity so that it will approach another object.

-# Make an enemy follow the player
+
 player = GameObject
   x: 50
   y: 50


shorter line

shorter line

--- src/hinoki.coffee
+++ src/hinoki.coffee
@@ -26,6 +26,7 @@
                 factory = container.factories?[id]
                 unless factory?
                     throw new Error "missing factory for service '#{id}'"
-                container.scope[id] = module.exports.inject container, factory, newChain
+                container.scope[id] =
+                    module.exports.inject container, factory, newChain

         fun.apply null, dependencyIds.map (id) -> container.scope[id]


line length correction

line length correction

--- app/assets/javascripts/annotation_document_manager.coffee
+++ app/assets/javascripts/annotation_document_manager.coffee
@@ -101,7 +101,7 @@

     this.waitingForApi = true
     responseProcessor = (annotationDocument) ->
-      console.log "AnnotationDocumentManager: loaded concrete annotation document (id: #{annotationDocument.id}, history request)"
+      console.log "AnnotationDocumentManager: loaded known annotation document (history request)"
       _this.documentStore.unshift annotationDocument
       _this.waitingForApi = false
     this.apiCall requestOptions, responseProcessor, postUpdateCallback


Fixed race condition.

Fixed race condition.

--- app/assets/javascripts/app/controllers/maintenance.coffee
+++ app/assets/javascripts/app/controllers/maintenance.coffee
@@ -37,12 +37,18 @@
   setMode: (e) =>
     value = @modeSetting.prop('checked')
     callback = ->
-      App.Setting.set('maintenance_mode', value)
-      App.WebSocket.send(
-        event:'maintenance'
-        data:
-          type: 'mode'
-          on: value
+      App.Setting.set(
+        'maintenance_mode',
+        value,
+        {
+          done: ->
+            App.WebSocket.send(
+              event:'maintenance'
+              data:
+                type: 'mode'
+                on: value
+            )
+        }
       )
     if value
       new App.ControllerConfirm(


Append HomeView subviews in 1 operation

Append HomeView subviews in 1 operation

--- app/assets/javascripts/backbone/views/home_view.js.coffee
+++ app/assets/javascripts/backbone/views/home_view.js.coffee
@@ -31,9 +31,9 @@
     else
       view = new ProjectMonitor.Views.ProjectView(model: model)
     @registerSubView(view)
-

   render: ->
-    @$el.empty()
-    @$el.append(subview.render().$el) for cid,subview of @subViews
+    $fragment = $(document.createDocumentFragment())
+    $fragment.append(subview.render().$el) for cid,subview of @subViews
+    @$el.html($fragment)
     @


text-row-tool minor refactor

text-row-tool minor refactor

--- app/assets/javascripts/components/mark/text-row-tool.cjsx
+++ app/assets/javascripts/components/mark/text-row-tool.cjsx
@@ -22,30 +22,20 @@
       {x, y}

   getInitialState: ->
-    # # DEBUG CODE
-    # console.log "PROPS [#{@props.mark.yUpper},#{@props.mark.yLower}]"
-    # console.log "INITIAL (STATE.X, STATE.Y): (#{Math.round @props.mark.x},#{Math.round @props.mark.y})"
     mark: @props.mark
-    centerX: @props.mark.x
-    centerY: @props.mark.y
-    markHeight: @props.defaultMarkHeight
+    markStatus: 'mark'
+    fillColor: @props.fillColor
+    strokeColor: @props.strokeColor
+    strokeWidth: @props.strokeWidth
+
+  getDefaultProps: ->
     fillColor: 'rgba(0,0,0,0.5)'
     strokeColor: 'rgba(0,0,0,0.5)'
     strokeWidth: 6
-    yUpper: @props.mark.yUpper
-    yLower: @props.mark.yLower
-    markHeight: @props.mark.yLower - @props.mark.yUpper
-    markStatus: 'mark'

   componentWillReceiveProps: ->
-    @setState
-      key: @props.mark.key
-      yUpper: @props.mark.yUpper
-      yLower: @props.mark.yLower
-      centerX: @props.mark.x
-      centerY: @props.mark.y
-      markHeight: @props.mark.yLower - @props.mark.yUpper
-
+    @setState mark: @props.mark
+
   onClickMarkButton: ->
     markStatus = @state.markStatus
     console.log 'markStatus is ', markStatus
@@ -79,9 +69,11 @@
     else
       markDragHandler = @props.handleDragMark

+    markHeight = @state.mark.yLower - @state.mark.yUpper
+
     <g
       className = "point drawing-tool"
-      transform = {"translate(#{Math.ceil @state.strokeWidth}, #{Math.round( @state.centerY - @state.markHeight/2 ) })"}
+      transform = {"translate(#{Math.ceil @state.strokeWidth}, #{Math.round( @state.mark.y - markHeight/2 ) })"}
       data-disabled = {@props.disabled || null}
       data-selected = {@props.selected || null}
     >
@@ -99,7 +91,7 @@
           y           = 0
           viewBox     = {"0 0 @props.imageWidth @props.imageHeight"}
           width       = {Math.ceil( @props.imageWidth - 2*@state.strokeWidth ) }
-          height      = {@state.markHeight}
+          height      = {markHeight}
           fill        = {if @props.selected then "rgba(255,102,0,0.25)" else "rgba(0,0,0,0.5)"}
           stroke      = {@state.strokeColor}
           strokeWidth = {@state.strokeWidth}
@@ -122,7 +114,7 @@
             <ResizeButton
               className = "lowerResize"
               handleResize = {@props.handleLowerResize}
-              transform = {"translate( #{@props.imageWidth/2}, #{ Math.round( @state.markHeight - @props.scrubberHeight/2 ) } )"}
+              transform = {"translate( #{@props.imageWidth/2}, #{ Math.round( markHeight - @props.scrubberHeight/2 ) } )"}
               scrubberHeight = {@props.scrubberHeight}
               scrubberWidth = {@props.scrubberWidth}
               workflow = {@props.workflow}
@@ -130,7 +122,7 @@
             />

             <DeleteButton
-              transform = "translate(50, #{Math.round @state.markHeight/2})"
+              transform = "translate(50, #{Math.round markHeight/2})"
               onClick = {@handleMarkDelete}
               workflow = {@props.workflow}
               isSelected = {@props.selected}
@@ -140,7 +132,7 @@
       <DoneCheckbox
         markStatus = {@state.markStatus}
         onClickMarkButton = {@onClickMarkButton}
-        transform = {"translate( #{@props.imageWidth-250}, #{ Math.round @state.markHeight/2 -@props.scrubberHeight/2 } )"}
+        transform = {"translate( #{@props.imageWidth-250}, #{ Math.round markHeight/2 -@props.scrubberHeight/2 } )"}
       />
     </g>


Moving to a switch

Moving to a switch

--- app/assets/javascripts/darkswarm/services/order.js.coffee
+++ app/assets/javascripts/darkswarm/services/order.js.coffee
@@ -7,31 +7,28 @@
       @order.shipping_method_id ||= parseInt(Object.keys(@order.shipping_methods)[0])

     navigate: (path)->
-      console.log path
       window.location.pathname = path

     submit: ->
       $http.put('/shop/checkout', {order: @preprocess()}).success (data, status)=>
         @navigate(data.path)
       .error (errors, status)=>
-        console.log "error"
         @errors = errors

-
-
     # Rails wants our Spree::Address data to be provided with _attributes
     preprocess: ->
       munged_order = {}
       for name, value of @order # Clone all data from the order JSON object
-        if name == "bill_address"
-          munged_order["bill_address_attributes"] = value
-        else if name == "ship_address"
-          munged_order["ship_address_attributes"] = value
-        else if name == "payment_method_id"
-          munged_order["payments_attributes"] = [{payment_method_id: value}]
-        else
-          munged_order[name] = value
-      # TODO: this
+        switch name
+          when "bill_address"
+            munged_order["bill_address_attributes"] = value
+          when "ship_address"
+            munged_order["ship_address_attributes"] = value
+          when "payment_method_id"
+            munged_order["payments_attributes"] = [{payment_method_id: value}]
+          else
+            munged_order[name] = value
+
       if munged_order.ship_address_same_as_billing
         munged_order.ship_address_attributes = munged_order.bill_address_attributes
       munged_order


fixed a bug with editable region and double clicking on images.

--- app/assets/javascripts/mercury/regions/editable.js.coffee
+++ app/assets/javascripts/mercury/regions/editable.js.coffee
@@ -119,7 +119,8 @@

     @element.dblclick (event) =>
       return if @previewing
-      if image = $(event.target).closest('img')
+      image = $(event.target).closest('img', @element)
+      if image.length
         @selection().selectNode(image.get(0), true)
         Mercury.trigger('button', {action: 'insertmedia'})


fix permission display for permissions that don't apply to role

test plan:
* teacher-only permissions (e.g. "Add/remove students")
should be shown as disabled for student roles

closes #CNVS-36025

Change-Id: Ic775d8bbc64559c7db0a8ef09dd92f24f192928b
Reviewed-on: https://gerrit.instructure.com/107102
Tested-by: Jenkins
Reviewed-by: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>
QA-Review: Heath Hales <8ca81b68c7e2592ac614bd07f22fcc735ca55f93@instructure.com>
Product-Review: James Williams  <3a5f4ed991dbfa5c9ef76ad729d240ca12f62180@instructure.com>

--- app/coffeescripts/views/roles/PermissionButtonView.coffee
+++ app/coffeescripts/views/roles/PermissionButtonView.coffee
@@ -283,7 +283,7 @@
     #
     # @api private
     isDefault: ->
-      !@isExplicit() && !@isLocked()
+      !@isExplicit()

     # Method Summary
     #   Read only attribute is set means you cannot change this permission.


Remove console log

Remove console log

--- assets/javascripts/controllers/index_controller.js.coffee
+++ assets/javascripts/controllers/index_controller.js.coffee
@@ -44,7 +44,6 @@
         messageParams.formattedBody = App.plugins.processMessageBody(formatted.body, formatted.type)

       msg = @store.createRecord("message", messageParams)
-      console.log "formatted body: ", msg.get("formattedBody")

       if room.get("messages.length") == (MogoChat.config.messagesPerLoad + 1)
         room.get("messages").shiftObject()


Connect GraphRenderer to range change events (#7371)

--- bokehjs/src/coffee/models/renderers/graph_renderer.coffee
+++ bokehjs/src/coffee/models/renderers/graph_renderer.coffee
@@ -30,6 +30,12 @@
     @connect(@model.edge_renderer.data_source.select, () -> @set_data())
     @connect(@model.edge_renderer.data_source.inspect, () -> @set_data())
     @connect(@model.edge_renderer.data_source.change, () -> @set_data())
+
+    for name, rng of @plot_model.frame.x_ranges
+      @connect(rng.change, () -> @set_data())
+
+    for name, rng of @plot_model.frame.y_ranges
+      @connect(rng.change, () -> @set_data())

   set_data: (request_render=true) ->
     # TODO (bev) this is a bit clunky, need to make sure glyphs use the correct ranges when they call


Add spec for creation and removal of overlay

--- spec/text-editor-component-spec.coffee
+++ spec/text-editor-component-spec.coffee
@@ -1196,6 +1196,28 @@
         expect(componentNode.querySelector('.test-highlight')).toBeFalsy()
         expect(componentNode.querySelector('.new-test-highlight')).toBeTruthy()

+  describe "overlay decoration rendering", ->
+    [marker, decoration, decorationParams, scrollViewClientLeft] = []
+    beforeEach ->
+      scrollViewClientLeft = componentNode.querySelector('.scroll-view').getBoundingClientRect().left
+
+    it "renders an overlay decoration when added and removes the overlay when the decoration is destroyed", ->
+      item = document.createElement('div')
+      item.classList.add 'my-overlay'
+
+      marker = editor.displayBuffer.markBufferRange([[2, 13], [2, 13]], invalidate: 'never')
+      decoration = editor.decorateMarker(marker, {type: 'overlay', item})
+      nextAnimationFrame()
+
+      overlay = component.getTopmostDOMNode().querySelector('atom-overlay .my-overlay')
+      expect(overlay).toBe item
+
+      decoration.destroy()
+      nextAnimationFrame()
+
+      overlay = component.getTopmostDOMNode().querySelector('atom-overlay .my-overlay')
+      expect(overlay).toBe null
+
   describe "hidden input field", ->
     it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", ->
       editor.setVerticalScrollMargin(0)


Decrease the timeout interval.

Decrease the timeout interval.

--- spec/text-editor-presenter-spec.coffee
+++ spec/text-editor-presenter-spec.coffee
@@ -92,14 +92,14 @@
     expectNoStateUpdate = (presenter, fn) -> expectStateUpdatedToBe(false, presenter, fn)

     waitsForStateToUpdate2 = (presenter, fn) ->
-      waitsFor "presenter state to update", 5000, (done) ->
+      waitsFor "presenter state to update", 1000, (done) ->
         disposable = presenter.onDidUpdateState ->
           disposable.dispose()
           process.nextTick(done)
         fn?()

     waitsForStateToUpdate = (presenter, fn) ->
-      waitsFor "presenter state to update", 5000, (done) ->
+      waitsFor "presenter state to update", 1000, (done) ->
         fn?()
         disposable = presenter.onDidUpdateState ->
           disposable.dispose()


Add a spec to verify gutter decorations are updated even if a higher priority gutter is hidden.

--- spec/text-editor-presenter-spec.coffee
+++ spec/text-editor-presenter-spec.coffee
@@ -2300,6 +2300,15 @@

             expect(decorationState[decoration3.id]).toBeUndefined()

+          it "updates when another gutter with higher priority is hidden", ->
+            editor.addGutter({name: 'test-gutter-1', priority: -150, visible: false})
+
+            # This update will scroll decoration1 out of view, and decoration3 into view.
+            expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5)
+
+            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
+            expect(decorationState[decoration1.id]).toBeUndefined()
+
           it "updates when ::scrollTop changes", ->
             # This update will scroll decoration1 out of view, and decoration3 into view.
             expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5)


Scripts: return empty object if instance data doesnt exist

--- scripts/node-testing/helper.coffee
+++ scripts/node-testing/helper.coffee
@@ -2,13 +2,12 @@

 getNthInstanceData = (instanceData, n) ->

+  instance = {}
+
   # getting nth test instance's id and public ip
-  instance = null
-
   nthInstanceData = fs.readFileSync(instanceData).toString().split("\n")[n]?.split(' ')

   if nthInstanceData
-    instance = {}
     [ instance.instanceId, instance.publicIpAddress ] = nthInstanceData

   return instance
@@ -16,7 +15,8 @@

 getNthInstancePublicIpAddress = (instanceData, n) ->

-  return getNthInstanceData(instanceData, n)?.publicIpAddress
+  # returns null if nth instance data doesn't exist
+  return getNthInstanceData(instanceData, n).publicIpAddress

 module.exports = {


fixes #61

fixes #61

--- keymaps/omnisharp-atom.cson
+++ keymaps/omnisharp-atom.cson
@@ -7,7 +7,7 @@
 #
 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
-'.workspace':
+'.atom-workspace':
   'esc': 'omnisharp-atom:hide'
   'ctrl-alt-o': 'omnisharp-atom:toggle'
   'ctrl-alt-x': 'omnisharp-atom:show-omni'


chore(cleanup): remove comments

chore(cleanup): remove comments

--- module/index.coffee
+++ module/index.coffee
@@ -71,27 +71,6 @@
 		@viewName       = path.join '/', moduleName, dasherized + '.html'
 		@viewPath       = path.join @directory, dasherized + '.html'

-		console.log 'VIEW NAME', @viewName
-		console.log 'VIEW PATH', @viewPath
-		console.log 'CLASS NAME', @className
-		console.log 'DASHERIZED', dasherized
-
-
-
-
-		# # @className      = _.str.classify normalized
-		# moduleName      = _.str.camelize normalized
-		# @controllerName = "#{moduleName}Controller"
-		# @serviceName    = "#{moduleName}service"
-		# directory       = "src/#{moduleName}"
-		# @routeName      = "/#{normalized }"
-		# @viewName       = "#{normalized }.html"
-		# @viewUrl        = "/#{moduleName}/#{@viewName}"
-		# @viewPath       = "#{directory}/#{@viewName}"
-		# @controllerPath = "#{directory}/#{moduleName}Controller.coffee"
-		# @servicePath    = "#{directory}/#{moduleName}Service.coffee"
-		# @routesPath     = "#{directory}/#{moduleName}Routes.coffee"
-
 	scaffold: ->
 		@log '\n', chalk.magenta 'Tree:'
 		@mkdir @directory


Consolidating code.

Consolidating code.

--- client/coffeescript/templates/tagbox.coffee
+++ client/coffeescript/templates/tagbox.coffee
@@ -61,16 +61,12 @@
             Template.tagbox.add_tag(@_id, @tags, [], entered_text, event.target)
           when 37 #Left-arrow: ADD SUGGESTED TAG
             if event.ctrlKey && suggested_tag?
-              @tags[suggested_tag] ?= { users: [], weight: 0}
-              @tags[suggested_tag].users.push(Session.get('user_id'))
-              Posts.update(@_id, {$set: {tags: @tags}})
-              Session.get("suggestions_#{ @_id }").remove(suggested_tag)
-              Session.get("context_#{@_id}").invalidate()
+              Template.tagbox.add_tag(@_id, @tags, [], suggested_tag, event.target)
           when 39 #Right-arrow: REMOVE SUGGESTED TAG
             if event.ctrlKey
               Session.get("suggestions_#{ @_id }").remove(suggested_tag)
               Session.get("context_#{@_id}").invalidate()
-          else    #Update suggestions with new text
+          else    #Update filter with new text
             Session.set("filter_text_#{ @_id }", entered_text)
             Session.get("context_#{@_id}").invalidate()


IDEView: Don't remove pane when untitled file removed automatically.

--- client/ide/lib/views/tabview/ideview.coffee
+++ client/ide/lib/views/tabview/ideview.coffee
@@ -113,40 +113,37 @@
           tabHandle.makeEditable()

-    @tabView.on 'PaneRemoved', ({ pane, handle }) =>
-
-      { frontApp } = kd.singletons.appManager
-
+    @tabView.on 'PaneRemoved', ({ pane, handle }) ->
       { options : { paneType } } = pane.view
       handle.off 'RenamingRequested'  if paneType is 'terminal'

-      @handleCloseSplitView handle  if frontApp.fakeViewsDestroyed
-

     # This is a custom event for IDEApplicationTabView
     # to distinguish between user actions and programmed actions
-    @tabView.on 'PaneRemovedByUserAction', (pane)=>
-      {view} = pane
+    @tabView.on 'PaneRemovedByUserAction', (pane) =>
+      { view } = pane
+
       if view instanceof IDETerminalPane
         sessionId = view.session or view.webtermView.sessionId
         @terminateSession @mountedMachine, sessionId

+      @handleCloseSplitView pane.tabHandle
+

   handleCloseSplitView: (handle) ->

-    { frontApp } = kd.singletons.appManager
-    appStorage   = kd.getSingleton('appStorageController').storage 'Ace', '1.0.1'
-    paneLength   = handle.getDelegate().panes.length
-
-    if not paneLength and not frontApp.targetTabView
-
-      appStorage.ready =>
-
-        if not appStorage.getValue 'IsAutoRemovePaneSuggested'
-          appStorage.setValue 'IsAutoRemovePaneSuggested', yes
-          return @showSuggestAutoRemovePaneModal()
-
-        @closeSplitView()  if appStorage.getValue 'enableAutoRemovePane'
+    appStorage = kd.getSingleton('appStorageController').storage 'Ace', '1.0.1'
+    paneLength = handle.getDelegate().panes.length
+
+    return if paneLength > 1 # remove pane when there is only one pane left
+
+    appStorage.ready =>
+
+      if not appStorage.getValue 'IsAutoRemovePaneSuggested'
+        appStorage.setValue 'IsAutoRemovePaneSuggested', yes
+        return @showSuggestAutoRemovePaneModal()
+
+      @closeSplitView()  if appStorage.getValue 'enableAutoRemovePane'

   showSuggestAutoRemovePaneModal: ->


StatusBar: Fixed typo.

StatusBar: Fixed typo.

--- client/ide/views/statusbar/statusbar.coffee
+++ client/ide/views/statusbar/statusbar.coffee
@@ -20,4 +20,4 @@

   empty: ->
     @menuButton.hide()
-    @status.updatePartial 'Click the plus button button above to create a new panel'
+    @status.updatePartial 'Click the plus button above to create a new panel'


pass along our request options

pass along our request options

--- client/skr/screens/locations/Locations.cjsx
+++ client/skr/screens/locations/Locations.cjsx
@@ -18,6 +18,7 @@
             <SC.ScreenControls commands={@state.commands} />
             <BS.Row>
                 <SC.LocationChooser label='Code' editOnly displayFinder
+                    syncOptions={@syncOptions}
                     commands={@state.commands} model={@location} name="code" />
                 <LC.Input sm=6 name='name' model={@location} />
             </BS.Row>


stack-editor: work with new design

stack-editor: work with new design

--- client/stack-editor/lib/editor/index.coffee
+++ client/stack-editor/lib/editor/index.coffee
@@ -22,6 +22,7 @@
 parseTerraformOutput = require 'stacks/views/stacks/parseterraformoutput'
 CredentialStatusView = require 'stacks/views/stacks/credentialstatusview'
 StackTemplatePreviewModal = require 'stacks/views/stacks/stacktemplatepreviewmodal'
+EnvironmentFlux = require 'app/flux/environment'

 module.exports = class StackEditorView extends kd.View
@@ -201,6 +202,10 @@
       cssClass     : 'template-title'
       autogrow     : yes
       defaultValue : stackTemplate?.title or 'Default stack template' # can we auto generate cute stack names?
+      bind: 'keyup'
+      keyup: (e) ->
+        { changeTemplateTitle } = EnvironmentFlux.actions
+        changeTemplateTitle stackTemplate?._id, e.target.value

   createOutputView: ->


Fix Help

Fix Help

--- modules/help.coffee
+++ modules/help.coffee
@@ -20,7 +20,7 @@
     #{@prefix}play    <link/title> - Plays the requested song
     #{@prefix}queue                - Shows the current song queue
     #{@prefix}skip                 - Vote to skip the current song
-                                (Bot commanders bypass voting)
+                          (Bot commanders bypass voting)
     #{@prefix}undo                 - Removes the most recent item added to the queue
     #{@prefix}np                   - Now Playing
     #{@prefix}help                 - Shows this help
@@ -30,6 +30,7 @@

     Bot Commanders Only:
     #{@prefix}volume  <vol>        - Sets volume of the bot
+    #{@prefix}shuffle              - Shuffles the queue
     #{@prefix}pause                - Pauses playback
     #{@prefix}resume               - Resumes playback
     #{@prefix}stop                 - Stops playback an clears the queue


TextInput now gives back focus when it is removed from the tree

--- src/art/engine/forms/text_input.coffee
+++ src/art/engine/forms/text_input.coffee
@@ -67,8 +67,12 @@
       focus: => @domElement.focus()
       blur:  => @domElement.blur()
       keyPress: ({props}) =>
-        if props.key == "Enter"
-          @handleEvent "enter", value:@value
+        @handleEvent "enter", value:@value if props.key == "Enter"
+        @handleEvent "escape", value:@value if props.key == "Escape"
+
+  _unregister: ->
+    @_canvasElementToFocusOnBlur?.focusCanvas()
+    super

   checkIfValueChanged: ->
     if @lastValue != @value


remove errant log statement

remove errant log statement

--- src/browser/auto-update-manager.coffee
+++ src/browser/auto-update-manager.coffee
@@ -106,7 +106,6 @@
       @checkForUpdatesIntervalID = null

   check: ({hidePopups}={}) ->
-    console.log 'checking for update'
     unless hidePopups
       autoUpdater.once 'update-not-available', @onUpdateNotAvailable
       autoUpdater.once 'error', @onUpdateError


fix touch emulator centerpoint

fix touch emulator centerpoint

--- framer/Extras/TouchEmulator.coffee
+++ framer/Extras/TouchEmulator.coffee
@@ -5,12 +5,12 @@
 	return touch =
 		identifier: identifier
 		target: event.target
-		pageX: event.pageX + offset.x
-		pageY: event.pageY + offset.y
-		clientX: event.clientX + offset.x
-		clientY: event.clientY + offset.y
-		screenX: event.screenX + offset.x
-		screenY: event.screenY + offset.y
+		pageX: event.pageX - offset.x
+		pageY: event.pageY - offset.y
+		clientX: event.clientX - offset.x
+		clientY: event.clientY - offset.y
+		screenX: event.screenX - offset.x
+		screenY: event.screenY - offset.y

 dispatchTouchEvent = (type, target, event, offset) ->


Use only the file name as the tab name

Use only the file name as the tab name

--- src/components/Specimen/Project.coffee
+++ src/components/Specimen/Project.coffee
@@ -50,10 +50,11 @@
     div {},
       if @props.files.length > 1
         @props.files.map (file, i) =>
+          [path..., name] = file.split('/')
           button
             'data-tab-id': i
             onClick: @selectTab
-            file
+            name

       textarea
         className: 'cg-SpecimenProject-source'


update cc popover accessibility id

update cc popover accessibility id

--- src/components/scores/concept-coach-cell.cjsx
+++ src/components/scores/concept-coach-cell.cjsx
@@ -16,7 +16,7 @@
     pieValue =
       Math.round((@props.task.completed_exercise_count / @props.task.exercise_count) * 100)
     tooltip =
-      <BS.Popover id="cc-cell-info-popover-#{@props.task.id}">
+      <BS.Popover id="cc-cell-info-popover-#{@props.task.id}" className='cc-scores-tooltip-completed-info'>
         <div>
           <BS.Table>
             <thead>


reload proxy settings before server started

--- config/bootstrap.coffee
+++ config/bootstrap.coffee
@@ -5,4 +5,6 @@
 module.exports =
   bootstrap: (done) ->
     sails.io.of require('url').parse(process.env.ROOTURL).pathname
-    done()
+    sails.models.upstream.reload()
+      .then done
+      .catch done


feat(salesforce): Sync Salesforce templates to files in the template folder

Summary:
Add Salesforce analytics

template fixes

fix opportunity updating

Test Plan: edgehill --test

Reviewers: bengotow

Reviewed By: bengotow

Differential Revision: https://review.inboxapp.com/D1483

--- src/flux/stores/analytics-store.coffee
+++ src/flux/stores/analytics-store.coffee
@@ -8,11 +8,31 @@
 module.exports =
 AnalyticsStore = Reflux.createStore
   init: ->
+    @listenAndTrack = (dispatcher=Actions) => (callback, action) =>
+      @listenTo dispatcher[action], (args...) =>
+        @track(action, callback(args...))
+
     @analytics = Mixpanel.init("625e2300ef07cb4eb70a69b3638ca579")
     @listenTo NamespaceStore, => @identify()
     @identify()

-    @_listenToActions()
+    @_listenToCoreActions()
+
+    @_setupGlobalPackageActions()
+
+  addPackageActions: (listeners, dispatcher=Actions) ->
+    _.each listeners, @listenAndTrack(dispatcher)
+
+  addGlobalPackageActions: (listeners) ->
+    @_globalPackageActions = _.extend @_globalPackageActions, listeners
+
+  _setupGlobalPackageActions: ->
+    @_globalPackageActions = {}
+    @listenTo Actions.sendToAllWindows, (actionData={}) =>
+      return unless atom.isMainWindow()
+      callback = @_globalPackageActions[actionData.action]
+      if callback?
+        @track(actionData.action, callback(actionData))

   # We white list actions to track.
   #
@@ -25,12 +45,7 @@
   #
   # Only completely anonymous data essential to future metrics or
   # debugging may be sent.
-  actionsToTrack: ->
-    logout: -> {}
-    fileAborted: (uploadData={}) -> {fileSize: uploadData.fileSize}
-    fileUploaded: (uploadData={}) -> {fileSize: uploadData.fileSize}
-    sendDraftError: (dId, msg) -> {drafLocalId: dId, error: msg}
-    sendDraftSuccess: ({draftLocalId}) -> {draftLocalId: draftLocalId}
+  coreWindowActions: ->
     showDeveloperConsole: -> {}
     composeReply: ({threadId, messageId}) -> {threadId, messageId}
     composeForward: ({threadId, messageId}) -> {threadId, messageId}
@@ -45,6 +60,13 @@
     abortDownload: -> {}
     fileDownloaded: -> {}

+  coreGlobalActions: ->
+    logout: -> {}
+    fileAborted: (uploadData={}) -> {fileSize: uploadData.fileSize}
+    fileUploaded: (uploadData={}) -> {fileSize: uploadData.fileSize}
+    sendDraftError: (dId, msg) -> {drafLocalId: dId, error: msg}
+    sendDraftSuccess: ({draftLocalId}) -> {draftLocalId: draftLocalId}
+
   track: (action, data={}) ->
     @analytics.track(action, _.extend(data, namespaceId: NamespaceStore.current()?.id))

@@ -58,7 +80,6 @@
         "$last_name": namespace.me().lastName()
         "namespaceId": namespace.id

-  _listenToActions: ->
-    _.each @actionsToTrack(), (callback, action) =>
-      @listenTo Actions[action], (args...) =>
-        @track(action, callback(args...))
+  _listenToCoreActions: ->
+    _.each @coreWindowActions(), @listenAndTrack()
+    _.each @coreGlobalActions(), @listenAndTrack() if atom.isMainWindow()


minor: comment, remove useless line

minor: comment, remove useless line

--- src/core/triangle_group_representation.coffee
+++ src/core/triangle_group_representation.coffee
@@ -66,9 +66,10 @@
     @aPowers = M.powers @a, n
     @bPowers = M.powers @b, m

+    #Points, that are invariant under generator action. Rotation centers.
     @centerA = [0.0,0.0,1.0]
     @centerB = [@sinh_r, 0.0, @cosh_r]
-    @centerAB = [@sinh_x*Math.cos(alpha), @sinh_x*Math.sin(alpha), @cosh_x ]
+    @centerAB = [@sinh_x*cos(alpha), @sinh_x*sin(alpha), @cosh_x ]

   aPower: (i) -> @aPowers[ mod i, @n ]
   bPower: (i) -> @bPowers[ mod i, @m ]


hub/prom: be less specific for http timings, only endpoints are of interest

--- src/smc-hub/hub_http_server.coffee
+++ src/smc-hub/hub_http_server.coffee
@@ -82,7 +82,7 @@
                              )
     response_time_histogram = MetricsRecorder.new_histogram('http_histogram', 'http server'
                                   buckets : [0.0001, 0.0005, 0.001, 0.002, 0.005, 0.01, 0.1, 0.5, 1, 5, 10]
-                                  labels: ['method', 'code']
+                                  labels: ['path', 'method', 'code']
                               )

     router.use (req, res, next) ->
@@ -91,10 +91,10 @@
         original_end = res.end
         res.end = ->
             original_end.apply(res, arguments)
-            # we're only interested in the first part
-            path = req.path.split('/')[1] # for two levels: split('/')[1..2].join('/')
-            res_finished_q({path:path, method:req.method, code:res.statusCode})
-            res_finished_h({method:req.method, code:res.statusCode})
+            {dirname} = require('path')
+            dir_path = dirname(req.path).split('/')[1] # for two levels: split('/')[1..2].join('/')
+            res_finished_q({path:dir_path, method:req.method, code:res.statusCode})
+            res_finished_h({path:dir_path, method:req.method, code:res.statusCode})
         next()

     app.enable('trust proxy') # see http://stackoverflow.com/questions/10849687/express-js-how-to-get-remote-client-address


Runner: Refactor instantiation of provided functions

--- src/main/runtime/ReactiveRunner.coffee
+++ src/main/runtime/ReactiveRunner.coffee
@@ -54,13 +54,11 @@

   _instantiateProvidedFunctionStream: (func, argExprs) ->
     argStreams = (@_instantiateExprStream(a) for a in argExprs)
-    result = if func.kind == STREAM
-               func.call null, argStreams
-             else
-                if argStreams.length
-                  Rx.Observable.combineLatest argStreams, func
-                else
-                  new Rx.BehaviorSubject func()
+    result = switch func.kind
+              when STREAM then func.call null, argStreams
+              when VALUE
+                if argStreams.length then Rx.Observable.combineLatest argStreams, func
+                else new Rx.BehaviorSubject func()
     result

   _instantiateExprStream: (expr) ->


Organize HTMLParser

Organize HTMLParser

--- src/trix/models/html_parser.coffee
+++ src/trix/models/html_parser.coffee
@@ -16,6 +16,8 @@

   getDocument: ->
     Trix.Document.fromJSON(@blocks)
+
+  # HTML parsing

   parse: ->
     try
@@ -28,12 +30,6 @@
     finally
       @removeHiddenContainer()

-  nodeFilter = (node) ->
-    if tagName(node) is "style"
-      NodeFilter.FILTER_REJECT
-    else
-      NodeFilter.FILTER_ACCEPT
-
   createHiddenContainer: ->
     if @referenceElement
       @containerElement = @referenceElement.cloneNode(false)
@@ -47,6 +43,41 @@

   removeHiddenContainer: ->
     @containerElement.parentNode.removeChild(@containerElement)
+
+  sanitizeHTML = (html) ->
+    doc = document.implementation.createHTMLDocument("")
+    doc.documentElement.innerHTML = html
+    {body, head} = doc
+
+    for style in head.querySelectorAll("style")
+      body.appendChild(style)
+
+    nodesToRemove = []
+    walker = walkTree(body)
+
+    while walker.nextNode()
+      node = walker.currentNode
+      switch node.nodeType
+        when Node.ELEMENT_NODE
+          if tagName(node) is "script"
+            nodesToRemove.push(node)
+          else
+            for {name} in [node.attributes...]
+              unless name in allowedAttributes or name.indexOf("data-trix") is 0
+                node.removeAttribute(name)
+        when Node.COMMENT_NODE
+          nodesToRemove.push(node)
+
+    for node in nodesToRemove
+      node.parentNode.removeChild(node)
+
+    body.innerHTML
+
+  nodeFilter = (node) ->
+    if tagName(node) is "style"
+      NodeFilter.FILTER_REJECT
+    else
+      NodeFilter.FILTER_ACCEPT

   processNode: (node) ->
     switch node.nodeType
@@ -120,6 +151,8 @@
           unless element.parentNode.firstChild is element
             @appendStringWithAttributes(" | ")

+  # Document construction
+
   appendBlockForAttributesWithElement: (attributes, element) ->
     @blockElements.push(element)
     block = blockForAttributes(attributes)
@@ -157,6 +190,21 @@
       piece.string = string + piece.string
     else
       text.unshift(pieceForString(string))
+
+  pieceForString = (string, attributes = {}) ->
+    type = "string"
+    string = normalizeSpaces(string)
+    {string, attributes, type}
+
+  pieceForAttachment = (attachment, attributes = {}) ->
+    type = "attachment"
+    {attachment, attributes, type}
+
+  blockForAttributes = (attributes = {}) ->
+    text = []
+    {text, attributes}
+
+  # Attribute parsing

   getTextAttributes: (element) ->
     attributes = {}
@@ -199,102 +247,8 @@
       element = element.parentNode
     ancestors

-  getMarginOfBlockElementAtIndex: (index) ->
-    if element = @blockElements[index]
-      unless tagName(element) in getBlockTagNames() or element in @processedElements
-        getBlockElementMargin(element)
-
-  getMarginOfDefaultBlockElement: ->
-    element = makeElement(Trix.config.blockAttributes.default.tagName)
-    @containerElement.appendChild(element)
-    getBlockElementMargin(element)
-
-  translateBlockElementMarginsToNewlines: ->
-    defaultMargin = @getMarginOfDefaultBlockElement()
-
-    for block, index in @blocks when margin = @getMarginOfBlockElementAtIndex(index)
-      if margin.top > defaultMargin.top * 2
-        @prependStringToTextAtIndex("\n", index)
-
-      if margin.bottom > defaultMargin.bottom * 2
-        @appendStringToTextAtIndex("\n", index)
-
-  pieceForString = (string, attributes = {}) ->
-    type = "string"
-    string = normalizeSpaces(string)
-    {string, attributes, type}
-
-  pieceForAttachment = (attachment, attributes = {}) ->
-    type = "attachment"
-    {attachment, attributes, type}
-
-  blockForAttributes = (attributes = {}) ->
-    text = []
-    {text, attributes}
-
   getAttachmentAttributes = (element) ->
     JSON.parse(element.dataset.trixAttachment)
-
-  sanitizeHTML = (html) ->
-    doc = document.implementation.createHTMLDocument("")
-    doc.documentElement.innerHTML = html
-    {body, head} = doc
-
-    for style in head.querySelectorAll("style")
-      body.appendChild(style)
-
-    nodesToRemove = []
-    walker = walkTree(body)
-
-    while walker.nextNode()
-      node = walker.currentNode
-      switch node.nodeType
-        when Node.ELEMENT_NODE
-          if tagName(node) is "script"
-            nodesToRemove.push(node)
-          else
-            for {name} in [node.attributes...]
-              unless name in allowedAttributes or name.indexOf("data-trix") is 0
-                node.removeAttribute(name)
-        when Node.COMMENT_NODE
-          nodesToRemove.push(node)
-
-    for node in nodesToRemove
-      node.parentNode.removeChild(node)
-
-    body.innerHTML
-
-  squishWhitespace = (string) ->
-    string
-      # Replace all breaking whitespace characters with a space
-      .replace(///[^\S#{Trix.NON_BREAKING_SPACE}]///g, " ")
-      # Replace two or more spaces with a single space
-      .replace(/\ {2,}/g, " ")
-
-  isBlockElement = (element) ->
-    return unless element?.nodeType is Node.ELEMENT_NODE
-    return if findClosestElementFromNode(element, matchingSelector: "td")
-    tagName(element) in getBlockTagNames() or window.getComputedStyle(element).display is "block"
-
-  isInsignificantTextNode = (node) ->
-    return unless node?.nodeType is Node.TEXT_NODE
-    return if /\S/.test(node.data)
-    return if elementCanDisplayPreformattedText(node.parentNode)
-    not node.previousSibling or isBlockElement(node.previousSibling) or not node.nextSibling or isBlockElement(node.nextSibling)
-
-  isExtraBR = (element) ->
-    tagName(element) is "br" and
-      isBlockElement(element.parentNode) and
-      element.parentNode.lastChild is element
-
-  elementCanDisplayPreformattedText = (element) ->
-    {whiteSpace} = window.getComputedStyle(element)
-    whiteSpace in ["pre", "pre-wrap", "pre-line"]
-
-  getBlockElementMargin = (element) ->
-    style = window.getComputedStyle(element)
-    if style.display is "block"
-      top: parseInt(style.marginTop), bottom: parseInt(style.marginBottom)

   getImageDimensions = (element) ->
     width = element.getAttribute("width")
@@ -303,3 +257,61 @@
     dimensions.width = parseInt(width, 10) if width
     dimensions.height = parseInt(height, 10) if height
     dimensions
+
+  # Element inspection
+
+  isBlockElement = (element) ->
+    return unless element?.nodeType is Node.ELEMENT_NODE
+    return if findClosestElementFromNode(element, matchingSelector: "td")
+    tagName(element) in getBlockTagNames() or window.getComputedStyle(element).display is "block"
+
+  isInsignificantTextNode = (node) ->
+    return unless node?.nodeType is Node.TEXT_NODE
+    return if /\S/.test(node.data)
+    return if elementCanDisplayPreformattedText(node.parentNode)
+    not node.previousSibling or isBlockElement(node.previousSibling) or not node.nextSibling or isBlockElement(node.nextSibling)
+
+  isExtraBR = (element) ->
+    tagName(element) is "br" and
+      isBlockElement(element.parentNode) and
+      element.parentNode.lastChild is element
+
+  elementCanDisplayPreformattedText = (element) ->
+    {whiteSpace} = window.getComputedStyle(element)
+    whiteSpace in ["pre", "pre-wrap", "pre-line"]
+
+  # Margin translation
+
+  translateBlockElementMarginsToNewlines: ->
+    defaultMargin = @getMarginOfDefaultBlockElement()
+
+    for block, index in @blocks when margin = @getMarginOfBlockElementAtIndex(index)
+      if margin.top > defaultMargin.top * 2
+        @prependStringToTextAtIndex("\n", index)
+
+      if margin.bottom > defaultMargin.bottom * 2
+        @appendStringToTextAtIndex("\n", index)
+
+  getMarginOfBlockElementAtIndex: (index) ->
+    if element = @blockElements[index]
+      unless tagName(element) in getBlockTagNames() or element in @processedElements
+        getBlockElementMargin(element)
+
+  getMarginOfDefaultBlockElement: ->
+    element = makeElement(Trix.config.blockAttributes.default.tagName)
+    @containerElement.appendChild(element)
+    getBlockElementMargin(element)
+
+  getBlockElementMargin = (element) ->
+    style = window.getComputedStyle(element)
+    if style.display is "block"
+      top: parseInt(style.marginTop), bottom: parseInt(style.marginBottom)
+
+  # Helpers
+
+  squishWhitespace = (string) ->
+    string
+      # Replace all breaking whitespace characters with a space
+      .replace(///[^\S#{Trix.NON_BREAKING_SPACE}]///g, " ")
+      # Replace two or more spaces with a single space
+      .replace(/\ {2,}/g, " ")


修复时间下拉款bug

修复时间下拉款bug

--- src/widget/edit/date-picker.coffee
+++ src/widget/edit/date-picker.coffee
@@ -489,7 +489,14 @@
 		@get("actionButton")?.set("disabled", @_finalReadOnly)
 		$inputDom.prop("type", "text").css("text-align", "left")
 		@_refreshInputValue(@_value)
-		return
+
+		return
+	_initDom:(dom)->
+		super(dom)
+		$inputDom = $fly(@_doms.input)
+		$inputDom.on("blur",()=>
+			@_postInput()
+		)

 	open: ()->
 		if super()
@@ -991,7 +998,7 @@
 						type: "number",
 						contextKey: "hour",
 						max: 23,
-						min: 0
+						min: "0"
 					}
 				}
 				{
@@ -1005,7 +1012,7 @@
 						type: "number",
 						contextKey: "minute",
 						max: 59,
-						min: 0
+						min: "0"
 					}
 				}
 				{
@@ -1019,7 +1026,7 @@
 						type: "number",
 						contextKey: "second",
 						max: 59,
-						min: 0
+						min: "0"
 					}
 				}
 			]


Retira closure desnecessário

Retira closure desnecessário

--- src/coffee/portal-totalizers.coffee
+++ src/coffee/portal-totalizers.coffee
@@ -1,120 +1,118 @@
-(($, window, document) ->
+$ = window.jQuery

-  pluginName = 'vtexTotalizers'
-  defaults = {
-    $template: null
-  }
+pluginName = 'vtexTotalizers'
+defaults = {
+	$template: null
+}

-  class vtexTotalizers
-    constructor: (@element, options) ->
-      @options = $.extend {}, defaults, options
+class vtexTotalizers
+	constructor: (@element, options) ->
+		@options = $.extend {}, defaults, options

-      @_defaults = defaults
-      @_name = pluginName
+		@_defaults = defaults
+		@_name = pluginName

-      @init()
+		@init()

-    init: ->
-      self = this
+	init: ->
+		self = this

-      self.options.$template = $ """
-

-

-          Resumo do Carrinho
-

-

-              Total de Produtos: 0
-

-

-              Itens: 0
-

-

-              Total de Kits: 0
-

-

-              Valor Total: R$ 0,00
-

-

-

-

-      """
+		self.options.$template = $ """
+

+

+				Resumo do Carrinho
+

+

+						Total de Produtos: 0
+

+

+						Itens: 0
+

+

+						Total de Kits: 0
+

+

+						Valor Total: R$ 0,00
+

+

+

+

+		"""

-      $(self.element).after self.options.$template
+		$(self.element).after self.options.$template

-      self.selectors = {
-        amountProducts: $('.amount-products-em', self.options.$template)
-        amountItems: $('.amount-items-em', self.options.$template)
-        totalCart: $('.total-cart-em', self.options.$template)
-      }
+		self.selectors = {
+			amountProducts: $('.amount-products-em', self.options.$template)
+			amountItems: $('.amount-items-em', self.options.$template)
+			totalCart: $('.total-cart-em', self.options.$template)
+		}

-      self.getCartData()
+		self.getCartData()

-      $(window).on 'cartUpdated', (event, cartData) ->
-        if (cartData)
-          self.setCartData(cartData)
-        else
-          self.getCartData()
+		$(window).on 'cartUpdated', (event, cartData) ->
+			if (cartData)
+				self.setCartData(cartData)
+			else
+				self.getCartData()

-      $('.amount-items-in-cart, .show-minicart-on-hover').mouseover ->
-        $(window).trigger 'miniCartMouseOver'
+		$('.amount-items-in-cart, .show-minicart-on-hover').mouseover ->
+			$(window).trigger 'miniCartMouseOver'

-      $('.amount-items-in-cart, .show-minicart-on-hover').mouseout ->
-        $(window).trigger 'miniCartMouseOut'
+		$('.amount-items-in-cart, .show-minicart-on-hover').mouseout ->
+			$(window).trigger 'miniCartMouseOut'

-    formatCurrency: (value) ->
-      if value is '' or not value? or isNaN value
-        num = 0.00
-      else
-        num = value / 100
-      parseFloat(num).toFixed(2).replace('.', ',').toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.')
+	formatCurrency: (value) ->
+		if value is '' or not value? or isNaN value
+			num = 0.00
+		else
+			num = value / 100
+		parseFloat(num).toFixed(2).replace('.', ',').toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.')

-    getCartData: ->
-      self = this
+	getCartData: ->
+		self = this

-      $(self.options.$template).addClass 'amount-items-in-cart-loading'
+		$(self.options.$template).addClass 'amount-items-in-cart-loading'

-      promise = $.ajax {
-        url: '/api/checkout/pub/orderForm/'
-        data: JSON.stringify {"expectedOrderFormSections": ["items", "paymentData", "totalizers"]}
-        dataType: 'json'
-        contentType: 'application/json; charset=utf-8'
-        type: 'POST'
-      }
+		promise = $.ajax {
+			url: '/api/checkout/pub/orderForm/'
+			data: JSON.stringify {"expectedOrderFormSections": ["items", "paymentData", "totalizers"]}
+			dataType: 'json'
+			contentType: 'application/json; charset=utf-8'
+			type: 'POST'
+		}

-      promise.done (data) ->
-        $(self.options.$template).removeClass 'amount-items-in-cart-loading'
+		promise.done (data) ->
+			$(self.options.$template).removeClass 'amount-items-in-cart-loading'

-      promise.success (data) ->
-        self.setCartData data
+		promise.success (data) ->
+			self.setCartData data

-      promise.fail (jqXHR, textStatus, errorThrown) ->
-        # console.log 'Error Message: ' + textStatus;
-        # console.log 'HTTP Error: ' + errorThrown;
+		promise.fail (jqXHR, textStatus, errorThrown) ->
+			# console.log 'Error Message: ' + textStatus;
+			# console.log 'HTTP Error: ' + errorThrown;

-      promise
+		promise

-    setCartData: (data) ->
-      self = this
+	setCartData: (data) ->
+		self = this

-      amountProducts = data.items.length
-      amountItems = 0;
-      amountItems += item.quantity for item in data.items
+		amountProducts = data.items.length
+		amountItems = 0;
+		amountItems += item.quantity for item in data.items

-      total = 0
-      for subtotal in data.totalizers
-        total += subtotal.value if subtotal.id is 'Items'
-      totalCart = self.formatCurrency(total)
+		total = 0
+		for subtotal in data.totalizers
+			total += subtotal.value if subtotal.id is 'Items'
+		totalCart = self.formatCurrency(total)

-      self.selectors.amountProducts.html amountProducts
-      self.selectors.amountItems.html amountItems
-      self.selectors.totalCart.html totalCart
+		self.selectors.amountProducts.html amountProducts
+		self.selectors.amountItems.html amountItems
+		self.selectors.totalCart.html totalCart

-    $.fn[pluginName] = (options) ->
-      @each ->
-        if !$.data(this, "plugin_#{pluginName}")
-          $.data(@, "plugin_#{pluginName}", new vtexTotalizers(@, options))
-
-)( jQuery, window, document )
+	$.fn[pluginName] = (options) ->
+		@each ->
+			if !$.data(this, "plugin_#{pluginName}")
+				$.data(@, "plugin_#{pluginName}", new vtexTotalizers(@, options))

 $ -> $('.portal-totalizers-ref').vtexTotalizers()
 # $ -> $('.carrinhoCompras a').vtexTotalizers()


:bug: Don't .split, .match already does this

--- src/markov.coffee
+++ src/markov.coffee
@@ -92,8 +92,8 @@

     # Chance to randomly respond un-prompted
     if pct > 0 and Math.random() < pct
-      words = msg.message.text.match /\s*\w+\s*/g
-      seeds = words.split /\s+/
+      words = msg.message.text.match /(?=\s*)\w+(?=\s*)/g
+      # seeds = words.split /\s+/
       randword = Math.floor(Math.random() * seeds.length)
       seed = seeds[randword]
       model.generate seed[0] or '', max, (text) =>


Fixed minor typo

Fixed minor typo

--- menus/git-plus.cson
+++ menus/git-plus.cson
@@ -34,7 +34,7 @@
           'command': 'git-plus:diff-branches'
         },
         {
-          'label': 'Diff Branche Files'
+          'label': 'Diff Branch Files'
           'command': 'git-plus:diff-branch-files'
         },
         {


[grunt] use `smartPlurals` in proper way

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -380,8 +380,7 @@
            * @return {string} Correct plural form
           ###
           env.addFilter 'plural', (count, forms, locale = currentLocale) ->
-            smartPlurals.Plurals.getRule(locale)
-            smartPlurals(count, forms)
+            smartPlurals.Plurals.getRule(locale)(count, forms)

           ###*
            * Format number based on given pattern


[grunt] use proper name for gettext class

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -62,7 +62,7 @@
     failureOutput : taskConfig.urlify.failureOutput
   })

-  i18n          = taskConfig.i18n.gettext
+  gettext       = taskConfig.i18n.gettext

   locales       = _.map(taskConfig.i18n.locales, 'locale')
   baseLocale    = taskConfig.i18n.baseLocale
@@ -353,7 +353,7 @@
           * @return {string} Translated string into current locale
           ###
           env.addGlobal 'gettext', (string) ->
-            i18n.dgettext(currentLocale, string)
+            gettext.dgettext(currentLocale, string)

           ###*
            * Load string from specified domain
@@ -365,7 +365,7 @@
           ###
           env.addGlobal 'dgettext', (domain = currentLocale, string) ->
             domain = if domain.charAt(0) == ':' then currentLocale + domain else domain
-            i18n.dgettext(domain, string)
+            gettext.dgettext(domain, string)

           ###*
           * Load plural string from current locale
@@ -375,7 +375,7 @@
           * @return {string} Pluralized and translated into current locale string
           ###
           env.addGlobal 'ngettext', (string, pluralString, count) ->
-            i18n.dngettext(currentLocale, string, pluralString, count)
+            gettext.dngettext(currentLocale, string, pluralString, count)

           ###*
            * Load plural string from specified domain
@@ -389,7 +389,7 @@
           ###
           env.addGlobal 'dngettext', (domain = currentLocale, string, pluralString, count) ->
             domain = if domain.charAt(0) == ':' then currentLocale + domain else domain
-            i18n.dngettext(domain, string, pluralString, count)
+            gettext.dngettext(domain, string, pluralString, count)

           ###*
           * Load string of specific context from current locale
@@ -398,7 +398,7 @@
           * @return {string} Translated string into current locale
           ###
           env.addGlobal 'pgettext', (context, string) ->
-            i18n.dpgettext(currentLocale, context, string)
+            gettext.dpgettext(currentLocale, context, string)

           ###*
            * Load string of specific context from specified domain
@@ -411,7 +411,7 @@
           ###
           env.addGlobal 'dpgettext', (domain = currentLocale, context, string) ->
             domain = if domain.charAt(0) == ':' then currentLocale + domain else domain
-            i18n.dpgettext(domain, context, string)
+            gettext.dpgettext(domain, context, string)

           ###*
           * Load plural string of specific context from current locale
@@ -422,7 +422,7 @@
           * @return {string} Pluralized and translated into current locale string
           ###
           env.addGlobal 'npgettext', (context, string, pluralString, count) ->
-            i18n.dnpgettext(currentLocale, context, string, pluralString, count)
+            gettext.dnpgettext(currentLocale, context, string, pluralString, count)

           ###*
            * Load plural string of specific context from specified domain
@@ -437,7 +437,7 @@
           ###
           env.addGlobal 'dnpgettext', (domain = currentLocale, context, string, pluralString, count) ->
             domain = if domain.charAt(0) == ':' then currentLocale + domain else domain
-            i18n.dnpgettext(domain, context, string, pluralString, count)
+            gettext.dnpgettext(domain, context, string, pluralString, count)

           # =======
           # Filters


[grunt] refactor passed inside Nunjucks data about page url, breadcrumb, basename and dirname

Please, note that pages at root from now will yeild proper dirname `'.'` and breadcrumb `['.']`

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -413,22 +413,17 @@
             ulrlify(string, options)

         preprocessData: (data) ->
-          fullFilepath = path.dirname(humanReadableUrl(@src[0]))
-
-          if fullFilepath == layoutsDir
-            filepath = ''
-            dirname  = ''
-          else
-            filepath = fullFilepath.replace(layoutsDir + '/', '')
-            dirname  = fullFilepath.split('/').slice(-1)[0]
+          pagepath    = humanReadableUrl(@src[0].replace(layoutsDir + '/', ''))
+          pagedir     = path.dirname(pagepath)
+          pagedirname = path.basename(pagedir)

           data.page = data.page || {}

           data.page.locale     = currentLocale
-          data.page.url        = '/' + filepath
-          data.page.breadcrumb = filepath.split('/')
-          data.page.basename   = path.basename(@src[0], '.nj')
-          data.page.dirname    = dirname
+          data.page.url        = if pagedir == '.' then '/' else '/' + pagedir
+          data.page.breadcrumb = if pagedir == '.' then ['.'] else pagedir.split('/')
+          data.page.basename   = path.basename(pagepath, path.extname(pagepath))
+          data.page.dirname    = pagedirname

           data


- LRSObject.on now throws error if event name or event handler is missing. - Improved code style (renamed func to handler). - Removed most underscore dependencies.

--- src/object.coffee
+++ src/object.coffee
@@ -9,7 +9,7 @@

 		if (!@options)
 			@options = {}
-		_.extend @options, options
+		_.extend(@options, options)

 		@events = {}

@@ -19,31 +19,32 @@
 		@

-	on: (event, func) ->
+	on: (event, handler) ->
+		throw new Error("Event type missing.") unless event # TODO: Check type?
+		throw new Error("Event handler missing.") unless handler # TODO: Check type?

-		if (!@events[event])
-			@events[event] = []
+		@events[event] = [] if not @events[event]

-		if (_.indexOf(@events[event], func) == -1)
-			@events[event].push func
+		@events[event].push(handler) unless handler in @events[event]

 		@

-	off: (event, func) ->
+	off: (event, handler) ->

-		if (!@events[event])
-			return
+		return unless @events[event]

-		index = _.indexOf(@events[event], func)
+		index = @events[event].indexOf(handler)

 		@events[event].splice(index, 1)

 		@

 	trigger: (event, attributes) ->
-		if(@events[event])
-			_.each @events[event], (func) =>
-				func.apply(@, attributes)
+		return unless @events[event]
+
+		@events[event].forEach((func) =>
+			func.apply(@, attributes)
+		)

 	get: (name) ->
 		@[name]


keep original sequence of the ad pod on the wrapper ad

--- src/parser.coffee
+++ src/parser.coffee
@@ -105,6 +105,9 @@
                                         for eventName in Object.keys ad.trackingEvents
                                             creative.trackingEvents[eventName] or= []
                                             creative.trackingEvents[eventName] = creative.trackingEvents[eventName].concat ad.trackingEvents[eventName]
+
+                                if ad.sequence?
+                                    wrappedAd.sequence = ad.sequence

                                 response.ads.splice index, 0, wrappedAd


error handling fix

error handling fix

--- lib/serializers/json.coffee
+++ lib/serializers/json.coffee
@@ -54,7 +54,7 @@
       message = buffer.toString("utf-8")
       callback null, JSON.parse(message), metadata
     catch err
-      callback null, err, null
+      callback err, null, null

 module.exports = JSONSerializer


Add condition that only parses nodes which have an attributes property (not comment nodes).

--- src/rivets.coffee
+++ src/rivets.coffee
@@ -133,7 +133,7 @@
     skipNodes = []
     bindingRegExp = @bindingRegExp()

-    parseNode = (node) =>
+    parse = (node) =>
       unless node in skipNodes
         for attribute in node.attributes
           if bindingRegExp.test attribute.name
@@ -183,8 +183,8 @@
       return

     for el in @els
-      parseNode el
-      parseNode node for node in el.getElementsByTagName '*'
+      parse el
+      parse node for node in el.getElementsByTagName '*' when node.attributes?

     return


Delete commented code

Delete commented code

--- lib/subindicatorator.coffee
+++ lib/subindicatorator.coffee
@@ -47,11 +47,4 @@

     averagedRows.push(averageIndicator)

-    #averagedRow =
-    #  periodStart: periodStart
-    #  text: modeText
-    #averagedRow[indicatorDefinition.valueField] = '-'
-    #averagedRow[indicatorDefinition.reduceField] = subIndicators
-
-
   return averagedRows


start spinner before clearing table

start spinner before clearing table

--- src/search.coffee
+++ src/search.coffee
@@ -125,8 +125,8 @@
     setup_ajaxy()
     hash = gethash()
     if hash
+        $('#ajax-loading').fadeIn()
         $('#q').empty().val(hash)
-        $('#ajax-loading').fadeIn()
         handleinput(false)
     if !Modernizr.input.autofocus
         $('#searchform form input').focus()


修正拼写错误

修正拼写错误

--- src/widget/edit/abstract-editor.coffee
+++ src/widget/edit/abstract-editor.coffee
@@ -65,7 +65,7 @@
 		return cola.constants.MESSAGE_REFRESH <= type <= cola.constants.MESSAGE_CURRENT_CHANGE or type == cola.constants.MESSAGE_VALIDATION_STATE_CHANGE or @_watchingMoreMessage

 	_processDataMessage: (path, type, arg) ->
-		if ype is cola.constants.MESSAGE_VALIDATION_STATE_CHANGE or cola.constants.MESSAGE_REFRESH <= type <= cola.constants.MESSAGE_CURRENT_CHANGE
+		if type is cola.constants.MESSAGE_VALIDATION_STATE_CHANGE or cola.constants.MESSAGE_REFRESH <= type <= cola.constants.MESSAGE_CURRENT_CHANGE
 			if @_bindInfo?.isWriteable
 				entity = @_scope.get(@_bindInfo.entityPath)
 				if entity


Test fix

Test fix

--- test/generators/join_tables.coffee
+++ test/generators/join_tables.coffee
@@ -110,7 +110,7 @@
               assert.ok(!err, "no errors: #{err}")
               assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
               expected = sortO(_.select(MODELS_JSON, (test) -> test.owner_id is owner_id), 'reverse_id')
-              actual = sortO(_.map(JSONUtils.parse(res.body), (item) -> _.omit(item, 'id')), 'reverse_id')
+              actual = sortO(_.map(JSONUtils.parse(res.body), (item) -> _.pick(item, 'owner_id', 'reverse_id')), 'reverse_id')
               assert.deepEqual(expected, actual, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")

               reverse_id = actual[0].reverse_id
@@ -122,7 +122,7 @@
                   assert.ok(!err, "no errors: #{err}")
                   assert.equal(res.status, 200, "status not 200. Status: #{res.status}. Body: #{util.inspect(res.body)}")
                   expected = sortO(_.select(MODELS_JSON, (test) -> test.reverse_id is reverse_id), 'owner_id')
-                  actual = sortO(_.map(JSONUtils.parse(res.body), (item) -> _.omit(item, 'id')), 'owner_id')
+                  actual = sortO(_.map(JSONUtils.parse(res.body), (item) -> _.pick(item, 'owner_id', 'reverse_id')), 'owner_id')
                   assert.deepEqual(expected, actual, "Expected: #{util.inspect(expected)}. Actual: #{util.inspect(actual)}")
                   done()


pass global App props to the App component

--- imports/startup/routes.cjsx
+++ imports/startup/routes.cjsx
@@ -13,7 +13,7 @@
 module.exports = (props) ->

   <Router history={browserHistory} >
-    <Route path="/" component={App}>
+    <Route path="/" component={App} App={props}>
       <Route path="apps" component={AppsPage} App={props} />
       <Route path="apps/:name/:version" component={AppsDetailPage} App={props} />
       <Route path="instances" component={Page} title='Instances'>


Thorough testing for multipleOf

Thorough testing for multipleOf

--- test/normalize/5-1-1-multipleOf.coffee
+++ test/normalize/5-1-1-multipleOf.coffee
@@ -63,6 +63,18 @@
       ]
     )
   )
+  test('5.1.1.1. Ignore', () ->
+    testNormalize(
+      {
+        multipleOf: undefined
+      },
+      {}
+    )
+    testNormalize(
+      {},
+      {}
+    )
+  )
   test('5.1.1.1. Valid', () ->
     testNormalize({
       multipleOf: 1


Another time reference circle does not like.

--- test/spec/poller_scheduler_spec.coffee
+++ test/spec/poller_scheduler_spec.coffee
@@ -102,7 +102,7 @@
         job1.promise.resolve("Done")
         job2.promise.resolve("Done")
         $rootScope.$digest()
-        sandbox.clock.now = (moment('2010-01-01 10:00:40').unix() * 1000)
+        sandbox.clock.now = (moment('2010-01-01T18:00:40.000Z').unix() * 1000)
         $timeout.flush()
         expect( job1.spy ).toHaveBeenCalledTwice()
         expect( job2.spy ).toHaveBeenCalledTwice()


Beat out the core commands.

Beat out the core commands.

--- keymaps/git-experiment.cson
+++ keymaps/git-experiment.cson
@@ -22,7 +22,7 @@
   'd': 'git:open-diff'
   'left': 'git:open-diff'

-'.git-commit-message-view atom-text-editor':
+'.git-commit-message-view atom-text-editor:not([mini])':
   'escape': 'git:view-and-commit-changes'
   'cmd-enter': 'git:commit'
   'ctrl-enter': 'git:commit'


ensureIndex for title

ensureIndex for title

--- lib/both/collections.coffee
+++ lib/both/collections.coffee
@@ -1 +1,3 @@
 Items = new Meteor.Collection 'items'
+if Meteor.isServer
+  Items._ensureIndex({ title: "text" })


fixed typo

fixed typo

--- lib/dataTable.server.coffee
+++ lib/dataTable.server.coffee
@@ -23,7 +23,7 @@
       DataTable.log "#{ subscription }:options", options
       total = collection.find( baseQuery ).count()
       DataTable.log "#{ subscription }:count:total", total
-      filtered = Browsers.find( filteredQuery ).count()
+      filtered = collection.find( filteredQuery ).count()
       DataTable.log "#{ subscription }:count:filtered", filtered
       @added( DataTable.countCollection, subscription, { count: total } )
       @added( DataTable.countCollection, "#{ subscription }_filtered", { count: filtered } )


destroy out of date views

destroy out of date views

--- lib/debugger/stepper.coffee
+++ lib/debugger/stepper.coffee
@@ -16,7 +16,11 @@
     ]

   attach: (ed) ->
-    @views.push new StepperView ed, @line
+    s = new StepperView ed, @line
+    @views.push s
+    ed.onDidDestroy =>
+      s.destroy()
+      @views = @views.filter((x) => x != s)

   setText: (@text) ->
     for view in @views
@@ -56,7 +60,7 @@
         @setText @text

   detach: ->
-    view?.destroy() for view in @views
+    view.destroy() for view in @views
     @views = []

   destroy: ->


[browser] Add null fall back on CommandManager#sendToWindow

--- src/browser/CommandManager.coffee
+++ src/browser/CommandManager.coffee
@@ -32,7 +32,7 @@
         return

     sendToWindow    : (window, command, args...) ->
-        return unless window?
+        return unless window?.browserWindow?.webContents?

         window.browserWindow.webContents.send "command", command, args...
         @emitter.emit "did-send", window, command, args...


horizontal layout for legend

horizontal layout for legend

--- Tank/Plugins/charts.coffee
+++ Tank/Plugins/charts.coffee
@@ -139,7 +139,7 @@
       colors: if @name in stackedGroups then stackedColors else defaultColors

       legend:
-        layout: "vertical"
+        layout: "horizontal"
         align: "center"
         verticalAlign: "bottom"
         borderWidth: 0


:new: Implement render in linter-views-new

--- lib/linter-views-new.coffee
+++ lib/linter-views-new.coffee
@@ -8,10 +8,22 @@
 class LinterViews
   constructor: (@linter) ->
     @subscriptions = new CompositeDisposable
+    @messages = []
+    @lineMessages = []
     @markers = []
     @panel = new BottomPanel
     @bottomContainer = new BottomContainer().prepare(@linter.state)
     @bottomBar = null
+
+    @subscriptions.add @linter.onDidClassifyMessages =>
+      @render()
+
+  render: ->
+    @messages = @linter.messages.getAllMessages()
+    @lineMessages = if @bottomContainer.getTab('File').attached then @linter.messages.getActiveFileMessagesForActiveRow() else []
+    count = @linter.messages.getCount()
+    count.Line = @lineMessages.length
+    @bottomContainer.setCount(count)

   attachBottom: (statusBar) ->
     @bottomBar = statusBar.addLeftTile


:bug: Fix persisting reference to pigments after package deactivation

Fixes abe33/atom-pigments#66

--- lib/minimap-pigments.coffee
+++ lib/minimap-pigments.coffee
@@ -14,11 +14,16 @@
     @minimap.registerPlugin 'pigments', this

   consumePigmentsServiceV1: (@pigments) ->
+    @subscriptions.add @pigments.getProject().onDidDestroy => @pigments = null
+
     @initialize() if @minimap? and @active

   deactivate: ->
+    @subscriptions.dispose()
+    @editorsSubscription.dispose()
     @minimap.unregisterPlugin 'pigments'
     @minimap = null
+    @pigments = null

   activatePlugin: ->
     return if @active
@@ -52,4 +57,3 @@

     @active = false
     @editorsSubscription?.dispose()
-    @subscriptions.dispose()


update loadURL for latest electron API changes

--- lib/nsync/web-window.coffee
+++ lib/nsync/web-window.coffee
@@ -17,7 +17,7 @@
     @webContents = @win.webContents

     @handleEvents()
-    @win.loadUrl(url) # TODO: handle failed load
+    @win.loadURL(url) # TODO: handle failed load

   handleEvents: ->
     @webContents.on 'did-finish-load', =>


move brand inside navbar, re-order center controls

--- tutor/src/components/navbar/index.cjsx
+++ tutor/src/components/navbar/index.cjsx
@@ -58,15 +58,13 @@
     params = Router.currentParams()
     {courseId} = params

-    brand = <TutorLink to='listing' className='navbar-brand'>
-
-            </TutorLink>
-
     <BS.Navbar fixedTop fluid ref="navBar">
+      <BS.Navbar.Brand>
+        <TutorLink to='listing' className='navbar-brand'>
+
+        </TutorLink>
+      </BS.Navbar.Brand>
       <CenterControls params={params} />
-      <BS.Navbar.Brand>
-        {brand}
-      </BS.Navbar.Brand>
       <BS.Navbar.Collapse>
         <BS.Nav>
           <CourseName course={course}/>