improvment of map start position

improvment of map start position

--- client/script.coffee
+++ client/script.coffee
@@ -6,9 +6,8 @@
           lng1.toFixed(4) is lng2.toFixed(4))
 onPosition = ->
 _geolocation = (callback) ->
-  if tracking
-    navigator.geolocation.getCurrentPosition callback, (err) ->
-      console.error "Error when retrieving location '#{err.message}'."
+  navigator.geolocation.getCurrentPosition callback, (err) ->
+    console.error "Error when retrieving location '#{err.message}'."
 geolocation = (callback) ->
   if lastPosition? then callback lastPosition else _geolocation callback
 cachePosition = ->
@@ -17,9 +16,7 @@
     onPosition(position)

 socket = io.connect '/'
-socket.on 'new geo', (geoJson) ->
-  console.log "Got geo from car.", geoJson
-  addGeoms geoJson
+socket.on 'new geo', (geoJson) -> addGeoms geoJson

 tracking = no
 deviceName = localStorage.getItem 'device-name'
@@ -42,7 +39,7 @@
 onPosition = (position) ->
   if loggedIn() and not comparePosition(lastSentPosition, position)
     {latitude:lat, longitude:lng} = position.coords
-    socket.emit 'new geo',
+    geoJson =
       geometry:
         type: 'Point'
         coordinates: [lng, lat]
@@ -53,7 +50,9 @@
         timestamp: Date.now()
         hdop: -1
         web: true
+    socket.emit 'new geo', geoJson
     lastSentPosition = position
+    addGeoms geoJson

 getGeos = (query, callback) ->
   $.ajax
@@ -110,15 +109,16 @@
 lineLayer = L.layerGroup()
 pointLayer = L.layerGroup().addTo map

-#geolocation (position) ->
-#  {latitude:lat, longitude:lng} = position.coords
-#  map.setView [lat, lng], 13
-
 # Get all logged positions for the day
 getFrom = new Date()
 getFrom.setHours 0,0,0,0
 getGeos {created: {$gt: getFrom}}, (geoJson) ->
   addGeoms geoJson.features
-  map.fitBounds new L.LatLngBounds(line._point.getLatLng() for name, line of history)
+  try
+    map.fitBounds new L.LatLngBounds(line._point.getLatLng() for name, line of history)
+  catch err
+    geolocation (position) ->
+      {latitude:lat, longitude:lng} = position.coords
+      map.setView [lat, lng], 13

 $('#start-position').removeClass('nodisplay') if location.hash is '#tracking'


improve sorting

improve sorting

--- prviewer.coffee
+++ prviewer.coffee
@@ -201,28 +201,19 @@
         cb err, pulls

     # Sort the pulls based on update time.
-    # TODO: Doesn't quite work...
     (pulls, cb) ->
-
       pulls.sort (a, b) ->
-        if a.class == 'info'
-          return -1 # Always at top.
-        else if a.class == b.class
-          if moment(a.updated_at).unix() > moment(b.updated_at).unix()
-            return -1
-          else
-            return 1
+        aTime = moment(a.updated_at).unix()
+        bTime = moment(b.updated_at).unix()
+        if a.class == 'info' and b.class != 'info'
+          # Always at top.
+          return -1
+        else if a.class == 'ignore' and b.class != 'ignore'
+          # Always at bottom.
+          return 1
         else
-          if a.class == 'warning'
-            return -1
-          else
-            return 1
-
-      pulls.sort (a, b) ->
-        if a.class == 'ignore'
-          return 1 # Always at bottom.
-        else
-          return -1
+          # Otherwise just sort by time.
+          return if aTime > bTime then -1 else 1

       cb null, pulls


stacktemplateview: set readonly and listen events after editor ready

--- client/stack-editor/lib/editor/stacktemplateview.coffee
+++ client/stack-editor/lib/editor/stacktemplateview.coffee
@@ -2,12 +2,12 @@
 KDButtonView            = kd.ButtonView
 Encoder                 = require 'htmlencode'
 curryIn                 = require 'app/util/curryIn'
-StackBaseEditorTabView  = require './stackbaseeditortabview'
 StackTemplateEditorView = require './stacktemplateeditorview'
+isMine  = require 'app/util/isMine'
+isAdmin = require 'app/util/isAdmin'

-module.exports = class StackTemplateView extends StackBaseEditorTabView
-
+module.exports = class StackTemplateView extends kd.View

   constructor: (options = {}, data) ->

@@ -56,3 +56,22 @@
         kd.utils.wait 250, => @editorView.resize()

     @editorView.on 'click', => @emit 'HideOutputView'
+
+
+  viewAppended: ->
+
+    super
+    { stackTemplate } = @getData()
+    isMine = isAdmin() or isMine(stackTemplate)
+    @editorView.ready =>
+      @setReadOnly()  unless isMine
+      @listenEditorEvents()
+
+
+  listenEditorEvents: ->
+    @on 'FocusToEditor', => @editorView.setFocus yes
+
+
+  setReadOnly: ->
+    @setClass 'isntMine'
+    @editorView.aceView.ace.editor.setReadOnly yes


Add test for duplicate groups in sync mode, refs #269

--- spec/Helpers.coffee
+++ spec/Helpers.coffee
@@ -71,7 +71,7 @@
       y = null
       z = null
       p = null
-      before (done) ->
+      beforeEach (done) ->
         c = new noflo.Component
         c.inPorts.add 'x',
           required: true
@@ -92,6 +92,8 @@
         c.inPorts.z.attach z
         c.outPorts.point.attach p
         done()
+      afterEach ->
+        c.outPorts.point.detach p

       it 'should pass data and groups to the callback', (done) ->
         src =
@@ -134,7 +136,6 @@
           z.disconnect()

       it 'should work without a group provided', (done) ->
-        p.removeAllListeners()
         noflo.helpers.WirePattern c,
           in: ['x', 'y', 'z']
           out: 'point'
@@ -224,7 +225,6 @@
             callback()
           , 100

-        p.removeAllListeners()
         counter = 0
         hadData = false
         p.on 'begingroup', (grp) ->
@@ -262,7 +262,6 @@
         , (data, groups, out) ->
           out.send { x: data.x, y: data.y }

-        p.removeAllListeners()
         counter = 0
         hadData = false
         p.on 'begingroup', (grp) ->
@@ -297,7 +296,6 @@
         , (data, groups, out) ->
           out.send { x: data.x, y: data.y, z: data.z }

-        p.removeAllListeners()
         groups = []
         p.on 'begingroup', (grp) ->
           groups.push grp
@@ -333,7 +331,6 @@
         , (data, groups, out) ->
           out.send { x: data.x, y: data.y, z: data.z }

-        p.removeAllListeners()
         groups = []
         p.on 'begingroup', (grp) ->
           groups.push grp
@@ -378,7 +375,6 @@
       c.outPorts.point.attach p

       it 'should correctly bind component to `this` context', (done) ->
-        p.removeAllListeners()
         noflo.helpers.WirePattern c,
           in: ['x', 'y', 'z']
           out: 'point'
@@ -398,7 +394,6 @@
         z.disconnect()

       it 'should correctly bind component to `this` context in async mode', (done) ->
-        p.removeAllListeners()
         noflo.helpers.WirePattern c,
           in: ['x', 'y', 'z']
           async: true
@@ -760,7 +755,8 @@
             d1: input.data1
             d2: input.data2
           out.send res
-
+        err.on 'data', (data) ->
+          done data
         out.once 'data', (data) ->
           chai.expect(data).to.be.an 'object'
           chai.expect(data.p1).to.equal 'req'
@@ -816,6 +812,8 @@
             out.send res
           , delay

+        err.on 'data', (data) ->
+          done data
         out.once 'data', (data) ->
           chai.expect(data).to.be.an 'object'
           chai.expect(data.p1).to.equal 'req'
@@ -854,12 +852,14 @@
         p2.send 73
         p2.disconnect()

-        chai.expect(Object.keys(c._wpData[null].groupedData)).to.have.length.above 0
-        chai.expect(Object.keys(c._wpData[null].params)).to.have.length.above 0
+        chai.expect(c.inPorts.data1.getBuffer().length, 'data1 should have a packet').to.be.above 0
+        chai.expect(c.inPorts.param2.getBuffer().length, 'param2 should have a packet').to.be.above 0

         c.shutdown (err) ->
           return done err if err
-          chai.expect(c._wpData).to.deep.equal {}
+          for portName, port in c.inPorts.ports
+            chai.expect(port.getBuffer()).to.eql []
+            chai.expect(c.load).to.equal 0
           done()

       it 'should drop premature data if configured to do so', (done) ->
@@ -877,6 +877,8 @@
             d2: input.data2
           out.send res

+        err.on 'data', (data) ->
+          done data
         out.once 'data', (data) ->
           chai.expect(data).to.be.an 'object'
           chai.expect(data.p1).to.equal 'req'
@@ -1043,7 +1045,7 @@
           tryAgain()
         , 30

-    describe 'with many inputs and groups', ->
+    describe 'with many inputs and groups in async mode', ->
       c = new noflo.Component
       c.token = null
       c.inPorts.add 'in', datatype: 'string'
@@ -1061,13 +1063,98 @@
         async: true
         forwardGroups: true
       , (data, groups, out, callback) ->
-
         setTimeout ->
           out.beginGroup data.path
           out.send data.message
           out.endGroup()
           do callback
         , 300
+
+      ins = noflo.internalSocket.createSocket()
+      msg = noflo.internalSocket.createSocket()
+      rep = noflo.internalSocket.createSocket()
+      pth = noflo.internalSocket.createSocket()
+      tkn = noflo.internalSocket.createSocket()
+      out = noflo.internalSocket.createSocket()
+      err = noflo.internalSocket.createSocket()
+      c.inPorts.in.attach ins
+      c.inPorts.message.attach msg
+      c.inPorts.repository.attach rep
+      c.inPorts.path.attach pth
+      c.inPorts.token.attach tkn
+      c.outPorts.out.attach out
+      c.outPorts.error.attach err
+
+      it 'should handle mixed flow well', (done) ->
+        groups = []
+        refGroups = [
+          'foo'
+          'http://techcrunch.com/2013/03/26/embedly-now/'
+          'path data'
+        ]
+        ends = 0
+        packets = []
+        refData = ['message data']
+        out.on 'begingroup', (grp) ->
+          groups.push grp
+        out.on 'endgroup', ->
+          ends++
+        out.on 'data', (data) ->
+          packets.push data
+        out.on 'disconnect', ->
+          chai.expect(groups).to.deep.equal refGroups
+          chai.expect(ends).to.equal 3
+          chai.expect(packets).to.deep.equal refData
+          done()
+
+        err.on 'data', (data) ->
+          done data
+
+        rep.beginGroup 'foo'
+        rep.beginGroup 'http://techcrunch.com/2013/03/26/embedly-now/'
+        rep.send 'repo data'
+        rep.endGroup()
+        rep.endGroup()
+        ins.beginGroup 'foo'
+        ins.beginGroup 'http://techcrunch.com/2013/03/26/embedly-now/'
+        ins.send 'ins data'
+        msg.beginGroup 'foo'
+        msg.beginGroup 'http://techcrunch.com/2013/03/26/embedly-now/'
+        msg.send 'message data'
+        msg.endGroup()
+        msg.endGroup()
+        ins.endGroup()
+        ins.endGroup()
+        ins.disconnect()
+        msg.disconnect()
+        pth.beginGroup 'foo'
+        pth.beginGroup 'http://techcrunch.com/2013/03/26/embedly-now/'
+        pth.send 'path data'
+        pth.endGroup()
+        pth.endGroup()
+        pth.disconnect()
+        rep.disconnect()
+    describe 'with many inputs and groups in sync mode', ->
+      c = new noflo.Component
+      c.token = null
+      c.inPorts.add 'in', datatype: 'string'
+      .add 'message', datatype: 'string'
+      .add 'repository', datatype: 'string'
+      .add 'path', datatype: 'string'
+      .add 'token', datatype: 'string', (event, payload) ->
+        c.token = payload if event is 'data'
+      c.outPorts.add 'out', datatype: 'string'
+      .add 'error', datatype: 'object'
+
+      noflo.helpers.WirePattern c,
+        in: ['in', 'message', 'repository', 'path']
+        out: 'out'
+        async: false
+        forwardGroups: true
+      , (data, groups, out) ->
+        out.beginGroup data.path
+        out.send data.message
+        out.endGroup()

       ins = noflo.internalSocket.createSocket()
       msg = noflo.internalSocket.createSocket()


I think this is better, also make the loop actually work

--- Ackermann.coffee
+++ Ackermann.coffee
@@ -1,8 +1,11 @@
 ack = (m, n) ->
   if m == 0 then return n + 1
+  else if m > 0 and n > 0 then return ack(m - 1, ack(m, n - 1))
   else if m > 0 then return ack(m - 1, 1)
-  else if m > 0 and n > 0 then return ack(m - 1, ack(m, n - 1))

+
+
+i = 0
 while true
     m = i
     n = 0


Fixed a typo

Fixed a typo

--- views/components/main/parts/kdock-panel.cjsx
+++ views/components/main/parts/kdock-panel.cjsx
@@ -120,7 +120,8 @@
       (dock) -> 0 <= dock.completeTime < new Date().getTime() + 1000).map(
       (dock) -> i18n.resources.__ dock.name).join(', ')
     notify "#{completedShips} #{__ 'built'}",
-      type: __ "Construction"
+      type: 'construction'
+      title: __ "Construction"
       icon: @constructionIcon
   render: ->
     <div>


Fixed custom middleware coming after our middleware

--- src/lib/docpad.coffee
+++ src/lib/docpad.coffee
@@ -2887,30 +2887,36 @@
 				serverExpress.use(express.bodyParser())  if opts.middlewareBodyParser isnt false
 				serverExpress.use(express.methodOverride())  if opts.middlewareMethodOverride isnt false

-				# DocPad Header Middleware
-				serverExpress.use(docpad.serverMiddlewareHeader)
-
-				# Router Middleware
-				serverExpress.use(serverExpress.router)  if opts.middlewareExpressRouter isnt false
-
 				# Emit the serverExtend event
 				# So plugins can define their routes earlier than the DocPad routes
 				docpad.emitSync 'serverExtend', {server:serverExpress,serverExpress,serverHttp,express}, (err) ->
 					return next(err)  if err

+					# DocPad Header Middleware
+					# Keep it before the serverExtend event
+					serverExpress.use(docpad.serverMiddlewareHeader)
+
+					# Router Middleware
+					# Keep it before the serverExtend event
+					serverExpress.use(serverExpress.router)  if opts.middlewareExpressRouter isnt false
+
 					# DocPad Router Middleware
+					# Keep it before the serverExtend event
 					serverExpress.use(docpad.serverMiddlewareRouter)

 					# Static
+					# Keep it before the serverExtend event
 					if config.maxAge
 						serverExpress.use(express.static(config.outPath,{maxAge:config.maxAge}))
 					else
 						serverExpress.use(express.static(config.outPath))

 					# DocPad 404 Middleware
+					# Keep it before the serverExtend event
 					serverExpress.use(docpad.serverMiddleware404)  if opts.middleware404 isnt false

 					# DocPad 500 Middleware
+					# Keep it before the serverExtend event
 					serverExpress.error(docpad.serverMiddleware500)  if opts.middleware500 isnt false

 				# Start the Server


Fix for issue #1446: Compiler crashes on permissions error instead of giving meaningful error message

--- command.coffee
+++ command.coffee
@@ -93,12 +93,14 @@
           throw err if err
           if stats.isDirectory()
             fs.readdir source, (err, files) ->
+              throw err if err
               unprocessed[sourceIndex] += files.length
               for file in files
                 compile path.join(source, file), sourceIndex
               unprocessed[sourceIndex] -= 1
           else if topLevel or path.extname(source) is '.coffee'
             fs.readFile source, (err, code) ->
+              throw err if err
               unprocessed[sourceIndex] -= 1
               if opts.join
                 contents[sourceIndex] = helpers.compact([contents[sourceIndex], code.toString()]).join('\n')


TeamListItem: show a notification on team destroy [fixes #110059876]

--- client/admin/lib/views/koding-admin/teamlistitem.coffee
+++ client/admin/lib/views/koding-admin/teamlistitem.coffee
@@ -76,6 +76,10 @@
           callback   : ->
             team.destroy (err) ->
               return  if showError err
+
+              new kd.NotificationView
+                title: 'Team has been destroyed!'
+
               delegate.emit 'ReloadRequested'
               modal.destroy()
         , team


Clarify logic about which element is the event source in an AjaxFormLoop update

--- tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/ajaxformloop.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/ajaxformloop.coffee
@@ -72,11 +72,11 @@
                 </#{insertionPoint.element.tagName}>
               """

-          newElement = insertionPoint.insertBefore newElement
+          insertionPoint.insertBefore newElement

           # Trigger this event, to inform the world that the zone-like new element has been updated
           # with content.
-          newElement.trigger events.zone.didUpdate
+          insertionPoint.trigger events.zone.didUpdate

       return false


Calculator exponentiation Fixes #4721515


force reload when the username changed

force reload when the username changed

--- core/app/backbone/controllers/profile_controller.coffee
+++ core/app/backbone/controllers/profile_controller.coffee
@@ -60,7 +60,7 @@

   setChannelListing: (username) ->
     channelCollectionView = new ChannelsView(collection: window.Channels)
-    window.Channels.setUsername(username)
-    window.Channels.setupReloading()
+    changed = window.Channels.setUsername(username)
+    window.Channels.setupReloading(changed)
     window.Channels.unsetActiveChannel()
     app.leftMiddleRegion.show(channelCollectionView)


Update coffee-autocompile.coffee

Update coffee-autocompile.coffee

better parsing for comment

--- lib/coffee-autocompile.coffee
+++ lib/coffee-autocompile.coffee
@@ -2,7 +2,7 @@
 path = require 'path'
 [mkdirp, coffee, uglify] = []

-class StylusAutocompile
+class CoffeeAutocompile
   activate: ->
     @disposable = atom.commands.add 'atom-workspace', 'core:save', @handleSave

@@ -19,8 +19,15 @@
     @compile()

   compile: ->
-    params = @getParams @activeEditor.getURI(), @activeEditor.getText()
-    return unless params?
+    text = @activeEditor.getText()
+    firstComment = text.match /^\s*#\s*(.*)\n*/
+    return unless firstComment? and firstComment[1]?
+    paramsString = firstComment[1].replace(/\s/g,"")
+    params = path: path
+    for param in paramsString.split ","
+      [key, value] = param.split ":"
+      continue unless key? and value?
+      params[key] = value

     @render params, @activeEditor.getText()

@@ -31,7 +38,7 @@
     renderer = coffee.compile source,
       sourceMap: params.sourcemap

-    filePath = path.resolve path.dirname(params.file), params.out
+    filePath = path.resolve path.dirname(@activeEditor.getURI()), params.out
     if params.sourcemap
       {js, v3SourceMap} = renderer
       js += "\n//# sourceMappingURL=#{filePath}.map"
@@ -44,28 +51,6 @@

     @writeFile filePath, js
     @writeFile "#{filePath}.map", v3SourceMap if v3SourceMap
-
-  getParams: (filePath, fileContent) ->
-    serialized = @getSerializedParams fileContent
-    return unless serialized?
-
-    params = file: filePath
-    for param in serialized.split /\s*,\s*/
-      [key, value] = param.split /\s*:\s*/
-      continue unless key? and value?
-      params[key] = value
-
-    params.compress = @parseBoolean params.compress
-    params.sourcemap = @parseBoolean params.sourcemap
-    return params if params.out or params.main
-
-  getSerializedParams: (fileContent) ->
-    serialized = if fileContent.match /^#!/
-      fileContent.match /\n.*\n/
-    else
-      fileContent.match /^.*\n/
-    return unless serialized?
-    serialized[0].replace(/^#\s+/, '').replace(/\n/g, '')

   writeFile: (filePath, content) ->
     mkdirp ?= require 'mkdirp'
@@ -86,4 +71,4 @@
     (value is 'true' or value is 'yes' or value is 1) and
       value isnt 'false' and value isnt 'no' and value isnt 0

-module.exports = new StylusAutocompile()
+module.exports = new CoffeeAutocompile()


Update coffee-autocompile.coffee

Update coffee-autocompile.coffee

cleanup

--- lib/coffee-autocompile.coffee
+++ lib/coffee-autocompile.coffee
@@ -23,12 +23,14 @@
     firstComment = text.match /^\s*#\s*(.*)\n*/
     return unless firstComment? and firstComment[1]?
     paramsString = firstComment[1].replace(/\s/g,"")
-    params = path: path
+    params = {}
     for param in paramsString.split ","
       [key, value] = param.split ":"
-      continue unless key? and value?
-      params[key] = value
-
+      if key? and value?
+        params[key] = value
+    params.compress = @parseBoolean params.compress
+    params.sourcemap = @parseBoolean params.sourcemap
+    return unless params.out or params.main
     @render params, @activeEditor.getText()

   render: (params, source) ->


property autocompletion in JS

property autocompletion in JS

--- lib/controllerProvider.coffee
+++ lib/controllerProvider.coffee
@@ -75,28 +75,63 @@
   { #event name
     regExp : /\$\.([-a-zA-Z0-9-_]*)\.(add|remove)EventListener\(["']([-a-zA-Z0-9-_\/]*)$/
     getCompletions: (request) ->
+      completions = undefined
+      line = getLine(request)
+
       tiCompletions = require('../tiCompletions')
+      regResult = @regExp.exec(line)
+      if regResult
+        idName = regResult[1]
+        sourceEditor = util.getFileEditor related.getTargetPath('xml')
+
+        if(!sourceEditor.isEmpty())
+          completions = []
+          curTagName = ''
+          sourceEditor.scan new RegExp("id=[\"']#{idName}[\"']",'g'), (item) ->
+            curTagName = viewAutoProvider.getPreviousTag(sourceEditor,item.range.start);
+            item.stop();
+
+          if curTagName && tiCompletions.tags[curTagName]
+            apiName = tiCompletions.tags[curTagName].apiName
+            curTagObject = tiCompletions.types[apiName]
+            _.each curTagObject.events, (value)->
+              completions.push
+                type: 'event'
+                text: value
+                rightLabel: "<#{curTagName}>"
+
+      completions
+  }
+  { # value
+    regExp : /\$\.([-a-zA-Z0-9-_]*)\.([-a-zA-Z0-9-_\/]*)\s*=\s*([-a-zA-Z0-9-_\/]*)$/
+    getCompletions: (request) ->
+      tiCompletions = require('../tiCompletions')
       completions = undefined
       line = getLine(request)

-      idName = @regExp.exec(line)[1]
-      sourceEditor = util.getFileEditor related.getTargetPath('xml')
-
-      if(!sourceEditor.isEmpty())
-        completions = []
-        curTagName = '';
-        sourceEditor.scan new RegExp("id=[\"']#{idName}[\"']",'g'), (item) ->
-          curTagName = viewAutoProvider.getPreviousTag(sourceEditor,item.range.start);
-          item.stop();
-
-        if curTagName && tiCompletions.tags[curTagName]
-          apiName = tiCompletions.tags[curTagName].apiName
-          curTagObject = tiCompletions.types[apiName]
-          _.each curTagObject.events, (value)->
-            completions.push
-              type: 'event'
-              text: value
-              rightLabel: "<#{curTagName}>"
+      regResult = @regExp.exec(line)
+      if regResult
+        idName = regResult[1]
+        propertyName = regResult[2]
+        sourceEditor = util.getFileEditor related.getTargetPath('xml')
+        if(!sourceEditor.isEmpty())
+          completions = []
+          curTagName = ''
+          sourceEditor.scan new RegExp("id=[\"']#{idName}[\"']",'g'), (item) ->
+            curTagName = viewAutoProvider.getPreviousTag(sourceEditor,item.range.start);
+            item.stop();
+
+
+          if curTagName && tiCompletions.tags[curTagName]
+            apiName = tiCompletions.tags[curTagName].apiName
+            curTagObject = tiCompletions.types[apiName]
+
+        _.each tiCompletions.properties[propertyName]?.values, (value)->
+          completions.push
+            type: 'value'
+            text: value
+            rightLabel: if _.contains(curTagObject.properties,propertyName) then "<#{curTagName}>" else ""
+            description: "value of '#{propertyName}' property"

         completions
   }
@@ -155,7 +190,8 @@
             _.each curTagObject.functions, (value)->
               completions.push
                 type: 'function'
-                text: value
+                displayText: "#{value}"
+                snippet: "#{value}(${1})${0}"
                 rightLabel: "<#{curTagName}>"

             _.each curTagObject.properties, (value)->


update def/template/menu_linux.cson

update def/template/menu_linux.cson

--- def/template/menu_linux.cson
+++ def/template/menu_linux.cson
@@ -1,298 +1,296 @@
 Menu:
   "&File":
-    value: "ファイル(&F)"
+    value: "File(&F)"
     submenu:
       "New &Window":
-        value: "新規ウインドウ(&W)"
+        value: "New Window(&W)"
       "&New File":
-        value: "新規ファイル(&N)"
+        value: "New File(&N)"
       "&Open File…":
-        value: "開く(&O)..."
+        value: "Open File(&O)..."
       "Open Folder…":
-        value: "フォルダを開く..."
+        value: "Open Folder..."
       "Add Project Folder…":
-        value: "プロジェクトフォルダを追加..."
+        value: "Add Project Folder..."
       "Reopen Last &Item":
-        value: "最後に使用したファイルを開く(&I)"
+        value: "Reopen Last Item(&I)"
       "&Save":
-        value: "保存(&S)"
+        value: "Save(&S)"
       "Save &As…":
-        value: "別名で保存(&A)..."
+        value: "Save As(&A)..."
       "Save A&ll":
-        value: "すべて保存(&L)"
+        value: "Save All(&L)"
       "&Close Tab":
-        value: "タブを閉じる(&C)"
+        value: "Close Tab(&C)"
       "Close &Pane":
-        value: "ペインを閉じる(&P)"
+        value: "Close Pane(&P)"
       "Clos&e Window":
-        value: "ウインドウを閉じる(&E)"
+        value: "Close Window(&E)"
       "Quit":
-        value: "終了"
+        value: "Quit"
       "Close All Tabs":
-        value: "タブをすべて閉じる"
+        value: "Close All Tabs"
   "&Edit":
-    value: "編集(&E)"
+    value: "Edit(&E)"
     submenu:
       "&Undo":
-        value: "取り消す(&U)"
+        value: "Undo(&U)"
       "&Redo":
-        value: "やり直す(&R)"
+        value: "Redo(&R)"
       "&Cut":
-        value: "カット(&C)"
+        value: "Cut(&C)"
       "C&opy":
-        value: "コピー(&O)"
+        value: "Copy(&O)"
       "Copy Pat&h":
-        value: "パスをコピー(&H)"
+        value: "Copy Path(&H)"
       "&Paste":
-        value: "ペースト(&P)"
+        value: "Paste(&P)"
       "Select &All":
-        value: "すべて選択(&A)"
+        value: "Select All(&A)"
       "&Toggle Comments":
-        value: "コメントの切替(&T)"
+        value: "Toggle Comments(&T)"
       Lines:
-        value: "行"
+        value: "Lines"
         submenu:
           "&Indent":
-            value: "インデントを追加(&I)"
+            value: "Indent(&I)"
           "&Outdent":
-            value: "インデントを戻す(&O)"
+            value: "Outdent(&O)"
           "&Auto Indent":
-            value: "自動インデント(&A)"
+            value: "Auto Indent(&A)"
           "Move Line &Up":
-            value: "選択中の行を上に移動(&U)"
+            value: "Move Line Up(&U)"
           "Move Line &Down":
-            value: "選択中の行を下に移動(&D)"
+            value: "Move Line Down(&D)"
           "Du&plicate Lines":
-            value: "行を複製(&P)"
+            value: "Duplicate Lines(&P)"
           "D&elete Line":
-            value: "行を削除(&E)"
+            value: "Delete Line(&E)"
           "&Join Lines":
-            value: "行を結合(&J)"
+            value: "Join Lines(&J)"
       Columns:
-        value: "列"
+        value: "Columns"
         submenu:
           "Move Selection &Left":
-            value: "選択範囲を左に移動(&L)"
+            value: "Move Selection Left(&L)"
           "Move Selection &Right":
-            value: "選択範囲を右に移動(&R)"
+            value: "Move Selection Right(&R)"
       Text:
-        value: "テキスト"
+        value: "Text"
         submenu:
           "&Upper Case":
-            value: "大文字に変換(&U)"
+            value: "Upper Case(&U)"
           "&Lower Case":
-            value: "小文字に変換(&L)"
+            value: "Lower Case(&L)"
           "Delete to End of &Word":
-            value: "単語の末尾まで削除(&W)"
+            value: "Delete to End of Word(&W)"
           "Delete to Previous Word Boundary":
-            value: "前の単語の境界まで削除"
+            value: "Delete to Previous Word Boundary"
           "Delete to Next Word Boundary":
-            value: "次の単語の境界まで削除"
+            value: "Delete to Next Word Boundary"
           "&Delete Line":
-            value: "行を削除(&D)"
+            value: "Delete Line(&D)"
           "&Transpose":
-            value: "前後を入れ替え(&T)"
+            value: "Transpose(&T)"
       Folding:
-        value: "折りたたみ"
+        value: "Folding"
         submenu:
           "&Fold":
-            value: "折りたたむ(&F)"
+            value: "Fold(&F)"
           "&Unfold":
-            value: "折りたたみを戻す(&U)"
+            value: "Unfold(&U)"
           "Unfold &All":
-            value: "すべての折りたたみを戻す(&A)"
+            value: "Unfold All(&A)"
           "Fol&d All":
-            value: "すべて折りたたむ(&D)"
+            value: "Fold All(&D)"
           "Fold Level 1":
-            value: "1段階折りたたむ"
+            value: "Fold Level 1"
           "Fold Level 2":
-            value: "2段階折りたたむ"
+            value: "Fold Level 2"
           "Fold Level 3":
-            value: "3段階折りたたむ"
+            value: "Fold Level 3"
           "Fold Level 4":
-            value: "4段階折りたたむ"
+            value: "Fold Level 4"
           "Fold Level 5":
-            value: "5段階折りたたむ"
+            value: "Fold Level 5"
           "Fold Level 6":
-            value: "6段階折りたたむ"
+            value: "Fold Level 6"
           "Fold Level 7":
-            value: "7段階折りたたむ"
+            value: "Fold Level 7"
           "Fold Level 8":
-            value: "8段階折りたたむ"
+            value: "Fold Level 8"
           "Fold Level 9":
-            value: "9段階折りたたむ"
+            value: "Fold Level 9"
       "&Preferences":
-        value: "環境設定(&P)..."
+        value: "Preferences(&P)"
       "Config…":
-        value: "個人設定..."
+        value: "Config..."
       "Init Script…":
-        value: "起動スクリプト..."
+        value: "Init Script..."
       "Keymap…":
-        value: "キーマップ..."
+        value: "Keymap..."
       "Snippets…":
-        value: "スニペット..."
+        value: "Snippets..."
       "Stylesheet…":
-        value: "スタイルシート..."
+        value: "Stylesheet..."
       "Reflow Selection":
-        value: "選択範囲をリフロー"
+        value: "Reflow Selection"
       Bookmark:
-        value: "ブックマーク"
+        value: "Bookmark"
         submenu:
           "View All":
-            value: "すべて表示"
+            value: "View All"
           "Toggle Bookmark":
-            value: "ブックマークの切替"
+            value: "Toggle Bookmark"
           "Jump to Next Bookmark":
-            value: "次のブックマークへ"
+            value: "Jump to Next Bookmark"
           "Jump to Previous Bookmark":
-            value: "前のブックマークへ"
+            value: "Jump to Previous Bookmark"
       "Select Encoding":
-        value: "エンコーディング選択"
+        value: "Select Encoding"
       "Go to Line":
-        value: "指定行に移動"
+        value: "Go to Line"
       "Select Grammar":
-        value: "文法を選択"
+        value: "Select Grammar"
   "&View":
-    value: "表示(&V)"
+    value: "View(&V)"
     submenu:
       "Toggle &Full Screen":
-        value: "フルスクリーン切替(&F)"
+        value: "Toggle Full Screen(&F)"
       "Toggle Menu Bar":
-        value: "メニューバー切替"
+        value: "Toggle Menu Bar"
       Panes:
-        value: "ペイン"
+        value: "Panes"
         submenu:
           "Split Up":
-            value: "ペイン分割 ↑"
+            value: "Split Up"
           "Split Down":
-            value: "ペイン分割 ↓"
+            value: "Split Down"
           "Split Left":
-            value: "ペイン分割 ←"
+            value: "Split Left"
           "Split Right":
-            value: "ペイン分割 →"
+            value: "Split Right"
           "Focus Next Pane":
-            value: "次のペインにフォーカス"
+            value: "Focus Next Pane"
           "Focus Previous Pane":
-            value: "前のペインにフォーカス"
+            value: "Focus Previous Pane"
           "Focus Pane Above":
-            value: "ペインにフォーカス ↑"
+            value: "Focus Pane Above"
           "Focus Pane Below":
-            value: "ペインにフォーカス ↓"
+            value: "Focus Pane Below"
           "Focus Pane On Left":
-            value: "ペインにフォーカス ←"
+            value: "Focus Pane On Left"
           "Focus Pane On Right":
-            value: "ペインにフォーカス →"
+            value: "Focus Pane On Right"
           "Close Pane":
-            value: "ペインを閉じる"
+            value: "Close Pane"
       Developer:
-        value: "開発"
+        value: "Developer"
         submenu:
           "Open In &Dev Mode…":
-            value: "開発モードで開く(&D)..."
+            value: "Open In Dev Mode(&D)..."
           "&Reload Window":
-            value: "ウィンドウの再読み込み(&R)"
+            value: "Reload Window(&R)"
           "Run Package &Specs":
-            value: "パッケージ Specs を実行(&S)"
+            value: "Run Package Specs(&S)"
           "Toggle Developer &Tools":
-            value: "デベロッパー ツール(&T)"
+            value: "Toggle Developer Tools(&T)"
       "&Increase Font Size":
-        value: "フォントサイズの拡大"
+        value: "Increase Font Size(&I)"
       "&Decrease Font Size":
-        value: "フォントサイズの縮小"
+        value: "Decrease Font Size(&D)"
       "Re&set Font Size":
-        value: "フォントサイズのリセット"
+        value: "Reset Font Size(&S)"
       "Toggle Soft &Wrap":
-        value: "自動折り返しの切替(&W)"
+        value: "Toggle Soft Wrap(&W)"
       "Toggle Command Palette":
-        value: "コマンドパレット"
+        value: "Toggle Command Palette"
       "Toggle Tree View":
-        value: "ツリービュー"
+        value: "Toggle Tree View"
   "&Selection":
-    value: "選択(&S)"
+    value: "Selection(&S)"
     submenu:
       "Add Selection &Above":
-        value: "選択範囲を広げる ↑(&A)"
+        value: "Add Selection Above(&A)"
       "Add Selection &Below":
-        value: "選択範囲を広げる ↓(&B)"
+        value: "Add Selection Below(&B)"
       "S&plit into Lines":
-        value: "選択範囲を各行に分割して同時操作(&P)"
+        value: "Split into Lines(&P)"
       "Single Selection":
-        value: "同時操作状態を解除"
+        value: "Single Selection"
       "Select to &Top":
-        value: "ファイル先頭まで選択(&T)"
+        value: "Select to Top(&T)"
       "Select to Botto&m":
-        value: "ファイル末尾まで選択(&M)"
+        value: "Select to Bottom(&M)"
       "Select &Line":
-        value: "行を選択(&L)"
+        value: "Select Line(&L)"
       "Select &Word":
-        value: "単語を選択(&W)"
+        value: "Select Word(&W)"
       "Select to Beginning of W&ord":
-        value: "単語の先頭まで選択(&O)"
+        value: "Select to Beginning of Word(&O)"
       "Select to Beginning of L&ine":
-        value: "行頭まで選択(&I)"
+        value: "Select to Beginning of Line(&I)"
       "Select to First &Character of Line":
-        value: "行の最初の文字まで選択(&C)"
+        value: "Select to First Character of Line(&C)"
       "Select to End of Wor&d":
-        value: "単語の末尾まで選択(&D)"
+        value: "Select to End of Word(&D)"
       "Select to End of Lin&e":
-        value: "行末まで選択(&E)"
+        value: "Select to End of Line(&E)"
       "Select Inside Brackets":
-        value: "カッコ内を選択"
+        value: "Select Inside Brackets"
   "F&ind":
-    value: "検索(&I)"
+    value: "Find(&I)"
     submenu:
       "Find in Buffer":
-        value: "検索..."
+        value: "検索"
       "Replace in Buffer":
-        value: "置換..."
+        value: "置換"
       "Select Next":
-        value: "次の一致も選択"
+        value: "Select Next"
       "Select All":
-        value: "一致をすべて選択"
+        value: "Select All"
       "Toggle Find in Buffer":
-        value: "検索パネル切替"
+        value: "Toggle Find in Buffer"
       "Find in Project":
-        value: "プロジェクト内検索..."
+        value: "Find in Project"
       "Toggle Find in Project":
-        value: "プロジェクト内検索パネル切替"
+        value: "Toggle Find in Project"
       "Find Next":
-        value: "次を検索"
+        value: "Find Next"
       "Find Previous":
-        value: "前を検索"
+        value: "Find Previous"
       "Replace Next":
-        value: "次を置換"
+        value: "Replace Next"
       "Replace All":
-        value: "すべて置換"
+        value: "Replace All"
       "Clear History":
-        value: "履歴をクリア"
+        value: "Clear History"
       "Find Buffer":
-        value: "バッファを検索"
+        value: "Find Buffer"
       "Find File":
-        value: "ファイルを検索"
+        value: "Find File"
       "Find Modified File":
-        value: "修正されたファイルを検索"
+        value: "Find Modified File"
   "&Packages":
-    value: "パッケージ(&P)"
+    value: "Packages(&P)"
   "&Help":
-    value: "ヘルプ(&H)"
+    value: "Help(&H)"
     submenu:
       "View &Terms of Use":
-        value: "利用条件(&T)"
+        value: "View Terms of Use(&T)"
       "View &License":
-        value: "ライセンス(&L)"
+        value: "View License(&L)"
       "&Documentation":
-        value: "ドキュメント(&D)"
-      Roadmap:
-        value: "ロードマップ"
+        value: "Documentation(&D)"
       "Frequently Asked Questions":
-        value: "よくあるご質問"
+        value: "Frequently Asked Questions"
       "Community Discussions":
-        value: "コミュニティ ディスカッション"
+        value: "Community Discussions"
       "Report Issue":
-        value: "問題の報告"
+        value: "Report Issue"
       "Search Issues":
-        value: "報告されている問題"
+        value: "Search Issues"
       "About Atom":
-        value: "Atom について"
+        value: "About Atom"
       "Welcome Guide":
-        value: "ウェルカムガイド"
+        value: "Welcome Guide"


Execute VM code

Execute VM code

--- lib/ethereum-interface.coffee
+++ lib/ethereum-interface.coffee
@@ -14,14 +14,15 @@
 EthJSBlock = require 'ethereumjs-block'
 EthJSVM = require 'ethereumjs-vm'
 ethJSABI = require 'ethereumjs-abi'
-BN = ethJSUtil.BN
-VM = {}
 # Env Vars
 Coinbase = ''
 Password = ''
 Compiler = 'solcjs' # set default compiler
 vmAccounts = []
 vmBlockNumber = 1150000
+BN = ethJSUtil.BN
+VM = new EthJSVM(null, null, { activatePrecompiles: true, enableHomestead: true })
+# RPC config
 rpcAddress = atom.config.get('atom-ethereum-interface.rpcAddress')
 useTestRpc = atom.config.get('atom-ethereum-interface.useTestRpc')

@@ -95,12 +96,11 @@

     addAccounts: (keyArr) ->
         accounts = []
-        @VM = new EthJSVM(null, null, { activatePrecompiles: true, enableHomestead: true })
         # prepare accounts from key and return accounts array
         for key of keyArr
             privateKey = new Buffer(keyArr[key], 'hex')
             address = ethJSUtil.privateToAddress(privateKey)
-            @VM.stateManager.putAccountBalance address, 'f00000000000000001', (error, callback) ->
+            VM.stateManager.putAccountBalance address, 'f00000000000000001', (error, callback) ->
             vmAccounts['0x' + address.toString('hex')] = { privateKey: privateKey, nonce: 0 }
             accounts.push('0x' + address.toString('hex'))
         accounts
@@ -478,7 +478,7 @@
             tx = new EthJSTX({
                     nonce: new BN(vmAccounts[Coinbase].nonce++),
                     gasPrice: new BN(1),
-                    gasLimit: new BN(1000, 10),
+                    gasLimit: new BN(3000000, 10),
                     value: new BN(0, 10),
                     data: that.code
                 })
@@ -486,7 +486,7 @@
             block = new EthJSBlock({
                     header: {
                         timestamp: new Date().getTime() / 1000 | 0,
-                        number: @vmBlockNumber
+                        number: that.vmBlockNumber
                     },
                     transactions: [],
                     uncleHeaders: []
@@ -500,8 +500,7 @@
                     constructorS = []
                     for i in that.constructVars.inputVariables
                         constructorS.push i.varValue
-
-                    that.VM.runTx { block: block, tx: tx, skipBalance: true, skipNonce: true }, (error, result) ->
+                    that.exeVM block, tx, (error, result) ->
                         if error
                             console.error error
                             that.showErrorMessage 508, error
@@ -539,11 +538,7 @@
                                         if !error
                                             that.argsToArray self.refs, childFunction, (error, argArray) ->
                                                 if !error
-                                                    console.log "Will call"
-                                                    # Buffer.concat([ ethJSABI.methodID(Method Name, input variable types), ethJSABI.rawEncode(input variable types, input variables) ]).toString('hex')
-                                                    buffer = Buffer.concat([ ethJSABI.methodID(childFunction, typArray), ethJSABI.rawEncode(typArray, argArray) ]).toString('hex')
-                                                    console.log buffer
-                                                    #that.call(myContract, childFunction, argArray)
+                                                    that.callVM(myContract, childFunction, typArray, argArray)
                                 render: ->
                                     self = this
                                     React.createElement 'div', { htmlFor: 'contractFunctions' }, this.state.childFunctions.map((childFunction, i) ->
@@ -556,15 +551,6 @@
                             )

                             ReactDOM.render React.createElement(functionABI), document.getElementById(that.contractName + '_call')
-            ###
-            console.log that.code
-            vm.runCode { code: new Buffer(that.code, 'hex'), gasLimit: new Buffer('ffffffff', 'hex') }, (error, callback) ->
-                if error
-                    console.error error
-                else
-                    console.log callback.gasUsed.toString()
-            ###
-
         else
             # Execute code using web3
             @estimatedGas = if @estimatedGas > 0 then @estimatedGas else 1000000
@@ -704,8 +690,45 @@
                 else
                     web3.personal.unlockAccount(web3.eth.defaultAccount, Password)
                     result = that.myContract[that.functionName]()
+                that.showOutput that.myContract.address, result
+
+    callVM: (@myContract, @functionName, @argTypes, @arguments) ->
+        that = this
+        to = that.myContract.createdAddress.toString('hex')
+        # Buffer.concat([ ethJSABI.methodID(Method Name, input variable types), ethJSABI.rawEncode(input variable types, input variables) ]).toString('hex')
+        buffer = Buffer.concat([ ethJSABI.methodID(that.functionName, that.argTypes), ethJSABI.rawEncode(that.argTypes, that.arguments) ]).toString('hex')
+        tx = new EthJSTX({
+                nonce: new BN(vmAccounts[Coinbase].nonce++),
+                gasPrice: new BN(1),
+                gasLimit: new BN(3000000, 10),
+                to: new Buffer(to, 'hex'),
+                value: new BN(0, 10),
+                data: new Buffer(buffer, 'hex')
+            })
+        tx.sign(vmAccounts[Coinbase].privateKey)
+        block = new EthJSBlock({
+                header: {
+                    timestamp: new Date().getTime() / 1000 | 0,
+                    number: vmBlockNumber
+                },
+                transactions: [],
+                uncleHeaders: []
+            })
+        @exeVM block, tx, (error, result) ->
+            if error
+                console.error error
+                that.showErrorMessage 508, error
+            else
                 console.log result
-                that.showOutput that.myContract.address, result
+                that.showOutput 'Method call is yet to be implemented', 'See github issue https://github.com/gmtDevs/atom-ethereum-interface/issues/23'
+
+    exeVM: (@block, @tx, callback) ->
+        that = this
+        console.log that.block
+        console.log that.tx
+        VM.runTx { block: that.block, tx: that.tx, skipBalance: true, skipNonce: true }, (error, result) ->
+            if !error
+                callback(null, result)

     toggle: ->
         if @modalPanel.isVisible()


hub sync: part 2 -- working on connect.

hub sync: part 2 -- working on connect.

--- salvus/hub.coffee
+++ salvus/hub.coffee
@@ -1932,26 +1932,24 @@
         opts = defaults opts,
             local_hub    : required
             project_id   : required
-            session_uuid : required
             path         : required
-            content      : required
-            chat         : required
+            cb           : required

         @local_hub    = opts.local_hub
         @project_id   = opts.project_id
-        @session_uuid = opts.session_uuid
         @path         = opts.path
-        @chat         = opts.chat

         # min_interval: to avoid possibly DOS's a local hub -- not sure what best choice is here.
         @sync = misc.retry_until_success_wrapper(f:@_sync, min_interval:200, logname:'localhub_sync')

-        # Our upstream server (the local hub)
-        @diffsync_server = new diffsync.DiffSync(doc:opts.content)
-        @diffsync_server.connect(new CodeMirrorDiffSyncLocalHub(@))
-
         # The downstream clients of this hub
         @diffsync_clients = {}
+
+        @reconnect (err) =>
+            if err
+                opts.cb(err)
+            else
+                opts.cb(false, @)

     reconnect: (cb) =>
         misc.retry_until_success
@@ -1973,24 +1971,20 @@
                             cb?(resp.error)
                         else
                             @session_uuid = resp.session_uuid
+                            @chat         = resp.chat
                             codemirror_sessions.by_uuid[@session_uuid] = @

-                            # Reconnect to the upstream (local_hub) server, being careful to save our current edits.
-                            edit_stack = @diffsync_server.edit_stack
+                            # Reconnect to the upstream (local_hub) server
                             @diffsync_server = new diffsync.DiffSync(doc:resp.content)
                             @diffsync_server.connect(new CodeMirrorDiffSyncLocalHub(@))

-                            # Apply all of the edits we couldn't send while the local hub was down
-                            # to upstream, then set this to our live.  When there are multiple hubs,
-                            # a lot can happen between sync's with a local_hub.
-                            live_content = resp.content
-                            for p in edit_stack
-                                live_content =  diffsync.dmp.patch_apply(p.edits, live_content)[0]
-                            @diffsync_server.live = live_content
-
-                            # Forget our downstream clients -- they will get
-                            # reconnect messages, and keep going fine, eventually.
-                            @diffsync_clients = {}
+                            #
+                            # TODO: apply lost changes!!
+                            #
+                            @set_content(resp.content)
+
+                            codemirror_sessions.by_path[@project_id + @path] = @
+                            codemirror_sessions.by_uuid[@session_uuid] = @

                             cb()

@@ -2602,7 +2596,7 @@
     # Return a CodeMirrorSession object corresponding to the given session_uuid or path.
     get_codemirror_session: (opts) =>
         opts = defaults opts,
-            session_uuid : undefined   # give at least one of the session uuid or filename
+            session_uuid : undefined   # give at least one of the session uuid or path
             project_id   : undefined
             path         : undefined
             cb           : required    # cb(err, session)
@@ -2616,26 +2610,16 @@
             if session?
                 opts.cb(false, session)
                 return
+        if not (opts.path? and opts.project_id?)
+            opts.cb("reconnect")  # will send path next time
+            return
+
         # Create a new session object.
-        @call
-            mesg : message.codemirror_get_session(session_uuid:opts.session_uuid, project_id:opts.project_id, path:opts.path)
-            cb   : (err, resp) =>
-                # winston.debug("new codemirror session: local_hub --> hub: #{err}, #{misc.to_json(resp)}")
-                if err
-                    opts.cb(err)
-                else if resp.event == 'error'
-                    opts.cb(resp.error)
-                else
-                    session = new CodeMirrorSession
-                        local_hub    : @
-                        project_id   : opts.project_id
-                        session_uuid : resp.session_uuid
-                        path         : resp.path
-                        content      : resp.content
-                        chat         : resp.chat
-                    codemirror_sessions.by_uuid[resp.session_uuid] = session
-                    codemirror_sessions.by_path[opts.project_id + resp.path] = session
-                    opts.cb(false, session)
+        new CodeMirrorSession
+            local_hub   : @
+            project_id  : opts.project_id
+            path        : opts.path
+            cb          : opts.cb

     #########################################
     # Sage sessions -- TODO!


unnecessary packagePath removed

unnecessary packagePath removed

--- lib/modx-scaffold-view.coffee
+++ lib/modx-scaffold-view.coffee
@@ -68,8 +68,8 @@

     getComponentsDirectory: ->
         atom.config.get('core.projectHome') or
-          process.env.ATOM_REPOS_HOME or
-          path.join(fs.getHomeDirectory(), 'modx-generator')
+            process.env.ATOM_REPOS_HOME or
+            path.join(fs.getHomeDirectory(), 'modx-generator')

     validComponentPath: ->
         if fs.existsSync(@getComponentPath())
@@ -84,7 +84,6 @@
         fsp.cp templatePath, componentPath, callback

     createComponentFiles: (callback) ->
-        ComponentPath = @getComponentPath()
-        packagesDirectory = @getComponentsDirectory()
+        componentPath = @getComponentPath()
         templatePath = path.resolve(__dirname, '..', 'templates', @mode)
-        @initComponent(ComponentPath, templatePath, callback)
+        @initComponent(componentPath, templatePath, callback)


:art: :gift: support count times, cleanup state, checkpoint ByEditor

--- lib/move-selected-text.coffee
+++ lib/move-selected-text.coffee
@@ -1,4 +1,5 @@
 _ = require 'underscore-plus'
+{CompositeDisposable} = require 'atom'

 requireFrom = (pack, path) ->
   packPath = atom.packages.resolvePackagePath(pack)
@@ -12,20 +13,30 @@
 CommandPrefix = 'vim-mode-plus-user'
 stateByEditor = new Map
 checkPointByEditor = new Map
+disposableByEditor = new Map
 # -------------------------
 class MoveSelectedText extends TransformString
+  countTimes: (fn) ->
+    _.times @getCount(), ->
+      fn()
+
   getSelectedTexts: ->
     @editor.getSelections().map((selection) -> selection.getText()).join('')

   withUndoJoin: (fn) ->
-    unless (isSequential = stateByEditor.get(@editor) is @getSelectedTexts())
+    unless disposableByEditor.has(@editor)
+      disposableByEditor.set @editor, @editor.onDidDestroy =>
+        checkPointByEditor.delete(@editor)
+        stateByEditor.delete(@editor)
+
+    isSequential = stateByEditor.get(@editor) is @getSelectedTexts()
+    unless isSequential
       checkPointByEditor.set(@editor, @editor.createCheckpoint())
-
     fn()

     stateByEditor.set(@editor, @getSelectedTexts())
-    if isSequential and checkPointByEditor.has(@editor)
-      @editor.groupChangesSinceCheckpoint(checkPointByEditor.get(@editor))
+    if isSequential and (checkpoint = checkPointByEditor.get(@editor))
+      @editor.groupChangesSinceCheckpoint(checkpoint)

 class MoveSelectedTextUp extends MoveSelectedText
   @commandPrefix: CommandPrefix
@@ -34,14 +45,14 @@

   execute: ->
     return unless @isMode('visual')
-    return unless @selectTarget()

     @withUndoJoin =>
       selections = @editor.getSelectionsOrderedByBufferPosition()
       selections.reverse() if @direction is 'down'
       @editor.transact =>
         for selection in selections
-          @mutate(selection)
+          @countTimes =>
+            @mutate(selection)

   mutate: (selection) ->
     switch @vimState.submode
@@ -126,9 +137,11 @@

   execute: ->
     return unless @isMode('visual')
+
     @withUndoJoin =>
       @eachSelection (selection) =>
-        @mutate(selection)
+        @countTimes =>
+          @mutate(selection)

   mutate: (selection) ->
     switch @vimState.submode


:gift: Improve containment check when toggglePresetOccurrence and add at-occurrence scope.

Which is set when cursor is at occurrence-marker

--- lib/occurrence-manager.coffee
+++ lib/occurrence-manager.coffee
@@ -35,6 +35,10 @@
       else
         @clearMarkers()

+    @disposables.add @editor.onDidChangeCursorPosition ({cursor}) =>
+      if cursor.isLastCursor() and @hasMarkers()
+        @editorElement.classList.toggle("at-occurrence", @cursorIsAtOccurrenceMarker())
+
     @markerLayer.onDidUpdate(@destroyInvalidMarkers.bind(this))

   markBufferRangeByPattern: (pattern, occurrenceType) ->
@@ -52,7 +56,15 @@
       @markerLayer.markBufferRange(range, @markerOptions)

   updateEditorElement: ->
-    @editorElement.classList.toggle("has-occurrence", @hasMarkers())
+    hasMarkers = @hasMarkers()
+    @editorElement.classList.toggle("has-occurrence", hasMarkers)
+    if hasMarkers
+      @editorElement.classList.toggle("at-occurrence", @cursorIsAtOccurrenceMarker())
+    else
+      @editorElement.classList.remove("at-occurrence")
+
+  cursorIsAtOccurrenceMarker: ->
+    @getMarkerAtPoint(@editor.getCursorBufferPosition())?

   # Callback get passed following object
   # - pattern: can be undefined on reset event
@@ -127,7 +139,12 @@
       range.intersectsWith(marker.getBufferRange(), exclusive)

   getMarkerAtPoint: (point) ->
-    @markerLayer.findMarkers(containsBufferPosition: point)[0]
+    markers = @markerLayer.findMarkers(containsBufferPosition: point)
+    # We have to check all returned marker until found, since we do aditional marker validation.
+    # e.g. For text `abc()`, mark for `abc` and `(`. cursor on `(` char return multiple marker
+    # and we pick `(` by isGreaterThan check.
+    for marker in markers ? [] when marker.getBufferRange().end.isGreaterThan(point)
+      return marker

   # Select occurrence marker bufferRange intersecting current selections.
   # - Return: true/false to indicate success or fail


hub: correct fix  (duh)

hub: correct fix  (duh)

--- salvus/hub.coffee
+++ salvus/hub.coffee
@@ -3098,7 +3098,7 @@

 number_of_clients = () ->
-    v = (C for C of clients when not C._destroy_timer? and not C.closed)
+    v = (C for id,C of clients when not C._destroy_timer? and not C.closed)
     return v.length

 database_is_working = false


Fix conditional

Fix conditional

--- coffee/tether.coffee
+++ coffee/tether.coffee
@@ -381,10 +381,10 @@
     for module in Tether.modules
       ret = module.position.call(@, {left, top, targetAttachment, targetPos, @attachment, elementPos, offset, targetOffset, manualOffset, manualTargetOffset, scrollbarSize})

-      if not ret? or typeof ret isnt 'object'
+      if ret is false
+        return false
+      else if not ret? or typeof ret isnt 'object'
         continue
-      else if ret is false
-        return false
       else
         {top, left} = ret


reimplement **file_access_log**; shrink some logging messages

--- salvus/hub.coffee
+++ salvus/hub.coffee
@@ -245,7 +245,7 @@
                             # more work and I don't have time now.
                             # get the file itself
                             (cb) ->
-                                winston.debug(misc.to_json(files))
+                                #winston.debug(misc.to_json(files))
                                 winston.debug("Reading file from disk '#{files.file.path}'")
                                 fs.readFile files.file.path, (err, _data) ->
                                     if err
@@ -595,7 +595,7 @@
     # Pushing messages to this particular connected client
     #######################################################
     push_to_client: (mesg) =>
-        winston.debug("hub --> client (client=#{@id}): #{misc.trunc(to_safe_str(mesg),600)}") if mesg.event != 'pong'
+        winston.debug("hub --> client (client=#{@id}): #{misc.trunc(to_safe_str(mesg),300)}") if mesg.event != 'pong'
         @push_data_to_client(JSON_CHANNEL, to_json(mesg))

     push_data_to_client: (channel, data) ->
@@ -840,7 +840,7 @@
             return
         #winston.debug("got message: #{data}")
         if mesg.event.slice(0,4) != 'ping' and mesg.event != 'codemirror_bcast'
-            winston.debug("client --> hub (client=#{@id}): #{misc.trunc(to_safe_str(mesg), 600)}")
+            winston.debug("client --> hub (client=#{@id}): #{misc.trunc(to_safe_str(mesg), 300)}")
         handler = @["mesg_#{mesg.event}"]
         if handler?
             handler(mesg)
@@ -1605,6 +1605,13 @@
                     database.touch_project(project_id : project.project_id)
                     project.local_hub?.project.save()
                 setTimeout(f, 5000)
+
+            # Record eaching opening of a file in the database log
+            if mesg.message.event == 'codemirror_get_session' and mesg.message.path? and mesg.message.path != '.sagemathcloud.log' and @account_id? and mesg.message.project_id?
+                database.log_file_access
+                    project_id : mesg.message.project_id
+                    account_id : @account_id
+                    filename   : mesg.message.path

             # Make the actual call
             project.call
@@ -1811,7 +1818,7 @@
     # The code below all work(ed) when written, but I had not
     # implemented limitations and authentication.  Also, I don't
     # plan now to use this code.  So I'm disabling handling any
-    # of these messages, as a security precaution.
+    # of these messages, as a security precaution.
     ###
     mesg_create_task_list: (mesg) =>
         # TODO: add verification that owners is valid
@@ -3961,7 +3968,7 @@
         @conn = undefined

     send_json: (client, mesg) ->
-        winston.debug("hub --> sage_server: #{misc.trunc(to_safe_str(mesg),600)}")
+        winston.debug("hub --> sage_server: #{misc.trunc(to_safe_str(mesg),300)}")
         async.series([
             (cb) =>
                 if @conn?


re-implement sampledBy, by a simpler one. it also passes the new tests

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -675,57 +675,36 @@
       @subscribeInternal = subscribe
     else
       @subscribeInternal = new PropertyDispatcher(subscribe, handler).subscribe
-    combine = (other, leftSink, rightSink) =>
+
+    @sampledBy = (sampler, combinator) =>
+      lazyCombinator =
+        if (combinator?)
+          combinator = toCombinator(combinator)
+          (myVal, otherVal) ->
+            combinator(myVal.value(), otherVal.value())
+        else
+          (myVal, otherVal) -> myVal.value()
       myVal = None
-      otherVal = None
-      new Property (sink) =>
+      subscribe = (sink) =>
         unsubscribed = false
         unsubMe = nop
         unsubOther = nop
         unsubBoth = -> unsubMe() ; unsubOther() ; unsubscribed = true
-        myEnd = false
-        otherEnd = false
-        checkEnd = ->
-          if myEnd and otherEnd
-            reply = sink end()
-            unsubBoth() if reply == Bacon.noMore
-            reply
-        initialSent = false
-        combiningSink = (markEnd, setValue, thisSink) =>
-          (event) =>
-            if (event.isEnd())
-              markEnd()
-              checkEnd()
-              Bacon.noMore
-            else if event.isError()
-                reply = sink event
-                unsubBoth() if reply == Bacon.noMore
-                reply
-            else
-              setValue(new Some(event.value))
-              if (myVal.isDefined and otherVal.isDefined)
-                if initialSent and event.isInitial()
-                  # don't send duplicate Initial
-                  Bacon.more
-                else
-                  initialSent = true
-                  reply = thisSink(sink, event, myVal.value, otherVal.value)
-                  unsubBoth() if reply == Bacon.noMore
-                  reply
-              else
-                Bacon.more
-
-        mySink = combiningSink (-> myEnd = true), ((value) -> myVal = value), leftSink
-        otherSink = combiningSink (-> otherEnd = true), ((value) -> otherVal = value), rightSink
-        unsubMe = this.subscribeInternal mySink
-        unsubOther = other.subscribeInternal otherSink unless unsubscribed
+        unsubMe = this.subscribeInternal (event) =>
+          if event.hasValue()
+            myVal = new Some(event)
+          else if event.isError()
+            sink event
+        unsubOther = sampler.subscribe (event) =>
+          if event.hasValue()
+            myVal.forEach (myVal) =>
+              sink(event.apply(lazyCombinator(myVal, event)))
+          else
+            if event.isEnd()
+              unsubMe()
+            sink event
         unsubBoth
-    @sampledBy = (sampler, combinator = former) =>
-      combinator = toCombinator(combinator)
-      pushPropertyValue = (sink, event, propertyVal, streamVal) -> sink(event.apply( ->combinator(propertyVal(), streamVal())))
-      values = combine(sampler, nop, pushPropertyValue)
-      values = values.changes() if sampler instanceof EventStream
-      values.takeUntil(sampler.filter(false).mapEnd())
+      if sampler instanceof Property then new Property(subscribe) else new EventStream(subscribe)

     @subscribe = (sink) =>
       # TODO: nämä tehdään nyt joka listenerille erikseen


hub: a little more bug fixing related to recording file accesses.

--- salvus/hub.coffee
+++ salvus/hub.coffee
@@ -1466,15 +1466,17 @@
                     else
                         if not @_file_access?
                             @_file_access = {}
-                        if not @_file_access[mesg.project_id + mesg.path]?
+                        key = mesg.project_id + @account_id + mesg.path
+                        if not @_file_access[key]?
                             database.log_file_access
                                 project_id : mesg.project_id
                                 account_id : @account_id
                                 filename   : mesg.path
-                            @_file_access[mesg.project_id + mesg.path] = true
+                            @_file_access[key] = true
                             f = () =>
-                                delete @_file_access[mesg.path]
-                            setTimeout(f, 60000)
+                                delete @_file_access[key]
+                            setTimeout(f, 5*60000)  # record particular file open by a user at most once every 5 minutes
+
                         # It is critical that we initialize the
                         # diffsync objects on both sides with exactly
                         # the same document.


refactor

refactor

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -18,13 +18,7 @@
 Bacon.more = "moar bacon!"

 Bacon.later = (delay, value) ->
-  new EventStream ((sink) ->
-      push = ->
-        sink next(value)
-        sink end()
-      setTimeout push delay
-      nop
-  )
+  Bacon.sequentially(delay, [value])

 Bacon.sequentially = (delay, values) ->
   valuesLeft = values


disable debug logging

disable debug logging


use compositeUnsubscribe in sampledBy

use compositeUnsubscribe in sampledBy

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -689,24 +689,21 @@
           (myVal, otherVal) -> myVal.value()
       myVal = None
       subscribe = (sink) =>
-        unsubscribed = false
-        unsubMe = nop
-        unsubOther = nop
-        unsubBoth = -> unsubMe() ; unsubOther() ; unsubscribed = true
-        unsubMe = this.subscribeInternal (event) =>
+        unsubMe = (usubAll) => this.subscribeInternal (event) =>
           if event.hasValue()
             myVal = new Some(event)
           else if event.isError()
             sink event
-        unsubOther = sampler.subscribe (event) =>
+        unsubOther = (unsubAll) => sampler.subscribe (event) =>
           if event.hasValue()
             myVal.forEach (myVal) =>
               sink(event.apply(-> lazyCombinator(myVal, event)))
           else
             if event.isEnd()
-              unsubMe()
+              unsubAll()
             sink event
-        unsubBoth
+        compositeUnsubscribe unsubMe, unsubOther
+
       if sampler instanceof Property then new Property(subscribe) else new EventStream(subscribe)

     @subscribe = (sink) =>


working merge

working merge

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -49,8 +49,18 @@
   merge: (right) ->
     left = this
     new EventStream (sink) ->
-      left.subscribe(sink)
-      right.subscribe(sink)
+      ends = 0
+      smartSink = (event) ->
+        if event == Bacon.end
+          ends++
+          if ends == 2
+            sink Bacon.end
+          else
+            Bacon.more
+        else
+          sink event
+      left.subscribe(smartSink)
+      right.subscribe(smartSink)

   withHandler: (handler) ->
     new Dispatcher(@subscribe, handler).toEventStream()


refactor general error handling

refactor general error handling

--- scripts/asana-info.coffee
+++ scripts/asana-info.coffee
@@ -37,6 +37,9 @@
   > #{project.notes}
   """

+report_error = (msg, err) ->
+  msg.send "Something went wrong: #{err}"
+

 get_task = (task_id, robot, msg) ->
   robot.http(asana_task_endpoint task_id)
@@ -45,7 +48,7 @@

       # Check for general networking errors
       if err
-        msg.send "Something went wrong: #{err}"
+        report_error msg, err
         return

       # If Asana returns 403 Forbidden it is possible that the URL belongs to
@@ -87,7 +90,7 @@
     .get() (err, res, body) ->

       if err
-        msg.send "Something went wrong: #{err}"
+        report_error msg, err
         return

       if res.statusCode != 200


Put move packet back into client

Put move packet back into client

--- webserver/static/js/network.coffee
+++ webserver/static/js/network.coffee
@@ -8,6 +8,7 @@
 LOGIN_PID = 0
 PLAYER_UPDATE_PID = 1
 MAP_UPDATE_PID = 2
+MOVE_PLAYER_PID = 3

 # Packet Handling
 PacketHandler = ?(Any) -> Any
@@ -54,8 +55,13 @@

 # Packet Sending

-sendLogin :: (Str, Str) -> Any
-sendLogin = (username, token) ->
+@sendMove :: (Num, Num) -> Any
+@sendMove = (dx, dy) ->
+    data = { Dx: dx, Dy: dy }
+    sendPacket(MOVE_PLAYER_PID, data)
+
+@sendLogin :: (Str, Str) -> Any
+@sendLogin = (username, token) ->
     data = { Username: username, Token: token }
     sendPacket(LOGIN_PID, data)


Cleanup

Cleanup

--- src/components/generic/ViewportRelativeMotion.coffee
+++ src/components/generic/ViewportRelativeMotion.coffee
@@ -4,10 +4,6 @@
   delta * (speed - (correction - (correction * speed)))

 Crafty.c 'ViewportRelativeMotion',
-  init: ->
-
-  remove: ->
-
   viewportRelativeMotion: ({ x, y, offsetY, speed }) ->
     @_speed = speed
     if x? and y?


FE:ActivityTicker change event name entered to posted for status updates and comments

--- client/Social/Activity/views/activitytickeritem.coffee
+++ client/Social/Activity/views/activitytickeritem.coffee
@@ -7,7 +7,7 @@

   itemLinkViewClassMap :
     JAccount           : ProfileLinkView
-    JNewApp               : AppLinkView
+    JNewApp            : AppLinkView
     JTag               : TagLinkView
     JGroup             : GroupLinkView
     JStatusUpdate      : ActivityLinkView
@@ -174,9 +174,9 @@
   pistachio: ->
     {source, target} = @getData()
     if target.getId() is KD.whoami().getId()
-      return "{{> @avatar}} You entered a {{> @subj}}: {{> @object}}"
-
-    return "{{> @avatar}} {{> @actor}} entered a {{> @subj}}: {{> @object}}"
+      return "{{> @avatar}} You posted a {{> @subj}}: {{> @object}}"
+
+    return "{{> @avatar}} {{> @actor}} posted a {{> @subj}}: {{> @object}}"

 class ActivityTickerItem extends KDListItemView


profile: loader added to about page markdown fetch

--- client/app/MainApp/lazy/staticprofilecontroller.coffee
+++ client/app/MainApp/lazy/staticprofilecontroller.coffee
@@ -410,6 +410,10 @@

   addAboutLogic:(callback=->)->
     log 'adding about logic'
+
+    @profileLoadingBar.setClass 'active'
+    @profileLoaderView.show()
+
     @profileUser.fetchAbout (err,about)=>
       log arguments
       if err
@@ -425,6 +429,9 @@
         @profileContentView.addSubView @aboutWrapper = new KDView
           partial : partial

+        @profileLoadingBar.unsetClass 'active'
+        @profileLoaderView.hide()
+
         callback()

   addStaticLogic:(callback=->)->


fix: make addCidsInMessageCids pure

fix: make addCidsInMessageCids pure

--- client/src/daily-report/services/report-builder.coffee
+++ client/src/daily-report/services/report-builder.coffee
@@ -12,12 +12,12 @@

   addImageInMessageCid = (message, type, name, base64, id) ->
-    return (message.cids || []).concat([{type: type, name: name, base64: base64, id: id}])
+    return [...(message.cids || []), {type: type, name: name, base64: base64, id: id}];

   renderEmbeddedImages = (message, useCid) ->
     images = message.body.match(/data:image\/(.*);base64,([^"]*)/gm)

-    if images != null && images.length > 0
+    if images?.length
       for imageIndex of images
         match = /data:image\/(.*);base64,(.*)$/.exec(images[imageIndex])


regexp captures domain-only URLs correctly now


Fixing responses test

Fixing responses test

--- test/responses_test.coffee
+++ test/responses_test.coffee
@@ -11,7 +11,7 @@
     @msg =
       send: sinon.spy()

-    require('../src/real')(@robot)
+    require('../src/responses')(@robot)

   it 'registers a bad listener', ->
     expect(@robot.hear).to.have.been.calledWith(/(kicks|hits|bad) (bot|hubot)/)


draw piece pattern to separate image object

--- views/puzzle.coffee
+++ views/puzzle.coffee
@@ -9,8 +9,8 @@
     @piece = new PuzzlePiece(this)

-#    alert(" T W E L V E !!!")
-#    @puzzle_view.temp_draw_piece_mask(0,0)
+    @piece.construct_piece("a")
+    @piece.draw_piece(0,0)

@@ -107,7 +107,6 @@
     @image = new PieceImage(this)
     @redraw = new PieceRedrawBuffer

-    @construct_piece("a")

   construct_piece: (sym) ->
@@ -115,6 +114,11 @@
     @hexes = @get_hexes()
     @box.set_box_dimensions()
     @p_mask.draw_pattern()
+
+
+  draw_piece: (x,y) ->
+    context = @puzzle.puzzle_view.context_canvas
+    context.drawImage(@p_mask.img,0,0)

   get_hexes: () ->
@@ -146,14 +150,15 @@
     @hex_draw = @piece.puzzle.hex_draw
     @img = document.createElement('canvas')
     @img.id = "piece-mask"
+    @piece_mask_context = @img.getContext('2d')

   draw_pattern: () ->
     @img.width = @piece.box.width
     @img.height = @piece.box.height
     @hexes = @piece.hexes
-    @hex_draw.set_context("canvas")
-#    @hex_draw.set_context("piece_mask")
+#    @hex_draw.set_context("canvas")
+    @hex_draw.set_context("piece_mask")
     for hx in @hexes
       aa = hx[0]
       bb = hx[1]
@@ -167,12 +172,14 @@

     @piece = puzzle_piece
     @puzzle = @piece.puzzle
-#    @img = @puzzle.puzzle_view.piece_mask
-    @img = document.createElement('canvas')
-    @img.id = "piece-mask"
+    @img = @piece.p_mask.img
+#    @img = document.createElement('canvas')
+#    @img.id = "piece-mask"
     @img.width = @piece.box.width
     @img.height = @piece.box.height
-    @piece_image_context = @img.getContext("2d")
+    @piece_image_context = @img.getContext('2d')
+
+

 # FIXME Nothing references this method yet.
@@ -288,19 +295,20 @@
                     "#50cc80","#5050cc","#cc5080",
                     "#b4cc50","#50ccb4","#8050cc"]

-    @initialize_canvases()
+    @canvas = document.getElementById("puzzle-widget")
+    @context_canvas = @canvas.getContext('2d')

     @context = @get_drawing_context("canvas")
     @img = document.getElementById("photo")
     @context.drawImage(@img,100,30)

-  initialize_canvases: () ->
-    @canvas = document.getElementById("puzzle-widget")
-    @context_canvas = @canvas.getContext("2d")
-
-    @piece_mask = document.createElement('canvas')
-    @piece_image_context = @piece_mask.getContext("2d")
+#  initialize_canvases: () ->
+#    @canvas = document.getElementById("puzzle-widget")
+#    @context_canvas = @canvas.getContext('2d')
+
+#    @piece_mask = document.createElement('canvas')
+#    @piece_image_context = @piece_mask.getContext('2d')

 #  temp_draw_piece_mask: (x,y) ->
@@ -315,7 +323,12 @@
     alert("get_drawing_context:  mode = "+mode)
     switch mode
       when "canvas" then context = @context_canvas
-      when "piece_mask" then context = @piece_image_context
+      when "piece_mask"
+        alert("Using gdc with 'piece_mask'")
+        if @puzzle.piece
+          context = @puzzle.piece.p_mask.img.getContext('2d')
+        else
+          alert("@puzzle.piece == null")
     return context


Rename mock.load_args() to mock.read_args()

Cannot use parse_args() as read_args() calls parse_args().  Need
to keep searching for a better name as read_args() is still not
right.

--- src/TinyMock.coffee
+++ src/TinyMock.coffee
@@ -22,7 +22,7 @@
   mock_objects = undefined
   mock_methods = undefined

-  load_args = (args) ->
+  read_args = (args) ->
     check_usage(args)
     parse_args(args)
     check_expects_method_name()
@@ -81,7 +81,7 @@
   create_empty_mock_methods_list = ->
     mock_methods = new MockMethodList()

-  load_args(args)
+  read_args(args)
   setup_environment()
   try
     run_test_function()


Introduce local variable for clarity.

Introduce local variable for clarity.

--- src/TinyMock.coffee
+++ src/TinyMock.coffee
@@ -108,8 +108,9 @@
     fail(messages.ReservedMethodName, method_name) if is_reserved_method_name(method_name)

   install_mock_method = (self, method_name) ->
-    self[method_name] = new_MockMethod(self, method_name)
-    mock_methods.add(self[method_name])
+    mock_method = new_MockMethod(self, method_name)
+    mock_methods.add(mock_method)
+    self[method_name] = mock_method

   is_mock_method = (method) ->
     mock_methods.contains(method)


fix so that default location computes axis extent correctly

--- static/coffee/renderers/guide/axis.coffee
+++ static/coffee/renderers/guide/axis.coffee
@@ -324,7 +324,7 @@
     req = {}

     side = @mget('side')
-    loc = @mget('guidespec').location
+    loc = @mget('guidespec').location ? 'min'

     if not _.isString(loc)
       return req


Remove the testing artifact

Remove the testing artifact

--- library/gearing/kernel.coffee
+++ library/gearing/kernel.coffee
@@ -114,16 +114,3 @@
         @server = try http.createServer(@connect)
         @secure = try https.createServer(@connect)
         @connect.use(@middleware)
-
-augment = require "./augment"
-document = require "./document"
-instance = Kernel.bootstrap()
-augment(@)
-
-test = @GET "/api/test", (request, response) ->
-    docs = document.collect @kernel
-    response.end JSON.stringify docs
-
-document.describe test, ->
-    @synopsis("what the fuck?")
-    @argument("id", "integer", "ID of the fucker")


Secure logs API

Secure logs API

--- src/api/logs.coffee
+++ src/api/logs.coffee
@@ -1,8 +1,15 @@
 logger = require 'winston'
 moment = require 'moment'
 Q = require 'q'
+authorisation = require './authorisation'
+utils = require "../utils"

 exports.getLogs = ->
+  # Only admins can view server logs
+  if not authorisation.inGroup 'admin', this.authenticated
+    utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getLogs denied.", 'info'
+    return
+
   query = this.request.query
   if not query?
     query = {}


add destroy task

add destroy task

--- src/api/task.coffee
+++ src/api/task.coffee
@@ -18,3 +18,21 @@
 }

 exports.cancel = cancel
+
+#---------------------------------------------------------------------
+destroy = $coroutine ({task}) ->
+  xapi = @getXAPI task
+
+  $wait xapi.call 'task.destroy', task.ref
+
+  return true
+
+destroy.params = {
+  id: { type: 'string' },
+}
+
+destroy.resolve = {
+  task: ['id', 'task'],
+}
+
+exports.destroy = destroy


better state mismatch detection

better state mismatch detection


Increase timeout for one test case

Increase timeout for one test case

--- test/unit/container.coffee
+++ test/unit/container.coffee
@@ -50,6 +50,8 @@
       delete HTMLElement::attachShadow::

     it "should render an anchor with iframe and set iframe size", (done) ->
+      @timeout 5000
+
       render a, (el) ->
         expect el
           .instanceof HTMLElement


Document hi script

Document hi script

--- scripts/hi.coffee
+++ scripts/hi.coffee
@@ -1,4 +1,12 @@
-# Say hi
+# Description:
+#   Say Hi! 🤖
+#
+# Commands:
+#   hubot hi - Hi! 🤖
+#
+# Author:
+#   Zach Whaley (zachwhaley) <zachbwhaley@gmail.com>
+

 module.exports = (robot) ->
   robot.respond /hi/i, (res) ->


Fixed: Logic error of environment detection.

--- src/index.coffee
+++ src/index.coffee
@@ -13,7 +13,7 @@
 groupRouter       = require './routes/group'        # 引用群组相关接口
 miscRouter        = require './routes/misc'         # 引用其他功能接口

-if env = process.env.NODE_ENV isnt 'development' and env isnt 'production'
+if (env = process.env.NODE_ENV) isnt 'development' and env isnt 'production'
   console.log "Error: NODE_ENV must be set to 'development' or 'production'."
   return process.exit()


add template links SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS to config file

--- server-ce/settings.coffee
+++ server-ce/settings.coffee
@@ -565,6 +565,8 @@
 	settings.templates =
 		mountPointUrl: "/templates"
 		user_id: process.env["SHARELATEX_TEMPLATES_USER_ID"]
+
+	settings.templateLinks: parse(process.env["SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS"])

 # /Learn


Fixes #338. Restore cursor and scroll position for beautify on save

--- src/beautify.coffee
+++ src/beautify.coffee
@@ -8,6 +8,7 @@
 Beautifiers = require("./beautifiers")
 beautifier = new Beautifiers()
 defaultLanguageOptions = beautifier.options
+logger = require('./logger')(__filename)

 # Lazy loaded dependencies
 fs = null
@@ -355,7 +356,6 @@
     "Options from `.jsbeautifyrc` files starting from directory `#{path.dirname(filePath)}` and going up to root\n" +
     "```json\n#{JSON.stringify(projectOptions, undefined, 4)}\n```")
     logs = ""
-    logger = require('./logger')(__filename)
     subscription = logger.onLogging((msg) ->

         # console.log('logging', msg)
@@ -392,18 +392,28 @@
             path ?= require('path')
             # Get Grammar
             grammar = editor.getGrammar().name
+            # Get file extension
+            fileExtension = path.extname(filePath)
+            # Remove prefix "." (period) in fileExtension
+            fileExtension = fileExtension.substr(1)
             # Get language
-            fileExtension = path.extname(filePath)
-            languages = beautifier.languages.getLanguages({grammar, fileExtension})
+            languages = beautifier.languages.getLanguages({grammar, extension: fileExtension})
             if languages.length < 1
                 return
             # TODO: select appropriate language
             language = languages[0]
             # Get language config
-            beautifyOnSave = atom.config.get("atom-beautify.language_#{language.namespace}_beautify_on_save")
+            key = "atom-beautify.language_#{language.namespace}_beautify_on_save"
+            beautifyOnSave = atom.config.get(key)
+            logger.verbose('save editor positions', key, beautifyOnSave)
             if beautifyOnSave
+                posArray = getCursors(editor)
+                origScrollTop = editor.getScrollTop()
                 beautifyFilePath(filePath, ->
                     buffer.reload()
+                    logger.verbose('restore editor positions', posArray,origScrollTop)
+                    setCursors(editor, posArray)
+                    editor.setScrollTop(origScrollTop)
                 )
             )
         plugin.subscribe disposable


Don't use SRC_DIRs, use the user-provided inputs

--- src/biscotto.coffee
+++ src/biscotto.coffee
@@ -236,7 +236,7 @@
                     relativePath = path.normalize(filename.replace(process.cwd(), ".#{path.sep}")) if filename.indexOf(process.cwd()) == 0
                     shortPath = relativePath.replace(path.resolve(process.cwd(), input) + path.sep, '')
                     # don't parse Gruntfile.coffee, specs, or anything not in a src dir
-                    parser.parseFile relativePath if _.some(SRC_DIRS, (dir) -> ///^#{dir}///.test(shortPath))
+                    parser.parseFile relativePath if _.some(options.inputs, (dir) -> ///^#{dir}///.test(shortPath))
                   catch error
                     throw error if options.debug
                     console.log "Cannot parse file #{ filename }@#{error.location.first_line}: #{ error.message }"


fix #133: use URIjs to generate permalink

--- src/builtins.coffee
+++ src/builtins.coffee
@@ -168,13 +168,12 @@
       render: -> React.DOM.a {href: @props.href}, @props.value

     component_cmd 'permalink', 'Create a link to the code in the input cell above', (code) ->
-      a = document.createElement 'a'
-      # TODO app should generate links
-      a.href = location.href
-      a.hash = null
+      uri = URI location.href
+      uri.hash null
       code ?= @previously_run()
-      a.search = '?' + encodeURIComponent btoa code
-      LinkComponent href: a.href, value: a.href
+      uri.query '?' + encodeURIComponent btoa code
+      uri = uri.toString()
+      LinkComponent href: uri, value: uri

     PromiseStatusComponent = React.createClass
       render: ->


shell.moveToTrash => shell.moveItemToTrash

--- src/packages/tree-view/lib/tree-view.coffee
+++ src/packages/tree-view/lib/tree-view.coffee
@@ -251,7 +251,7 @@
     atom.confirm(
       "Are you sure you would like to delete the selected #{entryType}?",
       "You are deleting #{entry.getPath()}",
-      "Move to Trash", (=> shell.moveToTrash(entry.getPath())),
+      "Move to Trash", (=> shell.moveItemToTrash(entry.getPath())),
       "Cancel", null
       "Delete", (=> fsUtils.remove(entry.getPath()))
     )


Removed debugging print.

Removed debugging print.

--- server/lib/signals.coffee
+++ server/lib/signals.coffee
@@ -7,8 +7,6 @@
   currentlyProcessedPublicationId = id

 SegfaultHandler.registerHandler (stack, signal, address) ->
-  console.log "IN", currentlyProcessedPublicationId
-
   # TODO: Should we log also errors outside publication processing?
   return unless currentlyProcessedPublicationId


Convert full text for TEI files.

Convert full text for TEI files.

--- server/publication.coffee
+++ server/publication.coffee
@@ -101,7 +101,7 @@
     switch @mediaType
       when 'pdf' then @processPDF()
       when 'tei' then @processTEI()
-      else throw new Error "Unsupported media type for processing: #{ @mediaType }"
+      else throw new Error "Unsupported media type: #{ @mediaType }"

   processPDF: =>
     currentlyProcessingPublication @_id
@@ -157,7 +157,17 @@
   processTEI: =>
     tei = Storage.open @cachedFilename()

-    cheerio.load(tei).root().text().replace(/\s+/g, ' ').trim()
+    @fullText = cheerio.load(tei).root().text().replace(/\s+/g, ' ').trim()
+
+    # TODO: We could also add some additional information (statistics, how long it took and so on)
+    @processed = moment.utc().toDate()
+    Publication.documents.update @_id,
+      $set:
+        processed: @processed
+        fullText: @fullText
+
+    # TODO: Maybe we should use instead of GeneratedField just something which is automatically triggered, but we then update multiple fields, or we should allow GeneratedField to return multiple fields?
+    @fullText

   _importingFilename: =>
     # We assume that importing contains only this person, see comment in uploadPublication


Send parsed JSON as "loadInteractiveGlobal" argument (app.js)

[#90778062]

LARA does it, so we are closer to our target env.

--- src/code/app.coffee
+++ src/code/app.coffee
@@ -9,7 +9,7 @@
     @setupInputWatchers()
     @restartPhone($("#interactive-iframe"))
     @globalState = {}
-
+
   setSource: (src) ->
     $src    = $("#interactiveSource")
     $iframe = $("#interactive-iframe")
@@ -40,11 +40,11 @@
         obj = JSON.parse(value) # TODO This has to be an object...
         l.warn "loadInteractive #{value} called"
         @post "loadInteractive", obj
-
+
       "getLearnerUrl": (e) =>
         l.warn "getLearnerUrl called"
         @post "getLearnerUrl"
-
+
       "getExtendedSupport": (e) =>
         l.warn "getExtendedSupport called"
         @post "getExtendedSupport"
@@ -56,29 +56,29 @@
       "loadInteractiveGlobal": (e) =>
         value = $('#dataOut').val()
         if value.length < 1
-          value = "{'fake': 'data', 'for': 'you'}"
+          value = '{"fake": "data", "for": "you"}'
         l.warn "loadInteractiveGlobal #{value} called"
-        @post "loadInteractiveGlobal", value
+        @post "loadInteractiveGlobal", JSON.parse(value)

       # TODO:
       # "htmlFragRequest": (e) =>
       #   l.warn "htmlFragRequest called"
       #   @post "htmlFragRequest"
-
+
       # "takeSnapshot": (e) =>
       #   l.warn "takeSnapshot called"
       #   @post "takeSnapshot"
-
+
       # TODO:
       # "lara-logging-present": (e) =>
       #   l.warn "getExtendedSupport called"
       #   @iframePhoneRpc.call message: 'lara-logging-present'
-
+
     bindButton = (name,f) =>
       l.info "binding button: #{name}"
       $elm = $ "##{name}"
       $elm.on "click", (e) => f(e)
-
+
     bindButton(buttonname, action) for buttonname, action of buttons

   ##
@@ -99,7 +99,7 @@
           server: "//snapshot.concord.org/shutterbug"
       else
         alert "shutterbug.js must be installed on the page"
-
+
   ##
   ##
   restartPhone: ($iframe) ->
@@ -109,12 +109,12 @@
     @queue = []
     @already_setup  = false
     @iframePhone = new iframePhone.ParentEndpoint($iframe[0], @phoneAnswered.bind(@))
-
+
     # TODO: (rpc)
     # @iframePhoneRpc = new iframePhone.IframePhoneRpcEndpoint
     #   phone: @iframePhone
     #   namespace: 'lara-logging'
-
+
   ##
   ##
   phoneAnswered: ->


Added fix to h* indentation

Added fix to h* indentation


making the compile function accessible

making the compile function accessible

--- src/compiler.coffee
+++ src/compiler.coffee
@@ -1,6 +1,8 @@
 _ = require '../third_party/_.js'
 util = require './util'
 {Method} = require './methods'
+
+root = exports ? this.compiler = {}

 class BlockChain

@@ -356,10 +358,11 @@
   """

 # TODO: move to a separate file
-fs = require 'fs'
-ClassFile = require '../src/ClassFile'
-fname = if process.argv.length > 2 then process.argv[2] else '/dev/stdin'
-bytes_array = util.bytestr_to_array fs.readFileSync(fname, 'binary')
-class_data = new ClassFile bytes_array
-
-console.log root.compile class_data
+if require.main == module
+  fs = require 'fs'
+  ClassFile = require '../src/ClassFile'
+  fname = if process.argv.length > 2 then process.argv[2] else '/dev/stdin'
+  bytes_array = util.bytestr_to_array fs.readFileSync(fname, 'binary')
+  class_data = new ClassFile bytes_array
+
+  console.log root.compile class_data


missing space.

missing space.

--- scope.coffee
+++ scope.coffee
@@ -17,7 +17,7 @@
   # as well as a reference to the **Block** node is belongs to, which is
   # where it should declare its variables, and a reference to the function that
   # it wraps.
-  constructor:(@parent, @expressions, @method) ->
+  constructor: (@parent, @expressions, @method) ->
     @variables = [{name: 'arguments', type: 'arguments'}]
     @positions = {}
     Scope.root = this unless @parent


Fixed bug with initial file copy

Fixed bug with initial file copy

--- src/creative.coffee
+++ src/creative.coffee
@@ -54,6 +54,7 @@

 # If there is no assets directory, then we should build one
 if not fs.existsSync './assets/'
+  console.log 'Creating an assets/ directory'.yellow
   needAssets = true
   fs.mkdirSync './assets/'

@@ -78,17 +79,18 @@
     for fileName in fs.readdirSync srcDir
       srcPath = "#{srcDir}/#{fileName}"
       destPath = "#{destDir}/#{fileName}"
-      if not ignoreFile srcPath
-        stat = fs.statSync srcPath
-        if stat.isDirectory()
-          console.log "#{indent}#{fileName}/".white
-          fs.mkdirSync destPath unless fs.existsSync destPath
-          rcopy srcPath, destPath, indent + '  '
-        else if not fileName.match /\.swp$/
-          console.log "#{indent}  #{fileName}".white
-          fs.writeFileSync(destPath, fs.readFileSync(srcPath))
+
+      stat = fs.statSync srcPath
+      if stat.isDirectory()
+        console.log "#{indent}#{fileName}/".white
+        fs.mkdirSync destPath unless fs.existsSync destPath
+        rcopy srcPath, destPath, indent + '  '
+      else if not fileName.match /\.swp$/
+        console.log "#{indent}  #{fileName}".white
+        fs.writeFileSync(destPath, fs.readFileSync(srcPath))

   # Recursively copy all the template files into the current project
+  console.log "Creating a project skeleton in #{__dirname}/../template".yellow
   rcopy __dirname + '/../template', process.cwd(), '  '


Changed tabs to spaces in off-canvas coffee.


rm console.log

rm console.log

--- tutor/src/api/index.coffee
+++ tutor/src/api/index.coffee
@@ -246,7 +246,6 @@
 }

 start = (bootstrapData) ->
-  console.log(bootstrapData)
   for storeId, model of BOOTSTRAPED_MODELS
     data = bootstrapData[storeId]
     model.bootstrap(data)


Use document.URL rather than going through the document's window.

--- application/chrome/content/wesabe/dom/Page.coffee
+++ application/chrome/content/wesabe/dom/Page.coffee
@@ -54,7 +54,7 @@
   # Returns the URL of this page.
   #
   @::__defineGetter__ 'url', ->
-    privacy.taint @defaultView.location.href
+    privacy.taint @document.URL

   #
   # Returns true if this page is in a frame, false otherwise.


Remove unused dependency

Remove unused dependency

--- validator/index.coffee
+++ validator/index.coffee
@@ -1,5 +1,4 @@
 tv4 = require 'tv4'
-formats = require 'tv4-formats'

 tv4.addFormat 'objectid', (data) ->
   if typeof data is 'string' and /^(?=[a-f\d]{24}$)(\d+[a-f]|[a-f]+\d)/i.test(data)


Translate setting in progress

Translate setting in progress

--- def/th/settings.cson
+++ def/th/settings.cson
@@ -1,53 +1,53 @@
 Settings:
-  "tab-title": "Settings"
+  "tab-title": "การตั้้้้้งค่า"
   menu: [
     {
       _label: "Core"
-      value: "Core"
+      value: "แกนหลัก"
     }
     {
       _label: "Editor"
-      value: "Editor"
+      value: "อิดิเตอร์"
     }
     {
       _label: "System"
-      value: "System"
+      value: "ระบบ"
     }
     {
       _label: "Keybindings"
-      value: "Keybindings"
+      value: "ผูกค่าปุ่มกด"
     }
     {
       _label: "Packages"
-      value: "Packages"
+      value: "แพคเก็จ"
     }
     {
       _label: "Themes"
-      value: "Themes"
+      value: "ธีม"
     }
     {
       _label: "Updates"
-      value: "Updates"
+      value: "อัพเดต"
     }
     {
       _label: "Install"
-      value: "Install"
+      value: "ติดตั้ง"
     }
   ]
-  "btn-open-config-folder": "Open Config Folder"
+  "btn-open-config-folder": "เปิดโฟลเดอร์กำหนดค่า"
   sectionHeadings: [
-    {_label: "Core Settings", value: "Core Settings"}
-    {_label: "Editor Settings", value: "Editor Settings"}
-    {_label: "System Settings", value: "System Settings"}
-    {_label: "Keybindings", value: "Keybindings"}
-    {_label: "Installed Packages", value: "Installed Packages"}
-    {_label: "Choose a Theme", value: "Choose a Theme"}
-    {_label: "Installed Themes", value: "Installed Themes"}
-    {_label: "Install Packages", value: "Install Packages"}
-    {_label: "Featured Packages", value: "Featured Packages"}
-    {_label: "Install Themes", value: "Install Themes"}
-    {_label: "Featured Themes", value: "Featured Themes"}
-    {_label: "Available Updates", value: "Available Updates"}
+    {_label: "Core Settings", value: "การกำหนดค่าหลัก"}
+    {_label: "Editor Settings", value: "การกำหนดค่าตัวแก้ไข"}
+    {_label: "System Settings", value: "การแก้ไขของระบบ"}
+    {_label: "Keybindings", value: "การผูกปุ่มกด"}
+    {_label: "Installed Packages", value: "แพคเก็จที่ติดตั้ง"}
+    {_label: "Choose a Theme", value: "เลือกรูปแบบ"}
+    {_label: "Installed Themes", value: "รูปแบบที่ติดตั้ง"}
+    {_label: "Install Packages", value: "ติดตั้งแพคเก็จ"}
+    {_label: "Featured Packages", value: "แพคเก็จแนะนำ"}
+    {_label: "Install Themes", value: "ติดตั้งรูปแบบ"}
+    {_label: "Featured Themes", value: "รูปแบบแนะนำ"}
+    {_label: "Available Updates", value: "รายการปรับปรุง"}
   ]
   subSectionHeadings: [
     {_label: "Invisible", value: "Invisible"}


Workspace: Implemented host disconnected.

--- client/app/CommonViews/workspace/collaborativeworkspace.coffee
+++ client/app/CommonViews/workspace/collaborativeworkspace.coffee
@@ -23,6 +23,8 @@

       keys = snapshot.val()?.keys

+      @workspaceRef.onDisconnect().remove()  if @amIHost()
+
       if keys # if we have keys this means we're about to join an old session
         log "it's an old session, impressed!"
         @sessionData  = keys
@@ -36,6 +38,11 @@

     @workspaceRef.on "child_added", (snapshot) =>
       log "everything is something happened", "child_added", snapshot.val(), snapshot.name()
+
+    @workspaceRef.on "child_removed", (snapshot) =>
+      log "possible disconnection occured"
+
+      @showDisconnectedModal()  unless @disconnectedModal

     @on "NewPanelAdded", (panel) ->
       log "New panel created", panel
@@ -65,7 +72,10 @@

   ready: -> # have to override for collaborative workspace

-  showSessionModal: ->
+  amIHost: ->
+    [sessionOwner] = @sessionKey.split ":"
+    return sessionOwner == KD.nick()
+
   showNotActiveView: ->
     notValid = new KDView
       cssClass : "not-valid"


sidebarmachineslistitem: fix leave session modal apperance

--- client/app/lib/components/sidebarmachineslistitem/index.coffee
+++ client/app/lib/components/sidebarmachineslistitem/index.coffee
@@ -166,6 +166,7 @@
   renderLeaveSharedMachine: ->

     return null  if @machine('type') is 'own' or @machine 'hasOldOwner'
+    return null  if @state.activeMachine isnt @machine('_id')
     return null  unless @machine 'isApproved'

     <LeaveSharedMachineWidget


remove debug statement

remove debug statement

--- server/app.coffee
+++ server/app.coffee
@@ -35,7 +35,6 @@
       Roles.addUsersToRoles id, user.roles

   Accounts.validateNewUser (user) ->
-    console.log Meteor.userId()
     try
       return true if isUserAuthorised Meteor.userId(), ['admin', 'manage-users']
     catch


trust proxy X-Forwarded-* headers when PROXIED is set

--- server/app.coffee
+++ server/app.coffee
@@ -9,6 +9,7 @@
   @set 'view engine', 'jade'
   @set 'views', join __dirname, 'views'
   @set 'url', process.env.URL or "http://localhost:#{@settings.port}/"
+  @enable 'trust proxy' if process.env.PROXIED

   @locals
     url: @settings.url


bye fat arrow

bye fat arrow

--- lib/Default.coffee
+++ lib/Default.coffee
@@ -38,7 +38,7 @@
     messageType + message

   generateTypeMessage: (type) ->
-    (message...) =>
+    (message...) ->
       message = @format message
       @transport @generateMessage type, message
       this


codepen: removing unnecessary variables

codepen: removing unnecessary variables

--- app/_src/components/codepen-embed.coffee
+++ app/_src/components/codepen-embed.coffee
@@ -2,10 +2,8 @@

 	ASSET_EI_JS_URL = '//assets.codepen.io/assets/embed/ei.js'
 	DATA_SLUG = 'slug'
-	DATA_OFFSET = 'offset'
 	DATA_RATIO = 'ratio'
 	HEIGHT = 400
-	watcher = null

 	constructor: (@$context, data) ->
 		if data?.isPjax


Fix wrong js

Fix wrong js

--- app/assets/javascripts/answers.js.coffee
+++ app/assets/javascripts/answers.js.coffee
@@ -9,8 +9,8 @@
     max_order = 0
     $(answers).find("[name$='[given_order]']").each (index, answer) ->
       value = parseFloat($(answer).val())
-      max_order = if value > max_given_order then value else max_given_order
-    return max_given_order
+      max_order = if value > max_order then value else max_order
+    return max_order

   nestedAnswers: ->
     $('.js-answers').each (index, answers) ->