Fix fileFinder test

Fix fileFinder test

--- spec/atom/root-view-spec.coffee
+++ spec/atom/root-view-spec.coffee
@@ -54,7 +54,7 @@
             expect(rootView.find('.file-finder')).toExist()
             expect(rootView.find('.file-finder input:focus')).toExist()
             rootView.trigger 'toggle-file-finder'
-            expect(rootView.find('.editor:focus')).toExist()
+            expect(rootView.find('.editor:has(:focus)')).toExist()
             expect(rootView.find('.file-finder')).not.toExist()

         it "shows all relative file paths for the current project", ->


fix unit tests I broke by adding timeout to tags

--- services/web/test/UnitTests/coffee/Tags/TagsHandlerTests.coffee
+++ services/web/test/UnitTests/coffee/Tags/TagsHandlerTests.coffee
@@ -6,7 +6,7 @@
 _ = require('underscore')

-describe 'Tags handler', ->
+describe 'TagsHandler', ->
 	user_id = "123nd3ijdks"
 	project_id = "123njdskj9jlk"
 	tagsUrl = "tags.sharelatex.testing"
@@ -26,17 +26,17 @@

 	it 'Should post the request to the tags api with the user id in the url', (done)->
 		@handler.addTag user_id, project_id, tag, =>
-			@request.post.calledWith({uri:"#{tagsUrl}/user/#{user_id}/project/#{project_id}/tag", json:{name:tag}}).should.equal true
+			@request.post.calledWith({uri:"#{tagsUrl}/user/#{user_id}/project/#{project_id}/tag", timeout:1000, json:{name:tag}}).should.equal true
 			done()

 	it 'should send a delete request when a delete has been recived with the body format standardised', (done)->
 		@handler.deleteTag user_id, project_id, tag, =>
-			@request.del.calledWith({uri:"#{tagsUrl}/user/#{user_id}/project/#{project_id}/tag", json:{name:tag}}).should.equal true
+			@request.del.calledWith({uri:"#{tagsUrl}/user/#{user_id}/project/#{project_id}/tag", timeout:1000,  json:{name:tag}}).should.equal true
 			done()

 	it 'should tell the tags api to remove the project_id from all the users tags', (done)->
 		@handler.removeProjectFromAllTags user_id, project_id, =>
-			@request.del.calledWith({uri:"#{tagsUrl}/user/#{user_id}/project/#{project_id}"}).should.equal true
+			@request.del.calledWith({uri:"#{tagsUrl}/user/#{user_id}/project/#{project_id}", timeout:1000}).should.equal true
 			done()

 	describe "groupTagsByProject", ->


Enable old integration tests

Enable old integration tests

--- storage/test/integration-geocaches.coffee
+++ storage/test/integration-geocaches.coffee
@@ -3,7 +3,7 @@
 request = require 'superagent-as-promised'

 access = require '../lib/access'
-geocache = require '../lib/geocache'
+geocacheService = require '../lib/geocache'

 describe 'REST routes for geocaches', ->
     db = null
@@ -11,7 +11,8 @@
     url = null

     setupTestData = Promise.coroutine (geocaches) ->
-        g = geocache db
+        geocaches = JSON.parse JSON.stringify geocaches
+        g = geocacheService db
         yield g.deleteAll()
         for geocache in geocaches
             yield g.upsert geocache
@@ -20,13 +21,17 @@
     gc = (id, options) ->
         defaults =
             Code: "GC#{id}"
+            Name: 'geocache name'
             Latitude: 10
             Longitude: 20
+            Terrain: 1
+            Difficulty: 1
             Archived: false
             Available: true
-            CacheType:
-                GeocacheTypeId: 1
+            CacheType: GeocacheTypeId: 2
+            ContainerType: ContainerTypeName: 'Micro'
             UTCPlaceDate: "/Date(#{new Date().getTime()}-0000)/"
+            EncodedHints: 'some hints'
         merge = (a, b) ->
             return a unless b?
             for k, v of b
@@ -50,10 +55,11 @@
         a = access db
         token = yield a.getToken()

-        setupTestData []
+    beforeEach Promise.coroutine ->
+        yield setupTestData []

     describe '/gcs', ->
-        it.only 'should return a list of GC numbers on GET', Promise.coroutine ->
+        it 'should return a list of GC numbers on GET', Promise.coroutine ->
             yield setupTestData [
                 gc '100'
                 gc '101'
@@ -66,11 +72,9 @@
             expect(response.body).to.include.members ['GC100', 'GC101']

         it 'should filter by age using "maxAge"', Promise.coroutine ->
-            yield setupDatabase [
-                gc '100',
-                    UTCPlaceDate: "/Date(#{new Date().getTime()}-0000)/"
-                gc '101',
-                    UTCPlaceDate: '/Date(946684800-0000)/'
+            yield setupTestData [
+                gc '100', UTCPlaceDate: "/Date(#{new Date().getTime()}-0000)/"
+                gc '101', UTCPlaceDate: '/Date(00946684800-0000)/'
             ]
             response = yield request
                 .get "#{url}/gcs"
@@ -81,7 +85,7 @@
             expect(response.body).to.include.members ['GC100']

         it 'should filter by coordinates using "bounds"', Promise.coroutine ->
-            yield setupDatabase [
+            yield setupTestData [
                 gc '100',
                     Latitude: 10
                     Longitude: 10
@@ -104,34 +108,28 @@
             expect(response.body).to.include.members ['GC100']

         it 'should filter by type id using "typeIds"', Promise.coroutine ->
-            yield setupDatabase [
+            yield setupTestData [
+                gc '100', CacheType: GeocacheTypeId: 5
+                gc '101', CacheType: GeocacheTypeId: 6
+                gc '102', CacheType: GeocacheTypeId: 7
+            ]
+            response = yield request
+                .get "#{url}/gcs"
+                .query typeIds: [5, 7]
+                .set 'Accept', 'application/json'
+            expect(response.type).to.equal 'application/json'
+            expect(response.body.length).to.equal 2
+            expect(response.body).to.include.members ['GC100', 'GC102']
+
+        it 'should filter disabled/archived geocaches using "excludeDisabled"', Promise.coroutine ->
+            yield setupTestData [
                 gc '100',
-                    CacheType:
-                        GeocacheTypeId: 5
+                    Archived: false
+                    Available: false
                 gc '101',
-                    CacheType:
-                        GeocacheTypeId: 6
+                    Archived: false
+                    Available: true
                 gc '102',
-                    CacheType:
-                        GeocacheTypeId: 7
-            ]
-            response = yield request
-                .get "#{url}/gcs"
-                .query typeIds: [5, 7]
-                .set 'Accept', 'application/json'
-            expect(response.type).to.equal 'application/json'
-            expect(response.body.length).to.equal 2
-            expect(response.body).to.include.members ['GC100', 'GC102']
-
-        it 'should filter disabled/archived geocaches using "excludeDisabled"', Promise.coroutine ->
-            yield setupDatabase [
-                gc '100',
-                    Archived: false
-                    Available: false
-                gc '101',
-                    Archived: false
-                    Available: true
-                gc '102',
                     Archived: true
                     Available: false
                 gc '103',
@@ -147,7 +145,7 @@
             expect(response.body).to.include.members ['GC101']

         it 'should return disabled/archived geocaches by default', Promise.coroutine ->
-            yield setupDatabase [
+            yield setupTestData [
                 gc '100',
                     Archived: false
                     Available: false
@@ -170,13 +168,9 @@

         it 'should filter stale geocaches by default', Promise.coroutine ->
-            yield setupDatabase [
-                gc '100',
-                    meta:
-                        updated: new Date().toISOString()
-                gc '101',
-                    meta:
-                        updated: '2000-01-01 00:00:00Z'
+            yield setupTestData [
+                gc '100', meta: updated: new Date().toISOString()
+                gc '101', meta: updated: '2000-01-01 00:00:00Z'
             ]
             response = yield request
                 .get "#{url}/gcs"
@@ -186,11 +180,9 @@
             expect(response.body).to.include.members ['GC100']

         it 'should return stale geocaches when "stale" is 1', Promise.coroutine ->
-            yield setupDatabase [
-                gc '100',
-                    updated: new Date().toISOString()
-                gc '101',
-                    updated: '2000-01-01 00:00:00Z'
+            yield setupTestData [
+                gc '100', meta: updated: new Date().toISOString()
+                gc '101', meta: updated: '2000-01-01 00:00:00Z'
             ]
             response = yield request
                 .get "#{url}/gcs"
@@ -202,55 +194,81 @@

     describe '/geocaches', ->
         it 'should return a list of geocaches on GET', Promise.coroutine ->
-            a = gc '100', meta: updated: new Date().toISOString()
-            b = gc '101', meta: updated: new Date().toISOString()
-            yield setupDatabase [a, b]
-            response = yield request
-                .get "#{url}/geocaches"
-                .set 'Accept', 'application/json'
-
-            expect(response.type).to.equal 'application/json'
-            expect(response.body.length).to.equal 2
-            expect(response.body).to.deep.include.members [a, b]
+            a = gc '100'
+            b = gc '101'
+            yield setupTestData [a, b]
+            response = yield request
+                .get "#{url}/geocaches"
+                .set 'Accept', 'application/json'
+
+            expect(response.type).to.equal 'application/json'
+            expect(response.body.length).to.equal 2
+            expect(response.body.map (gc) -> gc.Code).to.deep.equal ['GC100', 'GC101']
+
+        [
+            name: 'Code'
+            type: 'String'
+        ,
+            name: 'Name'
+            type: 'String'
+        ,
+            name: 'Terrain'
+            type: 'Number'
+        ,
+            name: 'Difficulty'
+            type: 'Number'
+        ,
+            name: 'Archived'
+            type: 'Boolean'
+        ].forEach ({name, type}) ->
+            it "should include field #{name} of type #{type}", Promise.coroutine ->
+                a = gc '100'
+                yield setupTestData [a]
+                response = yield request
+                    .get "#{url}/geocaches"
+                    .set 'Accept', 'application/json'
+
+                [result] = response.body
+                expect(result[name]).to.exist
+                expect(result[name]).to.be.a type

         it 'should include the update timestamp', Promise.coroutine ->
             a = gc '100', meta: updated: new Date().toISOString()
-            yield setupDatabase [a]
-            response = yield request
-                .get "#{url}/geocaches"
-                .set 'Accept', 'application/json'
-
-            expect(response.body[0].meta.updated).to.equal a.meta.updated
+            yield setupTestData [a]
+            response = yield request
+                .get "#{url}/geocaches"
+                .set 'Accept', 'application/json'
+
+            [result] = response.body
+            expect(result.meta.updated).to.equal a.meta.updated

         it 'should create new geocaches on POST', Promise.coroutine ->
-            yield setupDatabase []
-
             a = gc '100', meta: updated: new Date().toISOString()

             putResponse = yield request
-                .put "#{url}/geocaches"
+                .post "#{url}/geocache"
                 .set 'Content-Type', 'application/json'
                 .set 'X-Token', token
-                .send [a]
+                .send a

             getResponse = yield request
-                .get "#{url}/geocaches"
-                .set 'Accept', 'application/json'
-
-            expect(getResponse.body).to.deep.equal [a]
+                .get "#{url}/geocache/GC100"
+                .set 'Accept', 'application/json'
+
+            expect(putResponse.status).to.equal 201
+            expect(getResponse.status).to.equal 200

         it 'should should reject POSTs without a valid API key', Promise.coroutine ->
-            yield setupDatabase []
-
             a = gc '100', meta: updated: new Date().toISOString()

             try
                 putResponse = yield request
-                    .put "#{url}/geocaches"
+                    .post "#{url}/geocache"
                     .set 'Content-Type', 'application/json'
                     .set 'X-Token', 'invalid'
-                    .send [a]
+                    .send a
             catch err
+                # expected

             expect(err.status).to.equal 403

@@ -261,16 +279,15 @@
             expect(getResponse.body).to.deep.equal []

         it 'should should reject POSTs with a missing API key', Promise.coroutine ->
-            yield setupDatabase []
-
             a = gc '100', meta: updated: new Date().toISOString()

             try
                 putResponse = yield request
-                    .put "#{url}/geocaches"
+                    .post "#{url}/geocache"
                     .set 'Content-Type', 'application/json'
-                    .send [a]
+                    .send a
             catch err
+                # expected

             expect(err.status).to.equal 403


Use memcached delete method

Use memcached delete method

--- phpsession.coffee
+++ phpsession.coffee
@@ -36,6 +36,7 @@

 	set: ({id, json, lifetime, cb}) ->
 		unless id?
+			cb 'ERRMISSPARAM'
 			return

 		unless lifetime?
@@ -59,6 +60,7 @@

 	update: ({id, key, value, lifetime, cb}) ->
 		unless key? and id?
+			cb 'ERRMISSPARAM'
 			return

 		unless lifetime?
@@ -83,6 +85,7 @@

 	delete: ({id, cb}) ->
 		unless id?
+			cb 'ERRMISSPARAM'
 			return

 		unless cb?
@@ -92,10 +95,10 @@
 			id: id
 			cb: (session) =>
 				if session?
-					@set
-						id: id
-						raw: null
-						lifetime: 0
-						cb: cb
+					@mem.del "sessions/#{id}", (err) =>
+						if err?
+							cb err
+						else
+							cb()
 				else
-					cb 'ERRNOSESS'+					cb 'ERRNOSESS'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/expirable.coffee
+++ test/expirable.coffee
@@ -15,5 +15,7 @@
     obj.update()

   equals obj.I.active, false, "object is inactive after duration"
+
+tes

 module()


adding real tests

adding real tests

--- test/real_test.coffee
+++ test/real_test.coffee
@@ -30,3 +30,10 @@

   it 'registers a realFood listener', ->
     expect(@robot.hear).to.have.been.calledWith(/real(f|F)ood/i)
+
+  it 'registers a realVodka listener', ->
+   expect(@robot.hear).to.have.been.calledWith(/real(v|V)odka/i)
+
+  it 'registers a realMartini listener', ->
+    expect(@robot.hear).to.have.been.calledWith(/real(m|M)artini/i)
+


Improve tests

Improve tests

--- test/repo.test.coffee
+++ test/repo.test.coffee
@@ -697,9 +697,23 @@
       fs.remove git_dir, (err) ->
         done err

+    describe "an existing branch", ->
+      beforeEach (done) ->
+        repo.checkout "feature/foo", {b: true}, (err) ->
+          return done err if err?
+          repo.checkout "master", (err) ->
+            return done err if err?
+            repo.branch (err, _head) ->
+              head = _head
+              done err
+
+      it "should succeed", ->
+        head.name.should.equal "master"
+
     describe "and create new branch", ->
       beforeEach (done) ->
-        repo.checkout "feature/foo", {b: true}, ->
+        repo.checkout "feature/foo", {b: true}, (err) ->
+          return done err if err?
           repo.branch (err, _head) ->
             head = _head
             done err


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -18,7 +18,7 @@
     x: 5
     y: 10

-  counter =
+  counter = 0

   engine.each (obj, index) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -3,6 +3,7 @@
 test "#each", ->
   engine = Engine()

+  engine.add

 test "#find", ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -32,7 +32,8 @@
       equals obj, obj2
     else if index is 2
       equals obj, obj3
-    else if index i
+    else if index is 3
+

 test "#find", ->
   engine = Engine()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -26,6 +26,6 @@
     y: 20

   equals engine.first('type=testObj').length, 1
-  equals engine.find('type')
+  equals engine.fis('type')

 module()


Use the xtk bower component.

Use the xtk bower component.

--- test/unit/main.coffee
+++ test/unit/main.coffee
@@ -70,7 +70,7 @@
     'underscore.string': './lib/underscore.string'
     uirouter: './lib/angular-ui-router'
     uibootstrap: './lib/ui-bootstrap-tpls'
-    xtk: './lib/xtk_edge'
+    xtk: './lib/xtk'
     # The test helpers.
     expect: '../../test/unit/helpers/expect'
     # The test vendor libraries.


Ignore tests.

Ignore tests.

I'm going to be rewriting these better and split across
multiple files.

--- test/hippodrome_spec.coffee
+++ test/hippodrome_spec.coffee
@@ -1,6 +1,6 @@
 Hippodrome = require('../dist/hippodrome.js')

-describe 'Hippodrome', ->
+xdescribe 'Hippodrome', ->
   beforeEach ->
     @Actions =
       changeName: new Hippodrome.Action 'changeName',


store nodes and edges on sphere

store nodes and edges on sphere

--- lib/core/sphere.coffee
+++ lib/core/sphere.coffee
@@ -7,15 +7,25 @@

   constructor: (args) ->
     @id = args?.id or Node.randomKey()
+    @nodes = {}
+    @edges = {}

   attr: (predicate, object) ->
     @triple @id, predicate, object

   triple: (subject, predicate, object) ->
-    new Edge
-      start: new Node name: subject
-      end: new Node name: object
+    @addEdge
+      start: @addNode name: subject
+      end: @addNode name: object
       data:
         name: predicate

+  addNode: (attrs) ->
+    node = new Node attrs
+    @nodes[node.id()] = node
+
+  addEdge: (attrs) ->
+    edge = new Edge attrs
+    @edges[edge.id()] = edge
+
 module.exports = Sphere


Add a try/catch so that we never block switching tabs

--- lib/linter-plus.coffee
+++ lib/linter-plus.coffee
@@ -39,8 +39,12 @@

     @subscriptions.add atom.workspace.onDidChangeActivePaneItem (editor) =>
       @activeEditor = editor
-      @getLinter(editor)?.lint(false)
-      @view.render()
+      # Exceptions thrown here prevent switching tabs
+      try
+        @getLinter(editor)?.lint(false)
+        @view.render()
+      catch error
+        atom.notifications.addError error.message, {detail: error.stack, dismissable: true}
     @subscriptions.add atom.workspace.observeTextEditors (editor) =>
       currentEditorLinter = new EditorLinter @, editor
       @editorLinters.set editor, currentEditorLinter


adjust heavy damage line

adjust heavy damage line

--- parts/prophet-hp.cjsx
+++ parts/prophet-hp.cjsx
@@ -10,11 +10,11 @@
   else
     'success'

-getLineStyle = (owner) ->
-  if owner
+getLineStyle = (flag) ->
+  if flag
+    'friend-hp'
+  else
     'enemy-hp'
-  else
-    'friend-hp'

 module.exports = React.createClass
   render: ->


doActions: handle feedback messages

doActions: handle feedback messages

--- lib/phabricator.coffee
+++ lib/phabricator.coffee
@@ -712,26 +712,38 @@
         for action, i in results.data
           query['transactions['+(i+1)+'][type]'] = action.type
           query['transactions['+(i+1)+'][value]'] = action.value
+        query['transactions['+(i+1)+'][type]'] = 'comment'
+        if comment?
+          query['transactions['+(i+1)+'][value]'] = "#{comment} (#{user.name})"
+        else
+          query['transactions['+(i+1)+'][value]'] = "#{results.messages.join(', ')} (by #{user.name})"
         console.log query
-      { id: id, messages: results.messages, data: [ 'open' ] }
-
-  parseAction: (item, str, res = { data: [], messages: [] }) ->
+        console.log i
+      { id: id, message: results.messages.join(', '), notices: results.notices }
+
+  parseAction: (item, str, res = { data: [], messages: [], notices: [] }) ->
     p = new RegExp("^(in|not in|on|is|to) ([^ ]*)")
     r = str.trim().match p
     switch r[1]
       when 'in'
         res.data.push({ type: 'projects.add', value: r[2] })
+        res.messages.push("added to #{r[2]}")
       when 'not in'
         res.data.push({ type: 'projects.remove', value: r[2] })
+        res.messages.push("removed from #{r[2]}")
       when 'on'
         res.data.push({ type: 'owner', value: r[2] })
+        res.messages.push("owner set to #{r[2]}")
       when 'to'
         res.data.push({ type: 'column', value: r[2] })
+        res.messages.push("column changed to #{r[2]}")
       when 'is'
         if @statuses[r[2]]?
           res.data.push({ type: 'status', value: r[2] })
+          res.messages.push("status set to #{r[2]}")
         else if @priorities[r[2]]
           res.data.push({ type: 'priority', value: r[2] })
+          res.messages.push("priority set to #{r[2]}")
     next = str.trim().replace(p, '')
     if next.trim() isnt ''
       res = @parseAction(item, next, res)


fix mkdir recursive

fix mkdir recursive

--- lib/promiseSftp.coffee
+++ lib/promiseSftp.coffee
@@ -354,7 +354,7 @@
       currPath = if dirPath.charAt(0) == '/' then '/' else ''
       isFirst = true;
       for token in tokens
-        if isFirst then
+        if isFirst
           currPath = "#{token}"
           isFirst = false
         else


Update test

Update test

--- tests/infrastructure/commit_publisher.unit.coffee
+++ tests/infrastructure/commit_publisher.unit.coffee
@@ -160,7 +160,7 @@

   it "cleans up after the commit is processed, by deleting the object key", ->
     mockPublisher = sinon.mock(@commitPublisher)
-    mockPublisher.expects("_cleanupTimeout").once().withExactArgs(@commitId)
+    mockPublisher.expects("_clearTimeout").once().withExactArgs(@commitId)
     @commitPublisher.startPublishing()
     expect(@commitPublisher._inProgress[@commitId]).to.equal.undefined
     mockPublisher.verify()


fix beforeOnce

fix beforeOnce

--- spec/helpers/index.coffee
+++ spec/helpers/index.coffee
@@ -2,7 +2,7 @@

 beforeOnce = (fn) ->
-  _.once(beforeEach fn)
+  beforeEach _.once(fn)

 mixins =


:new: Add specs for new behavior

:new: Add specs for new behavior

--- spec/validate-spec.coffee
+++ spec/validate-spec.coffee
@@ -104,3 +104,9 @@
         validate.messages([{type: 'Error', text: 'Well', class: 'error', filePath: 1}], {name: ''})
       .toThrow()
       validate.messages([{type: 'Error', text: 'Well', class: 'error', filePath: '/'}], {name: ''})
+    it 'throws if both text and html are provided', ->
+      expect ->
+        validate.messages([{type: 'Error', text: 'Well', html: 'a', class: 'error', filePath: '/'}], {name: ''})
+      .toThrow()
+      validate.messages([{type: 'Error', text: 'Well', class: 'error', filePath: '/'}], {name: ''})
+      validate.messages([{type: 'Error', html: 'Well', class: 'error', filePath: '/'}], {name: ''})


Adds some dummy acks data.

Adds some dummy acks data.

--- admin/static/coffee/namespaceview.coffee
+++ admin/static/coffee/namespaceview.coffee
@@ -71,11 +71,13 @@
                     'id': @model.get('primary_uuid')
                     'name': datacenters.get(@model.get('primary_uuid')).get('name')
                     'replicas': @model.get('replica_affinities')[@model.get('primary_uuid')]
+                    'acks' : @model.get('replica_affinities')[@model.get('primary_uuid')]
                 'secondaries':
                     _.map secondary_affinities, (replica_count, uuid) =>
                         'id': uuid
                         'name': datacenters.get(uuid).get('name')
                         'replicas': replica_count
+                        'acks': replica_count
                 'datacenters_left': datacenters.models.length > _.size(@model.get('replica_affinities'))
             @.$el.html @template(json)


Add cmd to menus :memo:

Add cmd to menus :memo:

--- menus/menu.cson
+++ menus/menu.cson
@@ -121,6 +121,20 @@
           ]
         }
         {
+          'label': 'Table'
+          'submenu': [
+            {
+              'label': 'Format Table'
+              'command': 'markdown-writer:format-table'
+            }
+            { 'type': 'separator' }
+            {
+              'label': 'Jump to Next Table Cell'
+              'command': 'markdown-writer:jump-to-next-table-cell'
+            }
+          ]
+        }
+        {
           'label': 'Helpers'
           'submenu': [
             {
@@ -133,18 +147,13 @@
             }
             { 'type': 'separator' }
             {
-              'label': 'Jump to Definition'
+              'label': 'Jump to Link/Definition'
               'command': 'markdown-writer:jump-to-reference-definition'
             }
             { 'type': 'separator' }
             {
-              'label': 'Jump to Next Table Cell'
-              'command': 'markdown-writer:jump-to-next-table-cell'
-            }
-            { 'type': 'separator' }
-            {
-              'label': 'Format Table'
-              'command': 'markdown-writer:format-table'
+              'label': 'Open Link in Browser'
+              'command': 'markdown-writer:open-link-in-browser'
             }
           ]
         }


tests

tests

--- vendor/assets/javascripts/planning_view.js.coffee
+++ vendor/assets/javascripts/planning_view.js.coffee
@@ -141,6 +141,7 @@
       break
   if property == undefined
     css = "#planning-view__container .planning-view__row-wrapper { #{property}: #{value} }"
+    console.log css
     head = document.head || document.getElementsByTagName('head')[0]
     style = document.createElement 'style'
     style.type = 'text/css'
@@ -149,7 +150,7 @@
       style.styleSheet.cssText = css;
     else
       style.appendChild(document.createTextNode css)
-      head.appendChild(style)
+    head.appendChild(style)
   if value == undefined
     return property[style]
   else


initial value for jKiteStacks

initial value for jKiteStacks

--- workers/social/lib/social/models/kitestack.coffee
+++ workers/social/lib/social/models/kitestack.coffee
@@ -13,7 +13,18 @@
       ratio       : Number
       isEnabled   : Boolean

-  @fetchInfo = (callback) -> @one {}, callback
+  @fetchInfo = (callback) ->
+    @one {}, (err, info) ->
+      return callback err         if err?
+      return callback null, info  if info?
+
+      info = new JKiteStack
+        ratio     : 0
+        isEnabled : yes
+      info.save (err) ->
+        return callback err  if err
+
+        callback null, info

   @setInfo = secure (client, { ratio, isEnabled }, callback) ->
     { connection:{ delegate }} = client


Share updateInstance event of JWorkspace model

--- workers/social/lib/social/models/workspace.coffee
+++ workers/social/lib/social/models/workspace.coffee
@@ -41,7 +41,7 @@
         delete          : signature Function
     sharedEvents        :
       static            : []
-      instance          : []
+      instance          : ['updateInstance']

   @create$ = secure (client, data, callback) ->


Fixes a bug that caused normalization to break

`_.forEach` stops iteration when the argument function returns false.
The normalization assignment in Coffeescript caused an implicit return
statement that results in false if the value is false (which is a valid
case).

I fixed this by explicitly returning true.

--- src/normalize-salesforce.coffee
+++ src/normalize-salesforce.coffee
@@ -58,6 +58,7 @@
           normalized[@normalize(key)] = @normalize(value)
         else
           normalized[@normalize(key)] = value
+        true

       normalized

@@ -90,5 +91,6 @@
           )
         else
           denormalized[@denormalize(key, sObject)] = value
+        true

       denormalized


Check mountpoint before creating a new one, if exists fail. Show meaningful error messages

--- kites/sharedHosting/mounter.coffee
+++ kites/sharedHosting/mounter.coffee
@@ -101,29 +101,36 @@

     # fetch user ID for curlftfs command
     @spawnWrapper '/usr/bin/id', ['-u', username], (err,res)=>
-      if err?
+      if err
         log.error error = "[ERROR] Can't find user ID: #{err}"
         callback error
       else
-        uid = res.trim()
-        log.info "[OK] user ID for user #{username} is #{uid}"
-        ftpfsopts = "#{config.ftpfs.opts},uid=#{uid},gid=#{uid},fsname=#{remotehost},user=#{remoteuser}:#{remotepass}"
-        @createMountpoint options, (err,res)=>
-          if err
-            callback err
-          else
-            @spawnWrapper config.ftpfs.curlftpfs,['-o', ftpfsopts, remotehost, options.mountpoint] , (err, res)=>
-              if err?
-                log.error error = "[ERROR] couldn't mount remote FTP server #{remotehost}: #{err}"
-                callback error
+        @checkMountPoint options, (err, state)=>
+          if state.mounted
+            callback "Mountpoint #{state.mountpoint} already exists"
+          else
+            uid = res.trim()
+            log.info "[OK] user ID for user #{username} is #{uid}"
+            ftpfsopts = "#{config.ftpfs.opts},uid=#{uid},gid=#{uid},fsname=#{remotehost},user=#{remoteuser}:#{remotepass}"
+            @createMountpoint options, (err, res)=>
+              if err
+                callback err
               else
-                @remountVE options, (err,res)=>
-                  if err?
-                    callback err
+                @spawnWrapper config.ftpfs.curlftpfs, ['-o', ftpfsopts, remotehost, options.mountpoint], (err, res)=>
+                  if err
+                    log.error error = "Couldn't mount remote FTP server #{remotehost}: #{err}"
+                    fs.rmdir options.mountpoint, (err)->
+                      log.error err if err
+                      callback error
                   else
-                    @updateMountCfg options,(err,res)->
-                    callback null,res
-
+                    @remountVE options, (err,res)=>
+                      if err
+                        callback err
+                      else
+                        @updateMountCfg options, (err,res)->
+                        callback null, res
+
+  # Safe
   checkMountPoint : (options, callback)->
     #
     # this method checks if remount host mounted (it doesn't check for availability)
@@ -147,10 +154,12 @@

     rs = fs.createReadStream '/proc/mounts', flags: 'r'
     rs.setEncoding()
+
     rs.on 'error', (err)->
       console.error error = "Unexpected error : couldn't retrieve mount info: #{err.message}"
       callback error
-    rs.on 'data',(data)->
+
+    rs.on 'data', (data)->
       if data.indexOf(options.mountpoint) isnt -1
         console.log "[OK] #{remotehost} is mounted for user #{username}"
         rs.destroy()
@@ -160,7 +169,7 @@
           mountpoint: options.mountpoint
         callback null, res
       else
-        console.log error = "[ERROR] mountpoing #{options.mountpoint} is not mounted"
+        console.log error = "[ERROR] mount point #{options.mountpoint} is not mounted"
         res =
           mounted: false
           remotehost: remotehost
@@ -195,10 +204,10 @@
     @spawnWrapper '/sbin/fuser', ['-mk',options.mountpoint],(err,res)=>
       @spawnWrapper '/bin/umount', [options.mountpoint],(err, res)=>
         if err?
-          log.error error = "[ERROR] can't umount #{options.mountpoint}: #{err}"
+          log.error error = "Can't umount #{options.mountpoint}: #{err}"
           callback error
         else
-          log.info info = "[OK] directory #{options.mountpoint} umounted"
+          log.info info = "Directory #{options.mountpoint} umounted"
           @remountVE options,(err,res)=>
             if err
               callback err
@@ -209,7 +218,7 @@
                   console.warn "Couldn't remove mountpoint #{options.mountpoint}: #{err.message}"
                 else
                   console.log "mountpoint #{options.mountpoint} has been removed"
-                callback null
+                callback null, info

   # Safe
   readMountInfo: (options, callback)->
@@ -287,23 +296,23 @@
               jsonConf = JSON.stringify res
               fs.writeFile cfg, jsonConf, 'utf-8',(err)->
                 if err?
-                  log.error error = "[error] couldn't update config #{cfg}: #{err.message}"
+                  log.error error = "Couldn't update config #{cfg}: #{err.message}"
                   callback error
                 else
-                  log.info info = "[ok] config successfully updated"
+                  log.info info = "Config successfully updated"
                   callback null, info
             else
-              log.warn warn = "[WARN] config for #{remotehost} already exists"
+              log.warn warn = "Config for #{remotehost} already exists"
               callback null, warn
       else
         jsonConf = JSON.stringify [newConf]
         fs.writeFile cfg, jsonConf, 'utf-8',(err)->
           if err?
-            log.error error = "[error] couldn't update config #{cfg}: #{err.message}"
+            log.error error = "Couldn't update config #{cfg}: #{err.message}"
             callback error
           else
             fs.chmod cfg,'0600',(err)->
-            log.info info = "[ok] config successfully created"
+            log.info info = "Config successfully created"
             callback null, info

   # Safe
@@ -337,10 +346,10 @@
         jsonConf = JSON.stringify res
         fs.writeFile cfg, jsonConf, 'utf-8',(err)->
           if err?
-            log.error error = "[ERROR] Couldn't update config #{cfg}: #{err.message}"
+            log.error error = "Couldn't update config #{cfg}: #{err.message}"
             callback error
           else
-            log.info info = "[OK] config successfully updated"
+            log.info info = "Config successfully updated"
             callback null, info

   mountSshDriveWithKey: (options, callback)->
@@ -486,10 +495,10 @@
     args = ['-m', username]
     @spawnWrapper config.cagefsctl, args ,(err, res)->
       if err?
-        log.error error = "[ERROR] Couldn't remount user's VE - username #{username}: #{stderr}"
+        log.error error = "Couldn't remount user's VE - username #{username}: #{stderr}"
         callback error
       else
-        log.info info = "[OK] user's VE #{username} remounted"
+        log.info info = "User: #{username} virtual environment remounted."
         callback null, info

   spawnWrapper : (command, args , callback)->
@@ -503,18 +512,18 @@

     wrapper.on 'exit',(code)->
       if code isnt 0
-        log.error err = "[ERROR] command #{command} error: #{wrapperErr}"
-        callback err
+        log.error err = "Command #{command} error: #{wrapperErr}"
+        callback wrapperErr.toString("utf-8", 0, 12)
       else
         log.info res = wrapperData.toString("utf-8", 0, 12)
-        log.info info = "[OK] command #{command} executed successfully output: #{res}"
+        log.info info = "Command #{command} executed successfully output: #{res}"
         callback null, res

   # Safe
   createMountpoint : (options, callback)->

     # create mount point for remote resource
-    # /Users/<username>/RemoteDrive/<remote_hostname>
+    # /Users/<username>/RemoteDrives/<remote_hostname>

     # return
     #   callback error
@@ -536,17 +545,17 @@

     fs.stat mountpoint, (err,stats)->
       if stats
-        log.info info = "[OK] #{mountpoint} already exists"
+        log.info info = "Mountpoint #{mountpoint} already exists"
         callback null, info
       else
         mkdirp mountpoint, 0o0755, (err)->
           if err?
-            log.error error = "[ERROR] Couldn't create mountpoint #{mountpoint}: #{err.message}"
+            log.error error = "Couldn't create mountpoint #{mountpoint}: #{err.message}"
             callback error
           else
             chownr {username, path:mountpoint}, (err)->
               unless err
-                log.info info = "[OK] mountpoint #{mountpoint} created"
+                log.info info = "Mountpoint #{mountpoint} created"
                 callback null, info
               else
                 log.error "An error occured:", err


dont forget to pass remotepass if provided

--- kites/sharedHosting/mounter.coffee
+++ kites/sharedHosting/mounter.coffee
@@ -36,7 +36,7 @@
     #   callback error
     #   callback null, result (information message)

-    {username, remotehost, remotepass, remotetype} = options
+    {username, remotehost, remotepass, remotetype, storepass} = options

     @readMountInfo options, (err,res)=>
       if err?
@@ -56,9 +56,10 @@

         mount = mounts[0]

-        mount.username  = options.username
-        mount.storepass = options.storepass
-        mount.mountonly = yes
+        mount.username   = username
+        mount.storepass  = storepass
+        mount.mountonly  = yes
+        mount.remotepass = remotepass if remotepass

         switch mount.remotetype
           when "ftp"


do not use .netrc for curlftpfs - unsecure

--- kites/sharedHosting/mounter.coffee
+++ kites/sharedHosting/mounter.coffee
@@ -107,65 +107,22 @@
       else
         uid = res.trim()
         log.info "[OK] user ID for user #{username} is #{uid}"
-        ftpfsopts = "#{config.ftpfs.opts},uid=#{uid},gid=#{uid},fsname=#{remotehost}"
+        ftpfsopts = "#{config.ftpfs.opts},uid=#{uid},gid=#{uid},fsname=#{remotehost},user=#{remoteuser}:#{remotepass}"
         @createMountpoint options, (err,res)=>
           if err
             callback err
           else
-            options.install = true
-            @tmpNetrc options,(err,res)=>
+            @spawnWrapper config.ftpfs.curlftpfs,['-o', ftpfsopts, remotehost, options.mountpoint] , (err, res)=>
               if err?
-                callback err
+                log.error error = "[ERROR] couldn't mount remote FTP server #{remotehost}: #{err}"
+                callback error
               else
-                HOME = process.env.HOME
-                process.env.HOME = path.join config.usersPath, username
-                console.log "tmp home for .netrc is #{process.env.HOME}"
-                @spawnWrapper config.ftpfs.curlftpfs,['-o', ftpfsopts, remotehost, options.mountpoint] , (err, res)=>
-                  process.env.HOME = HOME
-                  console.log "home changed back to #{process.env.HOME}"
-                  options.install = false
-                  @tmpNetrc options,(err,res)=>
+                @remountVE options, (err,res)=>
                   if err?
-                    log.error error = "[ERROR] couldn't mount remote FTP server #{remotehost}: #{err}"
-                    callback error
+                    callback err
                   else
-                    @remountVE options, (err,res)=>
-                      if err?
-                        callback err
-                      else
-                        @updateMountCfg options,(err,res)->
-                        callback null,res
-
-  # Safe
-  tmpNetrc : (options,callback)->
-
-    # this method will create .netrc file for curlftpfs
-
-    {username, remotehost, remoteuser, remotepass, install} = options
-    rcPath = escapePath path.join config.usersPath, username, '.netrc'
-
-    unless safeForUser username, rcPath
-      console.error "User [#{username}] is trying to make something bad: ", rcPath
-      callback "You are not authorized to do this."
-      return no
-
-    if install
-      conf = "machine #{remotehost} login #{remoteuser} password #{remotepass}"
-      fs.writeFile rcPath, conf, 'utf-8', (err)->
-        if err?
-          console.error error = "[error] couldn't write .netrc file #{rcPath}: #{err.message}"
-          callback error
-        else
-          console.log info = "[ok] .netc #{rcPath} installed"
-          callback null, info
-    else
-      fs.unlink rcPath, (err)->
-        if err?
-          console.err error = "[ERROR] couldn't remove .netrc file #{rcPath}: #{err.message}"
-          callback error
-        else
-          console.log info = "[OK] .netrc file #{rcPath} has been removed"
-          callback null, info
+                    @updateMountCfg options,(err,res)->
+                    callback null,res

   # Safe
   umountDrive : (options, callback)->
@@ -552,4 +509,5 @@
                 log.error "An error occured:", err
                 callback err

-module.exports = mounter+module.exports = mounter
+


Find the closest container

Find the closest container

--- app/assets/javascripts/task_lists.coffee
+++ app/assets/javascripts/task_lists.coffee
@@ -46,7 +46,7 @@
 # since the user is trying to update old data. An error should be displayed
 # when the page loads. In Rails, you can use `flash[:error]`.
 updateTaskListItem = (item) ->
-  container = item.parents('.js-task-list-container')
+  container = item.closest('.js-task-list-container')
   url  = container.attr('data-task-list-update-url')
   data =
     item:    item.attr('data-item-index')


Add links to create and search song.

Add links to create and search song.

--- app/client/js/react/pages/mysongs.coffee
+++ app/client/js/react/pages/mysongs.coffee
@@ -10,7 +10,7 @@
     @constructor
   ###
   constructor: (routes, userStore, touch, firebase) ->
-    {div,h1,ul,li,p,nav,button} = React.DOM
+    {div,ul,li,p,nav} = React.DOM
     {a} = touch.scroll 'a'

     @component = React.createClass
@@ -28,19 +28,32 @@
                 a href: routes.mySong.url(song),
                   "#{song.getDisplayName()} [#{song.getDisplayArtist()}]"
           else
-            p {}, MySongs.MSG_NO_SONGS
+            div {},
+              p {}, MySongs.MSG_NO_SONGS
+              p {},
+                a
+                  href: routes.newSong.url()
+                , MySongs.MSG_ADD
+                MySongs.MSG_OR
+                a
+                  href: routes.songs.url()
+                , MySongs.MSG_SEARCH
+                MySongs.MSG_ONE
           nav {},
-            a
-              className: 'btn btn-link'
-              href: routes.newSong.url()
-            , MySongs.MSG_ADD_NEW_SONG
+            if songs.length > 0
+              a
+                className: 'btn btn-link'
+                href: routes.newSong.url()
+              , MySongs.MSG_ADD_NEW_SONG
             if deletedSongs.length > 0
               a
                 className: 'btn btn-link'
                 href: routes.trash.url()
               , "Trash (#{deletedSongs.length})"

+  @MSG_ADD: goog.getMsg 'Add'
   @MSG_ADD_NEW_SONG: goog.getMsg 'Add Song'
-  @MSG_NO_SONGS: goog.getMsg "
-    You have no songs stored on your device yet. Add or search one.
-  "
+  @MSG_NO_SONGS: goog.getMsg "You have no song stored on your device yet."
+  @MSG_ONE: goog.getMsg ' one.'
+  @MSG_OR: goog.getMsg ' or '
+  @MSG_SEARCH: goog.getMsg 'search'


Fixing epic links in rich content

Fixing epic links in rich content

--- app/coffee/modules/common/wisiwyg.coffee
+++ app/coffee/modules/common/wisiwyg.coffee
@@ -374,7 +374,7 @@
                         search: (term, callback) ->
                             term = taiga.slugify(term)

-                            searchTypes = ['issues', 'tasks', 'userstories']
+                            searchTypes = ['issues', 'tasks', 'userstories', 'epics']
                             searchProps = ['ref', 'subject']

                             filter = (item) =>
@@ -384,8 +384,7 @@
                                 return false

                             cancelablePromise.abort() if cancelablePromise
-
-                            cancelablePromise = $rs.search.do($scope.projectId, term)
+                            cancelablePromise = $rs.search.do($scope.projectId || $scope.vm.projectId, term)

                             cancelablePromise.then (res) =>
                                 # ignore wikipages if they're the only results. can't exclude them in search
@@ -441,15 +440,18 @@
                         search: (term, callback) ->
                             term = taiga.slugify(term)

-                            $rs.search.do($scope.projectId, term).then (res) =>
+                            $rs.search.do($scope.projectId || $scope.vm.projectId, term).then (res) =>
                                 if res.count < 1
+                                    console.log 1
                                     callback([])

                                 if res.count < 1 or not res.wikipages or res.wikipages.length <= 0
+                                    console.log 2
                                     callback([])

                                 else
                                     callback res.wikipages.filter((page) =>
+                                        console.log 3
                                         return taiga.slugify(page['slug']).indexOf(term) >= 0
                                     ), true


fix javascript sorting errors in zh_Hant locale

turns out zh_Hant is not a valid BCP 47 language tag
but "zh-Hant" is

this error was being swallowed up in the files and
 groups pages by react

test plan:
* with locales enabled, the files and groups pages
 should work with Traditional Chinese locale

closes #CNVS-26943 #CNVS-18596

Change-Id: I2f1aacae093a945bfedc95a2765657c1fb2d62b7
Reviewed-on: https://gerrit.instructure.com/71578
Tested-by: Jenkins
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
QA-Review: Clare Strong <40d6bb3ed7fef516c73274131d5a837c16de74fd@instructure.com>
Product-Review: James Williams  <3a5f4ed991dbfa5c9ef76ad729d240ca12f62180@instructure.com>

--- app/coffeescripts/util/natcompare.coffee
+++ app/coffeescripts/util/natcompare.coffee
@@ -1,6 +1,9 @@
 define [], ->
   strings: (x, y) ->
-    x.localeCompare(y, window.I18n.locale || 'en-US', { sensitivity: 'accent', ignorePunctuation: true, numeric: true})
+    locale = window.I18n.locale || 'en-US'
+    locale_map = {'zh_Hant': 'zh-Hant'}
+    locale = locale_map[locale] || locale
+    x.localeCompare(y, locale, { sensitivity: 'accent', ignorePunctuation: true, numeric: true})

   by: (f) ->
     return (x, y) =>


Maintenance: Add missing options for tree select perform actions.

--- app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee
+++ app/assets/javascripts/app/controllers/_ui_element/core_workflow_perform.coffee
@@ -40,7 +40,7 @@
       'boolean$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to']
       'integer$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional']
       '^select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select']
-      '^tree_select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'select', 'auto_select']
+      '^tree_select$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'add_option', 'remove_option', 'set_fixed_to', 'select', 'auto_select']
       '^input$': ['show', 'hide', 'remove', 'set_mandatory', 'set_optional', 'fill_in', 'fill_in_empty']

     operatorsName =


Exo.Spine.Controller: Fixed a ref bug with addChild and added a mechanism for setting the nodeId

--- src/spine/controller.coffee
+++ src/spine/controller.coffee
@@ -16,7 +16,7 @@
       _node

     @nodeId = -> @node().nodeId()
-    @setId = (id)-> @node.setId(id)
+    @setNodeId = (id)-> @node().setNodeId(id)
     @setMode = (mode)-> @node().setMode(mode)

     @activate = ->
@@ -45,7 +45,7 @@

     # TODO: Make sure the node function exists and throw an Exo.Incompatible
     # object error if not.
-    @addChild = (controller)-> @node().addChild controller.node()
+    @addChild = (controller)-> @node().addChild controller?.node()

     @children = ->
       @node().children().map (node)-> node.controller


about page

about page

--- tests/admin.go.coffee
+++ tests/admin.go.coffee
@@ -455,4 +455,27 @@
   jsonData = JSON.parse(@getPageContent())
   @test.assertMatch jsonData.uploadurl,/^\/_ah\/upload/,"test upload url"

+
+# add content by post
+casper.thenOpen baseURL + "/admin/rest/adminpage",
+  @echo "create about page"
+  method: "post"
+  data:
+    title: "About this site."
+    url: "about"
+    content: """This site is the showcase of GAE Go Starter.
+      GAE, Google App Engine, is one of PaaS platform to build a web application.
+      GAE has some excellent features for developers, for example, auto scaling and maintainance free key value store, taskque and so on.
+      Go is the best perfermance language for web application, and GAE with go launchs new instances fastest than python and java.
+      This starter template is collection of sample implementations of GAE/Go, so developers can develop new applications based on this app.
+      And this Starter app has content management functions, so it is easy to use this application as a corporate page or blog engine.
+      """
+    displaypage: "on"
+, ->
+  @echo "POST request has been sent."
+  @test.assertHttpStatus 201
+  jsonData = JSON.parse(@getPageContent())
+  @test.assertEqual jsonData.message, "created", "return created message"
+
+
 casper.run()


Don't renderAttrs unnecessarily

Don't renderAttrs unnecessarily

It is unneeded here, and causes bad behavior.

--- common/static/coffee/src/discussion/views/discussion_thread_view.coffee
+++ common/static/coffee/src/discussion/views/discussion_thread_view.coffee
@@ -278,7 +278,6 @@
       comment = new Comment(body: body, created_at: (new Date()).toISOString(), username: window.user.get("username"), votes: { up_count: 0 }, abuse_flaggers:[], endorsed: false, user_id: window.user.get("id"))
       comment.set('thread', @model.get('thread'))
       @renderResponseToList(comment, ".js-response-list")
-      @renderAttrs()
       @model.addComment()
       @renderAddResponseButton()


0.5a

0.5a

-Added left-bottom corner panel
-Added iTunes remote cell

--- Eva.widget/index.coffee
+++ Eva.widget/index.coffee
@@ -1,34 +1,40 @@
 refreshFrequency: 1000
 style: """
-    top: -45px
-    right: -60px
-    color: #fff
-    padding: 5px
-    opacity:0.5
+    top: -25px
     font-family: Futura
     text-transform: uppercase
-    .wrap
-        margin:0px
+    position:relative
+    opacity: 0.5
+    margin:0px
+    text-align:center
+    text-decoration:none
+    .left
+        position: fixed
+        bottom: -25px
+        left:-100px
+        width: 800px
+        float:left
+        vertical-align : bottom
+    .right
+        float:right
+        margin-right:-60px
     .nav
+        text-decoration: none
+        font-size: 20px
         transform:rotate(90deg)
-        width:100px
-        height:58px
+        width:100px;height:58px
         background:rgba(10,10,10,1)
         display:inline-block
         position:relative
         line-height:58px
-        text-align:center
         color:#ffffff
-        font-size:20px
-        text-decoration:none
         float:right
         margin-top:-5px
         margin-left:45px
         margin-right:45px
     .nav s
         margin-left:10px
-        width:0
-        height:0
+        width:0;height:0
         display:block
         overflow:hidden
         position:absolute
@@ -80,6 +86,17 @@
         border-top:95px solid rgba(10,10,10,1)
         right:0px
         bottom:-95px
+    .nav s1
+        margin-left:10px
+        width:0;height:0
+        display:block
+        overflow:hidden
+        position:absolute
+        border-right:0px dotted transparent
+        border-left:100px dotted transparent
+        border-bottom:60px solid rgba(10,10,10,1)
+        right:0px
+        top:-60px
     .nav s2
         margin-left:10px
         width:100px
@@ -96,7 +113,9 @@
         @keyframes meow_BB { from { border-top-color:rgba(256,0,0,1); } to { border-top-color:rgba(128,0,0,1); }  }
     .a1
         margin-right:140px
-    .ai, .nav:hover ai, .a4
+    .ai
+        visibility: hidden
+    .a4
         background:rgba(0,0,0,0)
     .nav:hover a0 s
         border-top-color:rgba(128,128,128,1)
@@ -112,9 +131,9 @@
         height:200px
     .a1:hover, .a2:hover, .a3:hover
         background-color:rgba(128,128,128,1)
-    .nav:hover s
+    .a1:hover s, .a2:hover s, .a3:hover s
         border-bottom-color:rgba(128,128,128,1)
-    .nav:hover b
+    .a1:hover b, .a2:hover b, .a3:hover b
         border-top-color:rgba(128,128,128,1)
     .output
         padding: 5px 10px
@@ -164,144 +183,267 @@
     .Rotate
         transform:rotate(-90deg)
         width:200px
+    .iTunesPre
+        width:0;height:0
+        position:relative
+        border-right:11px dotted transparent
+        border-left:11px dotted transparent
+        border-top:20px solid rgba(256,256,256,1)
+        right:-40px
+        top:-10px
+    .iTunesNext
+        width:0;height:0
+        position:relative
+        border-right:11px dotted transparent
+        border-left:11px dotted transparent
+        border-bottom:20px solid rgba(256,256,256,1)
+        right:-40px
+        top:-260px
+    .iTunesPause
+        width:30px;height:8px
+        position:relative
+        border-top:8px solid rgba(256,256,256,1)
+        border-bottom:8px solid rgba(256,256,256,1)
+        right:-37px
+        top:-100px
+    .iTunesPlay
+        width:0;height:0
+        position:relative
+        border-right:17px dotted transparent
+        border-left:17px dotted transparent
+        border-bottom:30px solid rgba(256,256,256,1)
+        right:-35px
+        top:-170px
+    .iTunesPlay:active
+        border-bottom-color: rgba(128,128,128,1)
+    .iTunesPause:active
+        border-top-color: rgba(128,128,128,1)
+        border-bottom-color: rgba(128,128,128,1)
+    .iTunesNext:active
+        border-bottom-color: rgba(128,128,128,1)
+    .iTunesPre:active
+        border-top-color: rgba(128,128,128,1)
 """

 render: -> """
-

+

+
+
+        <s></s>
+
46

+
WARNUNG

+        <s></s>
+
47

+
WARNUNG

+

+
+
+        <s></s>
+
49

+
WARNUNG

+        <s></s>
+
50

+
WARNUNG

+
+
+
+        <s1></s1><b1></b1>
+        <s></s>
+
54

+
WARNUNG

+

+
+
+        <s></s><b3></b3>
+        <s2></s2>
+

+

+

+
+        <s></s>
+
59

+
WARNUNG

+        <s></s><b2></b2>
+        <s></s>
+
61

+
WARNUNG

+

+
+
+        <s></s>
+
63

+
WARNUNG

+        <s></s>
+
64

+
WARNUNG

+
+
+
+        <s></s>
+
67

+
WARNUNG

+        <s></s>
+
68

+
WARNUNG

+

+
+
+        <s></s>
+
70

+
WARNUNG

+        <s></s>
+
71

+
WARNUNG

+
+
+        <s></s>
+
73

+
WARNUNG

+        <s></s>
+
74

+
WARNUNG

+        <s></s>
+
75

+
WARNUNG

+

+
+        <s></s>
+
76

+
WARNUNG

+        <s></s>
+
77

+
WARNUNG

+        <s></s>
+
78

+
WARNUNG

+
+        <s></s>
+
79

+
WARNUNG

+        <s></s>
+
80

+
WARNUNG

+        <s></s>
+
81

+
WARNUNG

+        <s></s>
+
82

+
WARNUNG

+

+

         <s></s>

0

-
WARNUNG

-
+
WARNUNG

         <s></s>

1

-
WARNUNG

-
+
WARNUNG

         <s></s>

2

-
WARNUNG

-
+
WARNUNG

         <s></s>

3

-
WARNUNG

-

+
WARNUNG

+

         <s></s>

4

-
WARNUNG

-
+
WARNUNG

         <s></s>
-

-

+

         <s></s>

6

-
WARNUNG

-
+
WARNUNG

         <s></s>

7

-
WARNUNG

-
+
WARNUNG

         <s></s>

8

-
WARNUNG

-
+
WARNUNG

         <s></s>
-

-

+

         <s></s>

CPU

-
Fehler%

-
-
-        <s></s>
-

-

+
Fehler%

+
+        <s></s>
+

+
         <s></s>

13

-
WARNUNG

-
-
+
WARNUNG

         <s></s><b1></b1>
-

+        <s></s>
+
verbleibend

+
Fehler

+
         <s></s>

Speicher

-
Fehler%

-
+
Fehler%

         <s2></s2>

-

-

+

+
         <s></s>

19

-
WARNUNG

-
-        <s></s>
-
Fehler

-        <b2></b2>
+
WARNUNG

+        <s></s><b2></b2>
+
Fehler

         <s></s>
-
WARNUNG

-

+
WARNUNG

+

+
         <s></s>

22

-
WARNUNG

-
+
WARNUNG

         <s></s>

Papierkorb

-
Fehler

-

+
Fehler

+
         <s></s>

25

-
WARNUNG

-
+
WARNUNG

         <s></s>

26

-
WARNUNG

-
+
WARNUNG

+
         <s></s>

PublikIP

-
Fehler

-
+
Fehler

         <s></s>

29

-
WARNUNG

-

+
WARNUNG

+
         <s></s>

31

-
WARNUNG

-
+
WARNUNG

         <s></s>32

+
         <s></s><b1></b1>
         <s></s><b1></b1>
-
OUTPUT

-

+
OUTPUT

+
         <s></s><b3></b3>
         <s2></s2><b3></b3>
         <s2></s2>
-

-

+

+

+
         <s></s><b2></b2>
         <s></s><b2></b2>

 """
-#

-#

-#
Wort des Tages

-#

-#

-#

-#

-#

-
-command: "pmset -g batt | grep \"%\" | awk 'BEGINN { FS = \";\" };{ print $1,$2,$3 }' | sed -e 's/-I/I/' -e 's/-0//' -e 's/;//' -e 's/;//' && ps aux  | awk 'BEGIN { sum = 0 }  { sum += $3 }; END { print sum }' && sysctl hw.ncpu | awk '{print $2}' && ps aux  | awk 'BEGIN { sum = 0 }  { sum += $4 }; END { print sum }' && du -ch ~/.Trash | grep total | cut -c 1-5"
+
+command: "pmset -g batt | grep \"%\" | awk 'BEGINN { FS = \";\" };{ print $1,$2,$3,$4 }' | sed -e 's/-I/I/' -e 's/-0//' -e 's/;//' -e 's/;//' && ps aux  | awk 'BEGIN { sum = 0 }  { sum += $3 }; END { print sum }' && sysctl hw.ncpu | awk '{print $2}' && ps aux  | awk 'BEGIN { sum = 0 }  { sum += $4 }; END { print sum }' && du -ch ~/.Trash | grep total | cut -c 1-5"
 update: (output, domEl) ->
 #   Initialise warnings
     warning=0;
@@ -332,20 +474,24 @@
     colorChange = (cell, colour) ->
         $(domEl).find("#{cell} s").css("border-bottom-color",   colour)
         $(domEl).find("#{cell} b").css("border-top-color",      colour)
+        $(domEl).find("#{cell} s1").css("border-bottom-color",  colour)
         $(domEl).find("#{cell} s2").css("border-bottom-color",  colour)
         $(domEl).find("#{cell} b1").css("border-top-color",     colour)
         $(domEl).find("#{cell} b2").css("border-top-color",     colour)
         $(domEl).find("#{cell} b3").css("border-top-color",     colour)
         $(domEl).find("#{cell}").css("background",              colour)
     warning_on = () ->
-        alert colorChange(".a0", "rgba(256,0,0,1)")
+        colorChange(".a0", "rgba(256,0,0,1)")
         $(domEl).find(".Wcontent").css("visibility","visible")
         $(domEl).find(".id").css("display","none")
+        colorChange("#15", "rgba(128,0,0,1)")
+        $(domEl).find("#15").css("visibility","visible")
     warning_off = () ->
-        alert colorChange(".a0", "rgba(10,10,10,1)")
+        colorChange(".a0", "rgba(10,10,10,1)")
         $(domEl).find(".Wcontent").css("visibility","hidden")
         $(domEl).find(".id").css("display","inline-block")
-
+        colorChange("#15", "rgba(128,0,0,0)")
+        $(domEl).find("#15").css("visibility","hidden")
 #   Processing time
     date = new Date()
     hour = date.getHours()
@@ -387,9 +533,20 @@
         Nwarning=0
 #   Deliver output
     $(domEl).find('.OP').text("#{output}")
-    $(domEl).find('.Bat').text("#{Batterievalues[0]}")
+    if (Batterievalues[0].indexOf("InternalBattery") > -1)
+        $(domEl).find('.Bat').text("innenbatterie")
+    else
+        $(domEl).find('.Bat').text("#{Batterievalues[0]}")
     $(domEl).find('.BatPer').text("#{Batterievalues[1]}")
-    $(domEl).find('.BatStatus').text("#{Batterievalues[2]}")
+    if (Batterievalues[2].indexOf("charged") > -1)
+        $(domEl).find('.BatStatus').text("geladen")
+    else if (Batterievalues[2].indexOf("discharging") > -1)
+        $(domEl).find('.BatStatus').text("entladen")
+    else if (Batterievalues[2].indexOf("finishing") > -1)
+        $(domEl).find('.BatStatus').text("beenden")
+    else
+        $(domEl).find('.BatStatus').text("#{Batterievalues[2]}")
+    $(domEl).find('.BatRe').text("#{Batterievalues[3]}")
     $(domEl).find('.CPUU').text("#{Math.floor(CPUUsage/CPUAmount)}")
     $(domEl).find('.MEMU').text("#{Math.floor(MemUsage)}")
     $(domEl).find('.sal').text("#{timeSegment}")
@@ -430,7 +587,8 @@
     else
         animation_off(".a0")
         warning_off()
-
+    if Bwarning == 1
+        15
 #   hover effects
     $('#IPCell').hover (->
             if Cwarning == 1
@@ -474,3 +632,9 @@
             alert colorChange(".a4", "rgba(10,10,10,0)")
             $(domEl).find(".a4x").css("visibility",               "hidden")
     )
+
+afterRender: (domEl) ->
+    $(domEl).on 'click', '.iTunesPre', => @run "osascript -e 'tell application \"iTunes\" to previous track'"
+    $(domEl).on 'click', '.iTunesNext', => @run "osascript -e 'tell application \"iTunes\" to next track'"
+    $(domEl).on 'click', '.iTunesPause', => @run "osascript -e 'tell application \"iTunes\" to pause'"
+    $(domEl).on 'click', '.iTunesPlay', => @run "osascript -e 'tell application \"iTunes\" to play'"


In invalid scope exception: include grammar metadata, ask for details

--- src/tokenized-buffer.coffee
+++ src/tokenized-buffer.coffee
@@ -391,7 +391,11 @@
         expectedScope = tag + 1
         poppedScope = scopes.pop()
         unless poppedScope is expectedScope
-          throw new Error("Encountered an invalid scope end id. Popped #{poppedScope}, expected to pop #{expectedScope}.")
+          error = new Error("Encountered an invalid scope end id. Popped #{poppedScope}, expected to pop #{expectedScope}.\nPlease report the grammar and contents of this file so we can fix this.")
+          error.metadata = {
+            grammarScopeName: @grammar.scopeName
+          }
+          throw error
     scopes

   indentLevelForRow: (bufferRow) ->


Note the synchronous loading of Tokenized Buffer

--- src/tokenized-buffer.coffee
+++ src/tokenized-buffer.coffee
@@ -30,6 +30,8 @@
   constructor: (optionsOrState) ->
     if optionsOrState instanceof telepath.Document
       @state = optionsOrState
+
+      # TODO: This needs to be made async, but should wait until the new Telepath changes land
       @buffer = project.bufferForPath(optionsOrState.get('bufferPath'))
     else
       { @buffer, tabLength } = optionsOrState


Strip out the call to "caller" when calling "caller".

--- application/chrome/content/wesabe.coffee
+++ application/chrome/content/wesabe.coffee
@@ -21,7 +21,9 @@

 wesabe =
   caller: ->
-    (require 'util/error').stackTrace new Error()
+    caller = (require 'util/error').stackTrace new Error()
+    caller.frames.shift() # remove this call
+    return caller

   getLineForStackFrame: (frame) ->
     (bootstrap.getContent frame.filename).split('\n')[frame.lineNumber]


Main loop: Allow draw callbacks to delete themselves.

--- engine/main_loop.coffee
+++ engine/main_loop.coffee
@@ -109,11 +109,13 @@

         for scene_name in @context.loaded_scenes
             scene = @context.scenes[scene_name]
-            for callback in scene.pre_draw_callbacks
-                callback scene, frame_duration
+            i = scene.pre_draw_callbacks.length+1
+            while --i != 0
+                scene.pre_draw_callbacks[scene.pre_draw_callbacks.length-i] scene, frame_duration

-            for logic_tick in scene.logic_ticks
-                logic_tick frame_duration
+            i = scene.logic_ticks.length+1
+            while --i != 0
+                scene.logic_ticks[scene.logic_ticks.length-i] frame_duration

             for p in scene.active_particle_systems
                 p._eval()
@@ -144,8 +146,9 @@

         for scene_name in @context.loaded_scenes
             scene = @context.scenes[scene_name]
-            for f in scene.post_draw_callbacks
-                f scene, frame_duration
+            i = scene.post_draw_callbacks.length+1
+            while --i != 0
+                scene.post_draw_callbacks[scene.post_draw_callbacks.length-i] scene, frame_duration

         @context.events.reset_frame_events()
         @frame_number += 1


Catch and report LESS compilation errors

--- src/plugins/enfield-generators.coffee
+++ src/plugins/enfield-generators.coffee
@@ -87,18 +87,22 @@
               paths: [path.dirname filepath]

             # Render CSS
-            less.render contents.toString(), options, (err, css) ->
-              if err
-                console.error "LESS Compilation Error: #{err.message}".red
-                return cb()
+            try
+              less.render contents.toString(), options, (err, css) ->
+                if err
+                  console.error "LESS Compilation Error: #{err.message}".red
+                  return cb()

-              outPath = filepath.replace /\.less$/, ''
-              site.pages.push {
-                published: true
-                url: outPath
-                raw_content: css
-                ext: '.css'
-              }
+                outPath = filepath.replace /\.less$/, ''
+                site.pages.push {
+                  published: true
+                  url: outPath
+                  raw_content: css
+                  ext: '.css'
+                }
+                cb()
+            catch err
+              console.error "LESS Compilation Error: #{err.message}".red
               cb()
         callback
       )


tłumaczenie pliku menu_win32

tłumaczenie pliku menu_win32

--- def/pl/menu_win32.cson
+++ def/pl/menu_win32.cson
@@ -5,246 +5,246 @@
       "New &Window":
         value: "Nowe okno(&W)"
       "&New File":
-        value: "New File(&N)"
+        value: "Nowy plik(&N)"
       "&Open File…":
-        value: "Open File(&O)..."
+        value: "Otwórz plik(&O)..."
       "Open Folder…":
-        value: "Open Folder..."
+        value: "Otwórz folder..."
       "Add Project Folder…":
-        value: "Add Project Folder..."
+        value: "Dodaj folder projektu..."
       "Reopen Project":
         value: "Ponownie otwórz projekt"
         submenu:
           "Clear Project History":
-            value: "Clear Project History"
+            value: "Wyczyść historię projektu"
       "Reopen Last &Item":
-        value: "Reopen Last Item(&I)"
+        value: "Otwórz ponownie plik(&I)"
       "Se&ttings":
-        value: "Settings(&T)..."
+        value: "Ustawienia(&T)..."
       "Config…":
-        value: "Config..."
+        value: "Konfiguracja..."
       "Init Script…":
-        value: "Init Script..."
+        value: "Skrypt Init..."
       "Keymap…":
-        value: "Keymap..."
+        value: "Mapowanie klawiszy..."
       "Snippets…":
-        value: "Snippets..."
+        value: "Wycinki..."
       "Stylesheet…":
         value: "Arkusz stylów..."
       "&Save":
-        value: "Save(&S)"
+        value: "Zapisz(&S)"
       "Save &As…":
-        value: "Save As(&A)..."
+        value: "Zapisz jako(&A)..."
       "Save A&ll":
-        value: "Save All(&L)"
+        value: "Zapisz wszystko(&L)"
       "&Close Tab":
-        value: "Close Tab(&C)"
+        value: "Zamknij zakładkę(&C)"
       "Close &Pane":
-        value: "Close Pane(&P)"
+        value: "Zamknij panel(&P)"
       "Clos&e Window":
-        value: "Close Window(&E)"
+        value: "Zamknij okno(&E)"
       "E&xit":
-        value: "Exit(&X)"
+        value: "Wyjdź(&X)"
       "Close All Tabs":
-        value: "Close All Tabs"
+        value: "Zamknij wszystkie zakładki"
   "&Edit":
-    value: "Edit(&E)"
+    value: "Edytuj(&E)"
     submenu:
       "&Undo":
-        value: "Undo(&U)"
+        value: "Cofnij(&U)"
       "&Redo":
-        value: "Redo(&R)"
+        value: "Ponów(&R)"
       "Cu&t":
-        value: "Cut(&T)"
+        value: "Wytnij(&T)"
       "&Copy":
-        value: "Copy(&C)"
+        value: "Kopiuj(&C)"
       "Copy Pat&h":
-        value: "Copy Path(&H)"
+        value: "Kopiuj ścieżkę(&H)"
       "&Paste":
-        value: "Paste(&P)"
+        value: "Wklej(&P)"
       "Select &All":
-        value: "Select All(&A)"
+        value: "Zaznacz wszystko(&A)"
       "&Toggle Comments":
-        value: "Toggle Comments(&T)"
+        value: "Przełącz na komentarz(&T)"
       Lines:
-        value: "Lines"
+        value: "Linie"
         submenu:
           "&Indent":
-            value: "Indent(&I)"
+            value: "Zwiększ wcięcie(&I)"
           "&Outdent":
-            value: "Outdent(&O)"
+            value: "Zmniejsz wcięcie(&O)"
           "&Auto Indent":
-            value: "Auto Indent(&A)"
+            value: "Automatyczne wcięcie(&A)"
           "Move Line &Up":
-            value: "Move Line Up(&U)"
+            value: "Przenieś linię do góry(&U)"
           "Move Line &Down":
-            value: "Move Line Down(&D)"
+            value: "Przenieś linię do dołu(&D)"
           "Du&plicate Lines":
-            value: "Duplicate Lines(&P)"
+            value: "Duplikuj linię(&P)"
           "D&elete Line":
-            value: "Delete Line(&E)"
+            value: "Skasuj linię(&E)"
           "&Join Lines":
-            value: "Join Lines(&J)"
+            value: "Połącz linię(&J)"
       Columns:
-        value: "Columns"
+        value: "Kolumny"
         submenu:
           "Move Selection &Left":
-            value: "Move Selection Left(&L)"
+            value: "Przenieś zaznaczenie na lewo(&L)"
           "Move Selection &Right":
-            value: "Move Selection Right(&R)"
+            value: "Przenieś zaznaczenie na prawo(&R)"
       Text:
-        value: "Text"
+        value: "Tekst"
         submenu:
           "&Upper Case":
-            value: "Upper Case(&U)"
+            value: "Wielkie litery(&U)"
           "&Lower Case":
-            value: "Lower Case(&L)"
+            value: "Małe litery(&L)"
           "Delete to End of &Word":
-            value: "Delete to End of Word(&W)"
+            value: "Skasuj do końca słowa(&W)"
           "Delete to Previous Word Boundary":
-            value: "Delete to Previous Word Boundary"
+            value: "Skasuj do granicy poprzedniego słowa"
           "Delete to Next Word Boundary":
-            value: "Delete to Next Word Boundary"
+            value: "Skasuj do granicy następnego słowa"
           "&Delete Line":
-            value: "Delete Line(&D)"
+            value: "Skasuj linię(&D)"
           "&Transpose":
-            value: "Transpose(&T)"
+            value: "Transponuj(&T)"
       Folding:
-        value: "Folding"
+        value: "Zwijanie kodu"
         submenu:
           "&Fold":
-            value: "Fold(&F)"
+            value: "Zwiń(&F)"
           "&Unfold":
-            value: "Unfold(&U)"
+            value: "Rozwiń(&U)"
           "Unfold &All":
-            value: "Unfold All(&A)"
+            value: "Rozwiń wszystko(&A)"
           "Fol&d All":
-            value: "Fold All(&D)"
+            value: "Zwiń wszystko(&D)"
           "Fold Level 1":
-            value: "Fold Level 1"
+            value: "Zwijanie poziom 1"
           "Fold Level 2":
-            value: "Fold Level 2"
+            value: "Zwijanie poziom 2"
           "Fold Level 3":
-            value: "Fold Level 3"
+            value: "Zwijanie poziom 3"
           "Fold Level 4":
-            value: "Fold Level 4"
+            value: "Zwijanie poziom 4"
           "Fold Level 5":
-            value: "Fold Level 5"
+            value: "Zwijanie poziom 5"
           "Fold Level 6":
-            value: "Fold Level 6"
+            value: "Zwijanie poziom 6"
           "Fold Level 7":
-            value: "Fold Level 7"
+            value: "Zwijanie poziom 7"
           "Fold Level 8":
-            value: "Fold Level 8"
+            value: "Zwijanie poziom 8"
           "Fold Level 9":
-            value: "Fold Level 9"
+            value: "Zwijanie poziom 9"
       "Reflow Selection":
-        value: "Reflow Selection"
+        value: "Usuń formatowanie"
       Bookmark:
-        value: "Bookmark"
+        value: "Zakładki"
         submenu:
           "View All":
-            value: "View All"
+            value: "Pokaż wszystkie"
           "Toggle Bookmark":
-            value: "Toggle Bookmark"
+            value: "Przełącz zakładkę"
           "Jump to Next Bookmark":
-            value: "Jump to Next Bookmark"
+            value: "Skocz do następnej zakładki"
           "Jump to Previous Bookmark":
-            value: "Jump to Previous Bookmark"
+            value: "Skocz do poprzedniej zakładki"
       "Select Encoding":
-        value: "Select Encoding"
+        value: "Wybierz kodowanie"
       "Go to Line":
-        value: "Go to Line"
+        value: "Idź do linii"
       "Select Grammar":
-        value: "Select Grammar"
+        value: "Sprawdź gramatykę składni"
   "&View":
-    value: "View(&V)"
+    value: "Widok(&V)"
     submenu:
       "Toggle &Full Screen":
-        value: "Toggle Full Screen(&F)"
+        value: "Przełącz na pełny ekran(&F)"
       "Toggle Menu Bar":
-        value: "Toggle Menu Bar"
+        value: "Wyłącz pasek menu"
       Panes:
-        value: "Panes"
+        value: "Panele"
         submenu:
           "Split Up":
-            value: "Split Up"
+            value: "Podziel na górze"
           "Split Down":
-            value: "Split Down"
+            value: "Podziel na dole"
           "Split Left":
-            value: "Split Left"
+            value: "Podziel po lewej"
           "Split Right":
-            value: "Split Right"
+            value: "Podziel po prawej"
           "Focus Next Pane":
-            value: "Focus Next Pane"
+            value: "Ustaw się na następnym panelu"
           "Focus Previous Pane":
-            value: "Focus Previous Pane"
+            value: "Ustaw się na poprzednim panelu"
           "Focus Pane Above":
-            value: "Focus Pane Above"
+            value: "Ustaw się na górnym panelu"
           "Focus Pane Below":
-            value: "Focus Pane Below"
+            value: "Ustaw się na dolnym panelu"
           "Focus Pane On Left":
-            value: "Focus Pane On Left"
+            value: "Ustaw się na lewym panelu"
           "Focus Pane On Right":
-            value: "Focus Pane On Right"
+            value: "Ustaw się na prawym panelu"
           "Close Pane":
-            value: "Close Pane"
+            value: "Zamknij panel"
       Developer:
-        value: "Developer"
+        value: "Opcje programistyczne"
         submenu:
           "Open In &Dev Mode…":
-            value: "Open In Dev Mode(&D)..."
+            value: "Otwórz w trybie programistycznym(&D)..."
           "&Reload Window":
-            value: "Reload Window(&R)"
+            value: "Przeładuj okno(&R)"
           "Run Package &Specs":
-            value: "Run Package Specs(&S)"
+            value: "Uruchom specyfikację pakietu(&S)"
           "Run &Benchmarks":
-            value: "Run Benchmarks(&B)"
+            value: "Uruchom benchmark(&B)"
           "Toggle Developer &Tools":
-            value: "Toggle Developer Tools(&T)"
+            value: "Narzędzia programistyczne(&T)"
       "&Increase Font Size":
-        value: "Increase Font Size(&I)"
+        value: "Zwiększ rozmiar czcionki(&I)"
       "&Decrease Font Size":
-        value: "Decrease Font Size(&D)"
+        value: "Zmniejsz rozmiar czcionki(&D)"
       "Re&set Font Size":
-        value: "Reset Font Size(&S)"
+        value: "Zresetuj rozmiar czcionki(&S)"
       "Toggle Soft &Wrap":
-        value: "Toggle Soft Wrap(&W)"
+        value: "Przełącz na miękkie zawijanie(&W)"
       "Toggle Command Palette":
-        value: "Toggle Command Palette"
+        value: "Przełącz na linię poleceń"
       "Toggle Tree View":
-        value: "Toggle Tree View"
+        value: "Przełącz na widok drzewa"
   "&Selection":
-    value: "Selection(&S)"
+    value: "Zaznaczenia(&S)"
     submenu:
       "Add Selection &Above":
-        value: "Add Selection Above(&A)"
+        value: "Dodaj zaznaczenie powyżej(&A)"
       "Add Selection &Below":
-        value: "Add Selection Below(&B)"
+        value: "Dodaj zaznaczenie poniżej(&B)"
       "S&plit into Lines":
-        value: "Split into Lines(&P)"
+        value: "Podziel na linie(&P)"
       "Single Selection":
-        value: "Single Selection"
+        value: "Pojedyncze zaznaczenie"
       "Select to &Top":
-        value: "Select to Top(&T)"
+        value: "Zaznacz do góry(&T)"
       "Select to Botto&m":
-        value: "Select to Bottom(&M)"
+        value: "Zaznacz do dołu(&M)"
       "Select &Line":
-        value: "Select Line(&L)"
+        value: "Zaznacz linię(&L)"
       "Select &Word":
-        value: "Select Word(&W)"
+        value: "Zaznacz słowo(&W)"
       "Select to Beginning of W&ord":
-        value: "Select to Beginning of Word(&O)"
+        value: "Zaznacz do początku słowa(&O)"
       "Select to Beginning of L&ine":
-        value: "Select to Beginning of Line(&I)"
+        value: "Zaznacz do początku linii(&I)"
       "Select to First &Character of Line":
-        value: "Select to First Character of Line(&C)"
+        value: "Zaznacz do pierwszego znaku w linii(&C)"
       "Select to End of Wor&d":
-        value: "Select to End of Word(&D)"
+        value: "Zaznacz do końca słowa(&D)"
       "Select to End of Lin&e":
-        value: "Select to End of Line(&E)"
+        value: "Zaznacz do końca linii(&E)"
       "Select Inside Brackets":
-        value: "Select Inside Brackets"
+        value: "Zaznacz wewnątrz nawiasów"
   "F&ind":
     value: "Szukaj(&I)"
     submenu:


'npm run bundle' on Windows fixed

'npm run bundle' on Windows fixed

--- src/bundle-builder/index.coffee
+++ src/bundle-builder/index.coffee
@@ -4,15 +4,12 @@
 pathUtils = require 'path'
 Module = require 'module'
 cp = require 'child_process'
-os = require 'os'

 {utils, log, assert} = Neft

 release = require './release'
 minify = require './minify'
 bundle = require './bundle'
-
-isWin32 = os.platform() is 'win32'

 module.exports = (opts, callback) ->
 	assert.isPlainObject opts
@@ -37,8 +34,6 @@
 	running = true
 	processPath = pathUtils.join __dirname, './process.js'
 	cmd = 'node'
-	if isWin32
-		cmd += '.cmd'
 	childProcess = cp.spawn cmd,
 		['--harmony', processPath, processOptsBase64],
 		stdio: ['ipc']


#16 typeahead styling added

#16 typeahead styling added

--- src/client/personal_stat.coffee
+++ src/client/personal_stat.coffee
@@ -20,6 +20,8 @@
             source: fetchedNames.ttAdapter()
         }
     )
+
+    $(".twitter-typeahead").css('display', 'block')

     $("input[name='player-name']").keydown(
         (event) ->


Md5Service documentation

Md5Service documentation

--- lib/layervault/services/md5.coffee
+++ lib/layervault/services/md5.coffee
@@ -1,9 +1,19 @@
 crypto  = require 'crypto'
 fs      = require 'fs'

+# Simple service that, given a path to a file, calculates
+# its MD5.
 module.exports = class Md5Service
+  # Constructs a new Md5Service.
+  #
+  # @param [String] file The path to the file.
   constructor: (@file) ->

+  # Runs the MD5 calculation by reading the file with a ReadStream,
+  # and passes the chunks to our MD5 function. This is done
+  # asynchronously. The resulting MD5 is given in hex form.
+  #
+  # @param [Function] cb The finished callback.
   calculate: (cb) ->
     md5 = crypto.createHash 'md5'
     s = fs.ReadStream(@file)


remove debugger

remove debugger

--- src/services/alerts/alerts.svc.coffee
+++ src/services/alerts/alerts.svc.coffee
@@ -55,7 +55,6 @@
       $http.post(ImpacRoutes.kpis.alerts.create(kpiId), params)

     @update = (alertId, params)->
-      debugger;
       $http.put(ImpacRoutes.kpis.alerts.update(alertId), params)

     @delete = (alertId)->


add a clarifying comment

add a clarifying comment

--- src/smc-webapp/jupyter/actions.coffee
+++ src/smc-webapp/jupyter/actions.coffee
@@ -106,6 +106,8 @@
         @syncdb.on('change', @_syncdb_change)

         @syncdb.once 'change', =>
+            # Important -- this also gets run on the backend, where
+            # @redux.getProjectActions(project_id) is maybe undefined...
             @redux.getProjectActions(project_id)?.log_opened_time(path)


Persist logger enabled states in session storage

--- src/trix/core/utilities/logger.coffee
+++ src/trix/core/utilities/logger.coffee
@@ -11,20 +11,37 @@
     @get(name).log(args...)

   constructor: (@name, @console, enabled) ->
+    enabled = readLoggerEnabledStateFromSessionStorage(@name) unless enabled?
     @disable() unless enabled

   enable: ->
     if @disabledConsole? and not @isEnabled()
       @console = @disabledConsole
       delete @disabledConsole
+      writeLoggerEnabledStateToSessionStorage(@name, true)

   disable: ->
     if @isEnabled()
       @disabledConsole = @console
       delete @console
+      writeLoggerEnabledStateToSessionStorage(@name, false)

   isEnabled: ->
     @console?
+
+  readLoggerEnabledStateFromSessionStorage = (name) ->
+    key = keyForLoggerName(name)
+    window.sessionStorage?[key] is "true"
+
+  writeLoggerEnabledStateToSessionStorage = (name, enabled) ->
+    key = keyForLoggerName(name)
+    if enabled
+      window.sessionStorage?[key] = "true"
+    else
+      delete window.sessionStorage?[key]
+
+  keyForLoggerName = (name) ->
+    "trix/loggers/#{name}/enabled"

   @proxyMethod "console?.log"
   @proxyMethod "console?.warn"
@@ -35,3 +52,4 @@
   @proxyMethod "console?.trace"
   @proxyMethod "console?.time"
   @proxyMethod "console?.timeEnd"
+


Strip comment nodes when parsing

Strip comment nodes when parsing

--- src/trix/utilities/html_parser.coffee
+++ src/trix/utilities/html_parser.coffee
@@ -123,12 +123,24 @@
   sanitizeHTML = (html) ->
     {body} = document.implementation.createHTMLDocument("")
     body.innerHTML = html
-    walker = walkTree(body, onlyNodesOfType: "element")
+
+    commentNodes = []
+    walker = walkTree(body)
+
     while walker.nextNode()
-      element = walker.currentNode
-      for {name} in [element.attributes...]
-        unless name in allowedAttributes or name.indexOf("data-trix") is 0
-          element.removeAttribute(name)
+      node = walker.currentNode
+      switch node.nodeType
+        when Node.ELEMENT_NODE
+          element = node
+          for {name} in [element.attributes...]
+            unless name in allowedAttributes or name.indexOf("data-trix") is 0
+              element.removeAttribute(name)
+        when Node.COMMENT_NODE
+          commentNodes.push(node)
+
+    for node in commentNodes
+      node.parentNode.removeChild(node)
+
     body.innerHTML

   isExtraBR = (element) ->


Twitter adapter's new methods now commented

--- lib/adapters/twitter_in.coffee
+++ lib/adapters/twitter_in.coffee
@@ -74,7 +74,9 @@
         @applyConfig =>
           super

-
+  #
+  # @param cb {function} Callback after config is applied
+  #
   applyConfig: (cb) ->
     if @properties.tags and @properties.tags isnt ""
       @twitProperties.track = @properties.tags
@@ -161,6 +163,12 @@
       @properties[props] = properties[props]
     @start()

+  #
+  #   getIdForScreenName(properties)
+  #   Gets twitter user ID for every screen name specified
+  #   @param userIdTab {array} array of user IDs
+  #   @param cb {function} callback to apply once function is done
+  #
   getIdForScreenName: (userIdTab, cb) ->
     unless @twit
       @twit = new twitter(


一台电脑多个ide同时测试前端代码

一台电脑多个ide同时测试前端代码

--- lib/build/build-manager.coffee
+++ lib/build/build-manager.coffee
@@ -28,10 +28,16 @@
       console.log "开始压缩..."
       buildWizard.destroy()
       buildStateView.attach()
-
+
       require('../../utils/zip')(atom.project.path,"./","foreveross.zip").then (zip_path) ->_.extend(result, asset: zip_path)
+    .then (result) ->
+      console.log "结束压缩...#{result}"
+      Q.Promise (resolve, reject, notify) ->
+        buildStateView.socket.on "resSocketId",(sid)->
+          console.log "resSocketId:#{sid}"
+          resolve(_.extend(result, socketId: sid))
+        buildStateView.socket.emit "reqSocketId"
     .then (result) =>
-      console.log "结束压缩...#{result}"
       @sendBuildRequest(result)
     .then (result) ->
       zip_path = "#{atom.project.path}/foreveross.zip"
@@ -82,7 +88,7 @@
         form.append "version","#{options.version}"
         form.append "build","#{options.build}"
         form.append "title","#{options.title}"
-
+        form.append "socketId","#{options.socketId}"

     else
       Q.Promise (resolve, reject, notify) =>
@@ -116,6 +122,6 @@
         form.append "title","#{options.title}"
         form.append "version","#{options.version}"
         form.append "build","#{options.build}"
-
-
+
         form.append "asset",fs.createReadStream(options.asset)
+        form.append "socketId","#{options.socketId}"


Resolved the problem that the height of the line increase by one pixel when underline is enabled

By default, height of border, padding, and margin is 0, when underline is enabled, the border-bottom set to 1px, then the current line has been  lifted.  Set margin-bottom to -1px can resolve it.

Signed-off-by: Huang Cheng <8ef188e1917e6f607a1ed78972b8f4f0faf9504a@gmail.com>

--- lib/highlight-line-view.coffee
+++ lib/highlight-line-view.coffee
@@ -82,7 +82,9 @@
       @showHighlight()

   resetBackground: ->
-    $('.line').css('background-color', '').css('border-bottom','')
+    $('.line').css('background-color', '')
+              .css('border-bottom','')
+              .css('margin-bottom','')

   showHighlight: =>
     bgColor = @wantedColor('backgroundRgbColor')
@@ -96,7 +98,8 @@
       $(lineElement).attr(
         'style',
         "background-color: #{bgRgba};" +
-          "border-bottom: 1px #{underlineStyleInUsed} #{ulRgba};")
+          "border-bottom: 1px #{underlineStyleInUsed} #{ulRgba};" +
+          "margin-bottom: -1px;")

   wantedColor: (color) ->
     wantedColor = atom.config.get("highlight-line.#{color}")


:bug: Handle serialized state in indexeddb

--- lib/project-finder-view.coffee
+++ lib/project-finder-view.coffee
@@ -84,18 +84,25 @@
               resolve(rows)

       .then (rows) =>
+        rows = rows.map (row) =>
+          if typeof row.value == "string" and row.isJSON
+            JSON.parse(row.value)
+
+          else
+            row.value
+
         rows = _.filter rows, (row) =>
           row.value.project? and
           not _.isEqual(row.value.project.paths, atom.project.getPaths())

-        items = rows.map (row) =>
+        rows = rows.map (row) =>
           # NOTE: Currently the name of the project
           #       is just set to the first path's basename
           name: path.basename(row.value.project.paths[0])
           paths: row.value.project.paths

         # Unique project listing
-        @setItems items
+        @setItems rows

   confirmed: (item) ->
     @hide()


Remove unnecessary alias

Remove unnecessary alias

--- library/gearing/service.coffee
+++ library/gearing/service.coffee
@@ -75,8 +75,8 @@
         presource = (p) -> gresource = pathname.match(p)
         pdomain = _.find(domains, pdomain)
         presource = _.find(resources, presource)
-        assert.ok(gdomain isnt null, "missing domain")
-        assert.ok(gresource isnt null, "missing resource")
+        assert(gdomain isnt null, "missing domain")
+        assert(gresource isnt null, "missing resource")
         return domain: gdomain, resource: gresource

     # This is a very basic method that adds the specified regular


Predictable screening behavior

Predictable screening behavior

--- library/membrane/duplex.coffee
+++ library/membrane/duplex.coffee
@@ -61,11 +61,11 @@
     @abstract yes

     # A usable hook that gets asynchronously invoked once a new
-    # channel (socket) gets connected to the Socket.IO hub in the
-    # context of the current service. The channel will be allowed
-    # to proceed only when prescreen calls the next procedure. If
-    # you wish to decline, just don't call `next` and close socket.
-    prescreen: (context, socket, next) -> next()
+    # channel (socket) gets connected and acknowledges by the server.
+    # The method gets a set of parameters that maybe be useful to
+    # have by the actual implementation. Please remember thet the
+    # method is asynchronously wired, so be sure to call `next`.
+    connected: (context, socket, next) -> next()

     # A usable hook that gets asynchronously invoked once a new
     # channel (socket) gets past the prescreening hook and is rated
@@ -73,13 +73,6 @@
     # place to implementation various schemes for authorization. If
     # you wish to decline, just don't call `next` and close socket.
     screening: (context, socket, binder, next) -> next()
-
-    # A usable hook that gets asynchronously invoked once a new
-    # channel (socket) gets connected and acknowledges by the server.
-    # The method gets a set of parameters that maybe be useful to
-    # have by the actual implementation. Please remember thet the
-    # method is asynchronously wired, so be sure to call `next`.
-    connected: (context, socket, next) -> next()

     # An internal, static method that is used to obtain gurading
     # domains for each of the declared server site providers. Please
@@ -213,12 +206,10 @@
         pure = /[a-zA-Z0-9/-_]+/.test @location()
         assert pure, "location is not pure enough"
         context.on "connection", (socket) =>
-            prescreen = @upstreamAsync "prescreen", =>
-                socket.on "screening", (binder, next) =>
-                    screening = @upstreamAsync "screening", =>
-                        @publishProviders context, socket, next
-                    screening context, socket, binder
-            prescreen context, socket
+            socket.on "screening", (binder, next) =>
+                screening = @upstreamAsync "screening", =>
+                    @publishProviders context, socket, next
+                screening context, socket, binder
         return next()

     # A hook that will be called prior to unregistering the service


minor add up

minor add up

--- library/nucleus/scoping.coffee
+++ library/nucleus/scoping.coffee
@@ -45,7 +45,7 @@
 # and the end user application constructed within the framework. It
 # is both an abstract base class as well as a ready to use bootstrap.
 # Please refer to the documentation of the methods for more info.
-module.exports.Scope = class Scope extends Archetype
+assert module.exports.Scope = class Scope extends Archetype

     # Construct a new scope, using the supplied tag (a short name)
     # and a synopsis (short description of the scope) parameters.


Make @res and @dom inheritable ;)

Make @res and @dom inheritable ;)

--- library/nucleus/service.coffee
+++ library/nucleus/service.coffee
@@ -129,8 +129,8 @@
         associate = "Associating #{inspected} resource with #{identify}"
         notRegexp = "The #{inspected} is not a valid regular expression"
         assert _.isRegExp(pattern), notRegexp
-        (@resources ?= []).push pattern
-        logger.debug associate.grey; @
+        @resources = (@resources or []).concat pattern
+        logger.debug associate.grey; this

     # This is a very basic method that adds the specified regular
     # expression pattern to the list of permitted domain patterns.
@@ -138,6 +138,7 @@
     # Supports implicit extraction of captured groups in the match.
     # Use this to configure what domains should match with service.
     @domain: (pattern) ->
+        previous = @domains or []
         identify = @identify().underline
         regexify = (s) -> new RegExp "^#{RegExp.escape(s)}$"
         pattern = regexify pattern if _.isString pattern
@@ -145,8 +146,8 @@
         associate = "Associating #{inspected} resource with #{identify}"
         notRegexp = "The #{inspected} is not a valid regular expression"
         assert _.isRegExp(pattern), notRegexp
-        (@domains ?= []).push pattern
-        logger.debug associate.grey; @
+        @domains = (@domains or []).concat pattern
+        logger.debug associate.grey; this

     # This method determines whether the supplied HTTP request
     # matches this service. This is determined by examining the


slidingBarView: warn on invalid internalViews

--- coffee/src/views/sliding_bar_view.coffee
+++ coffee/src/views/sliding_bar_view.coffee
@@ -46,6 +46,9 @@
     for view in @internalViews
       if view instanceof Backbone.View
         @$('.internal-views').append view.render().el
+      else
+        console.log 'WARNING: SlidingBarView only supports internalViews derived
+            from Backbone.View'

     @


insert_stops.coffee: Add M route

insert_stops.coffee: Add M route

--- Web/insert_stops.coffee
+++ Web/insert_stops.coffee
@@ -11,8 +11,8 @@

       # two helper functions to sort the bus routes
       replaceroute = (a) ->
-          routeorder = ["15", "80", "3", "14"]
-          tempval = ["-4","-3","-2","-1"]
+          routeorder = ["15", "80", "3", "14", "M"]
+          tempval = ["-4","-3","-2","-1", "0"]
           index = routeorder.indexOf(a)
           return tempval[index] if index >= 0
           a


Refresh task view after killing (instead of redirecting to active task list)

--- SingularityUI/app/views/task.coffee
+++ SingularityUI/app/views/task.coffee
@@ -95,6 +95,6 @@
                 callback: (confirmed) =>
                     return unless confirmed
                     taskModel.destroy()
-                    app.router.navigate 'tasks', trigger: true
+                    setTimeout (=> @refresh()), 500

 module.exports = TaskView


prevent selecting text on buttons

prevent selecting text on buttons

--- app/assets/javascripts/components/text-entry.cjsx
+++ app/assets/javascripts/components/text-entry.cjsx
@@ -17,6 +17,7 @@
   handleTranscription: ->
     console.log 'handleTranscription()'
     unless @nextStepAvailable()
+      console.log 'FOOODSKJLHDLKJSHDLKSJDHKSJDH ', $('transcribe-input').val()
       @props.recordTranscription('FOO', 'BAR')
       return
     @setState currentStep: @state.currentStep + 1


EDSC-11: remove debugging comments

EDSC-11: remove debugging comments

--- app/assets/javascripts/modules/spinners.js.coffee
+++ app/assets/javascripts/modules/spinners.js.coffee
@@ -16,7 +16,6 @@
     # Show spinner at start of ajax request
     $(document).ajaxSend (event, jqxhr, settings) ->
       url = settings.url
-      # alert url

       $(facets).addClass('busy') if url.indexOf('dataset_facets.json') > -1
       if url.indexOf('datasets.json') > -1
@@ -39,7 +38,6 @@
     # Hide spinner when ajax request finishes
     $(document).ajaxComplete (event, jqxhr, settings) ->
       url = settings.url
-      # alert 'Stopped ' + url

       $(facets).removeClass('busy') if url.indexOf('dataset_facets.json') > -1
       if url.indexOf('datasets.json') > -1


replace add event by send event

replace add event by send event

--- app/assets/javascripts/s3_direct_upload.js.coffee
+++ app/assets/javascripts/s3_direct_upload.js.coffee
@@ -22,7 +22,7 @@
   settings =
     path: ''
     additional_data: null
-    before_add: null
+    before_send: null
     remove_completed_progress_bar: true
     remove_failed_progress_bar: false
     image_max_width: 1200
@@ -39,13 +39,10 @@
       imageMaxHeight: settings.image_max_height
       disableImagePreview: true

-      # add: (e, data) ->
-      #   current_files.push data
-      #   file = data.files[0]
-      #   unless settings.before_add and not settings.before_add(file)
-      #     data.context = $(tmpl("template-upload", file)) if $('#template-upload').length > 0
-      #     $uploadForm.append(data.context)
-      #     data.submit()
+      send: (e, data) ->
+        file = data.files[0]
+        if settings.before_send
+          settings.before_send(file)

       start: (e) ->
         $uploadForm.trigger("s3_uploads_start", [e])


remove "alpha" from default drug search list

--- app/assets/javascripts/search_interactions.coffee
+++ app/assets/javascripts/search_interactions.coffee
@@ -26,7 +26,7 @@
     ta.data('typeahead').source = data

 $('#drugSearch').click ->
-  example_ids = ['SUNITINIB','ZALCITABINE','LINCOCIN', 'ALPHA','TRASTUZUMAB','PHLORETIN','NOTREAL'].join "\n"
+  example_ids = ['SUNITINIB','ZALCITABINE','LINCOCIN','TRASTUZUMAB','PHLORETIN','NOTREAL'].join "\n"
   $('#ids_text').text("Drugs")
   $.get '/drug_names.json', (data)->
     ta.data('typeahead').source = data


Use TextEditor::onDidDestroy

Use TextEditor::onDidDestroy

--- lib/bracket-matcher.coffee
+++ lib/bracket-matcher.coffee
@@ -43,7 +43,7 @@
     @subscriptions.add atom.config.observe 'bracket-matcher.autocompleteSmartQuotes', (newValue) =>
       @toggleQuotes(newValue)

-    @subscriptions.add @editor.on 'destroyed', => @unsubscribe()
+    @subscriptions.add @editor.onDidDestroy => @unsubscribe()

   insertText: (text, options) =>
     return true unless text


Fix WhatsApp url

Fix WhatsApp url

--- app/assets/javascripts/social-share-button.coffee
+++ app/assets/javascripts/social-share-button.coffee
@@ -102,8 +102,8 @@
       when "telegram"
         SocialShareButton.openUrl("https://telegram.me/share/url?text=#{title}&url=#{url}")
       when "whatsapp_app"
-        whatsapp_app_url = "whatsapp://send?text=#{title}&url=#{url}"
+        whatsapp_app_url = "whatsapp://send?text=#{title}%0A#{url}"
         window.open(whatsapp_app_url, '_top')
       when "whatsapp_web"
-        SocialShareButton.openUrl("https://web.whatsapp.com/send?text=#{title}&url=#{url}")
+        SocialShareButton.openUrl("https://web.whatsapp.com/send?text=#{title}%0A#{url}")
     false