added drag n drop functionality, there are still some bugs to be fixed.

--- plugins/image.coffee
+++ plugins/image.coffee
@@ -190,9 +190,211 @@
             xposition = jQuery(@options.editable.element).offset().left + jQuery(@options.editable.element).outerWidth() - 3 # 3 is the border width of the contenteditable border
             yposition = jQuery(@options.toolbar).offset().top - jQuery(document).scrollTop() - 29
             @options.dialog.dialog("option", "position", [xposition, yposition])
+
+            # Add DragnDrop
+            @_addDragnDrop()
+
+            # Show Dialog
             @options.dialog.dialog("open")

         _closeDialog: ->
             @options.dialog.dialog("close")

+        _addDragnDrop: ->
+            helper =
+                # Delay the execution of a function
+                delayAction: (functionToCall, delay) ->
+                    timer = clearTimeout(timer)
+                    timer = setTimeout(functionToCall, delay)  unless timer
+
+                # Calculate position on an initial drag
+                calcPosition: (ui, offset) ->
+                    position = offset.left + third
+                    if ui.offset.left >= position and ui.offset.left <= (offset.left + third * 2)
+                        "middle"
+                    else if ui.offset.left < position
+                        "left"
+                    else "right"  if ui.offset.left > (offset.left + third * 2)
+
+                # Insertion Configuration Object
+                insertConfig:
+                    left:
+                        left: 0
+                        float: "left"
+                        padding: "0 10px 0 0"
+
+                    right:
+                        left: 0
+                        float: "right"
+                        padding: "0 0 0 10px"
+
+                    middle:
+                        padding: "0 0 10px 0"
+                        float: "none"
+
+                # removes all temporary nodes created before
+                removeTmpNodes: ->
+                    $(".tmp, .tmpBig", editable).remove()  if $(".tmp", editable)
+
+                # create image to be inserted
+                createInsertElement: (ui, tmp) ->
+                    image = ui.draggable[0]
+                    src = image.src
+                    width = image.width
+                    height = image.height
+                    altText = image.alt
+                    imageInsert = $("<img>").attr(
+                        src: src
+                        width: width
+                        height: height
+                        alt: altText
+                        class: (if tmp then "tmp" else "")
+                    ).css("display", "none")
+                    imageInsert
+
+                createHelperElement: ->
+                    $("<div/>").addClass "tmp tmpBig"
+
+                showOverlay: (position) ->
+
+                    eHeight = editable.height() + parseFloat(editable.css('paddingTop')) + parseFloat(editable.css('paddingBottom'))
+
+                    overlay.big.css height: eHeight
+                    overlay.left.css height: eHeight
+                    overlay.right.css height: eHeight
+
+                    switch position
+                        when "left"
+                            overlay.big.addClass("blueOverlayLeft").removeClass("blueOverlayRight").css(left: third).show()
+                            overlay.left.hide()
+                            overlay.right.hide()
+                        when "middle"
+                            overlay.big.removeClass "blueOverlayLeft blueOverlayRight"
+                            overlay.big.hide()
+                            overlay.left.show()
+                            overlay.right.show()
+                        when "right"
+                            overlay.big.addClass("blueOverlayRight").removeClass("blueOverlayLeft").css(left: 0).show()
+                            overlay.left.hide()
+                            overlay.right.hide()
+                        else
+
+                # check if the element was dragged into or within a contenteditable
+                checkOrigin: (event) ->
+                    unless $(event.srcElement).parents("[contenteditable]").length is 0
+                        true
+                    else
+                        false
+
+            dnd =
+                handleDragEvent: (event, ui) ->
+                    tmpObject = $(".tmp", editable)
+                    internalDrop = helper.checkOrigin(event)
+                    position = helper.calcPosition(ui, offset)
+                    $(event.target).remove()  if internalDrop
+                    helper.showOverlay position
+                    if position is "middle"
+                        if tmpObject.parent("div").length is 0
+                            tmpObject.wrap $("<div/>")
+                            tmpObject.css "display", "none"
+                        tmpObject.parent("div").css(helper.insertConfig[position]).addClass "tmpBig"
+                    else
+                        $(".tmpBig").replaceWith $(".tmp, editable")  if $(".tmpBig")
+                        tmpObject.css(helper.insertConfig[position]).css "display", "block"
+
+                handleStopEvent: (event, ui) ->
+                    internalDrop = helper.checkOrigin(event)
+                    $(event.target).remove()  if internalDrop
+
+                    overlay.big.hide()
+                    overlay.left.hide()
+                    overlay.right.hide()
+
+                handleDropEvent: (event, ui) ->
+                    # check whether it's an internal drop or not
+                    internalDrop = helper.checkOrigin(event)
+                    helper.removeTmpNodes()
+                    position = helper.calcPosition(ui, offset, internalDrop)
+                    imageInsert = helper.createInsertElement(ui, false)
+                    if position is "middle"
+                        imageInsert.css(helper.insertConfig[position]).css
+                          position: "relative"
+                          left: (editable.width() - $(ui.helper).width()) / 2
+                          display: "block"
+
+                        imageInsert.insertBefore $(event.target)
+                    else
+                        imageInsert.css(helper.insertConfig[position]).css "display", "block"
+                        $(event.target).prepend imageInsert
+
+                    overlay.big.hide()
+                    overlay.left.hide()
+                    overlay.right.hide()
+                     # add draggable functionality to the image after it has been dropped
+                    imageInsert.draggable
+                        cursor: "move"
+                        helper: "clone"
+                        drag: dnd.handleDragEvent
+                        stop: dnd.handleStopEvent
+
+                handleOverEvent: (event, ui) ->
+
+                  editable.append overlay.big
+                  editable.append overlay.left
+                  editable.append overlay.right
+
+                  $(ui.helper).css "backgroundColor", "green"
+                  helper.removeTmpNodes()
+                  position = helper.calcPosition(ui, offset)
+
+                  createTmp = ->
+                      if position is "middle"
+                          helperInsert = helper.createHelperElement()
+                      else
+                          helperInsert = helper.createInsertElement(ui, true)
+                      $(event.target).prepend helperInsert
+                      helper.showOverlay position
+
+                  helper.delayAction createTmp, 100
+
+                handleLeaveEvent: (event, ui) ->
+                    $(ui.helper).css "backgroundColor", "red"
+                    $('.bigBlueOverlay, .smallDottedOverlay').remove()
+                    helper.removeTmpNodes()
+
+                createHelper: (event) ->
+                    console.log(event.currentTarget)
+                    $('<div>').css({
+                        backgroundImage: "url(" + $(event.currentTarget).attr('src') + ")"
+                        width: '100px'
+                        height: '100px'
+                    }).addClass('customHelper');
+
+
+            editable = $(@options.editable.element)
+            offset = editable.offset()
+            third = parseFloat(editable.width() / 3)
+            overlayMiddleConfig =
+                width: third
+                height: editable.height()
+
+            overlay =
+                big: $("<div/>").addClass("bigBlueOverlay").css(
+                  width: third * 2
+                  height: editable.height()
+                )
+                left: $("<div/>").addClass("smallDottedOverlay smallDottedOverlayLeft").css(overlayMiddleConfig)
+                right: $("<div/>").addClass("smallDottedOverlay smallDottedOverlayRight").css(overlayMiddleConfig).css("left", third * 2)
+
+            $(".rotationWrapper img").draggable
+                cursor: "move"
+                helper: dnd.createHelper
+                drag: dnd.handleDragEvent
+                stop: dnd.handleStopEvent
+
+            $(@options.editable.element).children('p').droppable
+                tolerance: "pointer"
+                drop: dnd.handleDropEvent
+                over: dnd.handleOverEvent
+                out: dnd.handleLeaveEvent
 )(jQuery)


fixing database

fixing database

--- server/src/db.coffee
+++ server/src/db.coffee
@@ -1,4 +1,4 @@
 mongoose = require 'mongoose'
 mongoose.Promise = require 'bluebird'
-mongoose.connect "mongodb://#{process.env.MONGO_HOST || 'localhost'}/"
+mongoose.connect "mongodb://#{process.env.MONGO_HOST || 'localhost'}/wedding"
 mongoose


Add promise support to function that was missed.

--- lib/clever.coffee
+++ lib/clever.coffee
@@ -257,14 +257,10 @@
         ca: certs
       _(opts).extend(headers: options.headers) if options.headers
       apply_auth clever.auth, opts
-      if _(obj).isFunction()
+      if not obj or _(obj).isFunction()
         cb = obj
         _(opts).extend { method: 'get', json: true }
-      quest opts, (err, resp, body) =>
-        return cb err if err
-        handle_errors resp, body, (err, resp, body) ->
-          return cb err if err
-          cb err, body?.data
+      make_request opts, cb

   class District extends Resource
     @path: '/v1.1/districts'


repair

repair

--- lib/config.coffee
+++ lib/config.coffee
@@ -24,7 +24,6 @@
         atom.config.set('isotope-light-ui.backgroundImage', 'false')
       else
         body.setAttribute('isotope-light-ui-bg-gradient', 'false')
-        applyBackgroundImage()

     applyBackgroundImage = () ->
       if atom.config.get('isotope-light-ui.backgroundImage')
@@ -65,7 +64,6 @@
     applyCompactness()
     applyBackgroundGradient()
     applyBackgroundImage()
-    applyBackgroundColor()
     applyGutterStyle()
     applyTooltipContrast()
     applyEditorFont()


document changes to output function

document changes to output function

--- lib/config.coffee
+++ lib/config.coffee
@@ -96,7 +96,14 @@

   ###*
    * Given a vinyl-wrapped file and optional extension, this function produces
-   * the path to the file's destination.
+   * the path to the file's destination. To do so, it goes through these steps:
+   *
+   * - Take the relative path and split it by /
+   * - If it's in a 'dumped' directory, remove that directory
+   * - URI encode any strange characters
+   * - Add the full path to the output folder to the beginning
+   * - Join it back together with /
+   * - If an extension override was provided, replace the extension
    *
    * @param  {File} f - vinyl instance
    * @param  {String} ext - file extension, no dot


Added TextareaInput

Added TextareaInput

--- lib/inputs.coffee
+++ lib/inputs.coffee
@@ -3,7 +3,7 @@
 cx = require "react/lib/cx"
 ReactCSSTransitionGroup = require "react/lib/ReactCSSTransitionGroup"

-{div, input, select, option, i, button} = React.DOM
+{div, input, select, option, i, button, textarea} = React.DOM

 monthMap = _.map [
   "January"
@@ -69,7 +69,7 @@

     return ReactCSSTransitionGroup transitionName: "fade", indicator

-  renderInput: (options) ->
+  renderInput: (el, options) ->
     props = _.extend {},
       ref: "input"
       value: @props.value
@@ -79,7 +79,7 @@
     , options

     return div className: "form-field",
-      @transferPropsTo input props
+      @transferPropsTo el props
       @renderIndicator()

 TextInput = React.createClass
@@ -87,14 +87,21 @@
   mixins: [Input, Text]

   render: ->
-    @renderInput()
+    @renderInput input

 PasswordInput = React.createClass
   displayName: "PasswordInput"
   mixins: [Input, Text]

   render: ->
-    @renderInput type: "password"
+    @renderInput input, type: "password"
+
+TextareaInput = React.createClass
+  displayName: "TextareaInput"
+  mixins: [Input, Text]
+
+  render: ->
+    @renderInput textarea

 DateInput = React.createClass
   displayName: "DateInput"


Test missing Google API key on shorten url

--- test/utils/index.coffee
+++ test/utils/index.coffee
@@ -52,6 +52,12 @@
     Utils.formatIndefiniteArticle('car').should.equal 'a car'
     Utils.formatIndefiniteArticle('apple').should.equal 'an apple'

+  it 'should throw error on missing api key on shorten url', ->
+    @faulty = ->
+      Utils.shortenUrl 'https://koding.com', (->)
+
+    @faulty().should.throw
+
   # it 'should create external link', ->
   #   appendChildSpy = sinon.spy document.body.appendChild
   #   removeChildSpy = sinon.spy document.body.removeChild


Update Can I Use updater to work with notes

--- updaters/prefixes.coffee
+++ updaters/prefixes.coffee
@@ -25,7 +25,7 @@
   for browser, versions of data.stats
     for interval, support of versions
       for version in interval.split('-')
-        if updater.browsers[browser] and support.match(/\sx$/)
+        if updater.browsers[browser] and support.match(/\sx($|\s)/)
           version = version.replace(/\.0$/, '')
           need.push(updater.browsers[browser] + ' ' + version)
   need


Kernel: Drop starting status IO messages

* Kernels send starting status IO messages that have an empty
  parent_header.

--- lib/kernel.coffee
+++ lib/kernel.coffee
@@ -307,6 +307,11 @@
             console.log "Invalid message: Missing content"
             return false

+        if message.content.execution_state is 'starting'
+            # Kernels send a starting status message with an empty parent_header
+            console.log "Dropped starting status IO message"
+            return false
+
         unless message.parent_header?
             console.log "Invalid message: Missing parent_header"
             return false


return early if lint is not specified as a plugin for the current project

--- lib/linter.coffee
+++ lib/linter.coffee
@@ -12,9 +12,10 @@

   lint: (textEditor) ->
     return new Promise (resolve, reject) =>
+      return resolve [] unless @manager.config.config.plugins.lint?.active
+      return resolve [] unless @manager.server and @manager.config.config
+
       messages = []
-      return resolve [] unless @manager.server and @manager.config.config
-      return resolve [] unless @manager.config.config.plugins.lint?.active

       buffer = textEditor.getBuffer()
       URI = textEditor.getURI()


Add OPTIONS support

Add OPTIONS support

--- lib/router.coffee
+++ lib/router.coffee
@@ -5,7 +5,7 @@
 exports.Router =
 class Router
   constructor: ->
-    @methods =  [ 'GET', 'HEAD', 'POST', 'PUT', 'DELETE' ]
+    @methods =  [ 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'OPTIONS' ]
     @routes =   []

   # router.match( path [, method] )
@@ -37,6 +37,14 @@
   #
   get: ( path )->
     @match path, 'GET'
+
+  # ### router.options( path )
+  # equivalent to
+  #
+  #     router.match( path, 'OPTIONS' )
+  #
+  options: ( path )->
+    @match path, 'OPTIONS'

   # ### router.put( path )
   # equivalent to


damn, another typo

damn, another typo

--- lib/server.coffee
+++ lib/server.coffee
@@ -19,7 +19,7 @@
 server.get('/logout/',
   (req, resp) ->
     if req.user?
-      res.clearCookie('userSession')
+      resp.clearCookie('userSession')
       req.session.auth = null
       req.session.destroy(->)
     resp.redirect("/login/"))


more readable stack at the top & outside the json

--- heck.coffee
+++ heck.coffee
@@ -26,6 +26,11 @@
       map = plates.Map()
       if data.options.debug
         debugHTML  = data.options.debugBlock.start
+        debugHTML += data.stack
+        debugHTML += data.options.debugBlock.close
+        debugHTML += '<br/>'
+        delete data.stack
+        debugHTML += data.options.debugBlock.start
         debugHTML += JSON.stringify data, null, '  '
         debugHTML += data.options.debugBlock.close
         map.where('class').is(data.options.debugClass).partial debugHTML


reveal item selected when autoPreview activated

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -34,7 +34,7 @@
       return if textChanged
       @updateGutter(newBufferPosition)
       if @isAutoPreview() and (oldBufferPosition.row isnt newBufferPosition.row)
-        @confirm(preview: true)
+        @preview()

     @editor.getTitle = => ["Narrow", @provider?.getTitle()].join(' ')
     @editor.isModified = -> false
@@ -56,12 +56,14 @@
   registerCommands: ->
     atom.commands.add @editorElement,
       'core:confirm': => @confirm()
-      'narrow-ui:preview-item': => @confirm(preview: true)
+      'narrow-ui:preview-item': => @preview()
       'narrow-ui:toggle-auto-preview': => @toggleAutoPreview()
       # 'core:cancel': => @refresh()

   isAutoPreview: -> @autoPreview
-  toggleAutoPreview: -> @autoPreview = not @autoPreview
+  toggleAutoPreview: ->
+    if @autoPreview = not @autoPreview
+      @preview()

   getItems: ->
     Promise.resolve(@provider.getItems())
@@ -87,25 +89,28 @@
     @clearBlockDecorations()
     query = @getNarrowQuery()
     words = _.compact(query.split(/\s+/))
+
+    @getItems().then (items) =>
+      @updateGrammar(@editor, words.map(_.escapeRegExp).join('|'))
+      @clearText()
+      @setItems(@filterItems(items, words))
+      @updateGutter(@editor.getCursorBufferPosition())
+
+  filterItems: (items, words) ->
     filterKey = @provider.getFilterKey()

-    @getItems().then (items) =>
-      patterns = []
-      for word in words
-        pattern = _.escapeRegExp(word)
-        patterns.push(pattern)
-
-        items = _.filter items, (item) ->
-          if filterKey of item
-            item[filterKey].match(///#{pattern}///i)
-          else
-            # When item has no filterKey, it is special, always displayed.
-            true
-
-      @updateGrammar(@editor, patterns.join('|'))
-      @clearText()
-      @setItems(items)
-      @updateGutter(@editor.getCursorBufferPosition())
+    filter = (items, pattern) ->
+      _.filter items, (item) ->
+        if filterKey of item
+          item[filterKey].match(///#{pattern}///i)
+        else
+          # When item has no filterKey, it is special, always displayed.
+          true
+
+    for pattern in words.map(_.escapeRegExp)
+      items = filter(items, pattern)
+    items
+

   addBlockDecorationForBufferRow: (row, item) ->
     @blockDecorations ?= []
@@ -119,6 +124,9 @@
     buffer.onDidChange ({newRange}) =>
       return unless (newRange.start.row is 0)
       @refresh()
+
+  preview: ->
+    @confirm(preview: true)

   confirm: (options={}) ->
     point = @editor.getCursorBufferPosition()


test .graph

test .graph

--- test/authz_test.coffee
+++ test/authz_test.coffee
@@ -171,4 +171,74 @@
           assert !err
           assert !allowed
           done()
-
+
+  describe "#graph", ->
+    defaultOpts = { ancestors: true, descendants: true }
+    defaultGraph = [['parent', 'child']]
+    defaultRoles = ['a', 'b']
+    stubGet = (result, roles,  options, graph) ->
+      options ||= defaultOpts
+      graph ||= defaultGraph
+      roles ||= defaultRoles
+      gently.expect g.rest, 'get', (url, opts) ->
+        assert.equal url, g.format('http://example.com/%s/roles?%s&ancestors=%s&descendants=%s%s',
+          account, g.arrayParam('roles', roles),
+          options.ancestors, options.descendants, if  options.fromRole then "&from_role=" + g.pathEscape(options.fromRole) else '' );
+        {
+          on: (arg, callback) ->
+            assert.equal arg, 'complete'
+            if result == 'error'
+              callback new Error('error')
+            else if result == 'errorCode'
+              callback null, {statusCode: 500}
+            else
+              callback graph, {statusCode: 200}
+        }
+
+    stubGetSuccess = stubGet.bind(null, 'success')
+    stubGetError   = stubGet.bind(null, 'error')
+    stubGetFailure = stubGet.bind(null, 'errorCode')
+
+    callRoleGraph = (roleIds, options, callback) ->
+      conjur_authz.connect('http://example.com', token).graph account, roleIds, options, callback
+
+
+    it 'accepts a string', (done) ->
+      stubGetSuccess [ 'role' ]
+      callRoleGraph 'role', defaultOpts, ->
+        done()
+
+    it 'accepts an array', (done) ->
+      stubGetSuccess ['role1', 'role2']
+      callRoleGraph ['role1', 'role2'], defaultOpts, ->
+        done()
+
+    it 'fires the callback with an error when an error occurs', (done) ->
+      stubGetError ['role']
+      cb = (err, res) ->
+        assert.notEqual err, null
+        assert.equal res, null
+        done()
+      callRoleGraph 'role', defaultOpts, cb
+
+    it 'fires the callback with an error when the response status is not 200', (done) ->
+      stubGetFailure ['role']
+      cb = (err, res) ->
+        assert.notEqual err, null
+        assert.equal res, null
+        done()
+      callRoleGraph 'role', defaultOpts, cb
+
+    it 'fires the callback with (null, graph) when the request succeeds', (done) ->
+      stubGetSuccess ['role']
+      cb = (err, res) ->
+        assert.equal null, err
+        assert.deepEqual res, defaultGraph
+        done()
+      callRoleGraph 'role', defaultOpts, cb
+
+
+
+
+
+


Added testing for other templates

Added testing for other templates

--- test/basic.test.coffee
+++ test/basic.test.coffee
@@ -65,4 +65,43 @@
   validate('exports', {
     exports: 'exports'
   })
+
+  for name in ['amd', 'node']
+    validate("#{name}-by-name", {
+      templateName: name
+      exports: 'exports'
+    })
+    validate("#{name}-by-path", {
+      templatePath: path.join(__dirname, "../templates/#{name}.dot")
+      exports: 'exports'
+    })
+    validate("#{name}-with-libs", {
+      templateName: name
+      require: {
+        argA: 'lib-a'
+        argB: {
+          name: 'lib-b',
+          amd: null
+          cjs: null
+          global: null
+          default: null
+        }
+        argC: {
+          name: 'lib-c',
+          amd: 'lib-c-amd'
+          cjs: 'lib-c-cjs'
+          global: 'lib-c-global'
+          default: 'lib-c-default'
+        }
+        argD: {
+          name: null,
+          amd: 'lib-d-amd'
+          cjs: 'lib-d-cjs'
+          global: 'lib-d-global'
+          default: 'lib-d-default'
+        }
+      }
+      exports: 'exports'
+    })
+
 )


Fixing list competition endpoint

Fixing list competition endpoint

--- http.coffee
+++ http.coffee
@@ -11,14 +11,14 @@
     [/user\/\w+/, 'get', listUser]
     ['/users', 'get', listUsers]
     ['/user', 'post', createUser]
+    [/competition\/\w+/, 'get', listCompetition]
     ['/competitions/all', 'get', listCompetitions]
     ['/competitions/by-owner', 'get', listCompetitionsByOwner]
     ['/competitions/by-membership', 'get', listCompetitionsByMembership]
     ['/competition', 'post', startCompetition]
     ['/competition/end', 'post', endCompetition]
+    ['/competition/join', 'post', joinCompetition]
     # [/competition\/\w+/withdraw/, 'post', withdrawFromCompetition]
-    # [/competition\/\w+/join/, 'post', joinCompetition]
-    # [/competition\/\w+/, 'get', listCompetition]
   ]

 # Endpoint handler methods
@@ -59,14 +59,14 @@
   .done()

 listCompetition = (req, res) ->
-  competitionId = @parseObjectId(req, 'competitions/all')
+  competitionId = @parseObjectId(req, 'competition')
   if not competitionId
     res.json(400, {message: "must provide competitionId"})
     return

   @listSingle(
     res,
-    @api.listCompetitions(userId),
+    @api.listCompetitions(competitionId),
     { typeName: 'competition', query: { competition_id: competitionId } }
   )


MachineStateModal: follow-up reinit events too.

--- client/ide/views/modals/machinestatemodal.coffee
+++ client/ide/views/modals/machinestatemodal.coffee
@@ -30,6 +30,7 @@
     computeController.on "start-#{@machineId}", @bound 'updateStatus'
     computeController.on "build-#{@machineId}", @bound 'updateStatus'
     computeController.on "stop-#{@machineId}",  @bound 'updateStatus'
+    computeController.on "reinit-#{@machineId}",@bound 'updateStatus'
     computeController.on "error-#{@machineId}", =>
       @hasError = yes
       @updateStatus status: Unknown


fix for ie11 not supporting json response

--- client/shared/record_store/restful_client.coffee
+++ client/shared/record_store/restful_client.coffee
@@ -99,8 +99,9 @@
         @currentUpload.responseType = 'json'
         @currentUpload.addEventListener 'load', =>
           if (@currentUpload.status >= 200 && @currentUpload.status < 300)
-            @onUploadSuccess(@currentUpload.response)
-            resolve(@currentUpload.response)
+            data = JSON.parse(@currentUpload.response) if _.isString(@currentUpload.response)
+            @onUploadSuccess(data)
+            resolve(data)
             @currentUpload = null
         @currentUpload.upload.addEventListener('progress', onProgress) if onProgress
         @currentUpload.addEventListener('error', reject)


fixing proxy output

fixing proxy output

--- index.coffee
+++ index.coffee
@@ -51,7 +51,7 @@

 reddish_port = 8000
 reddish_monitor_port = 8001
-reddish_hostname = 'reddi.sh'
+reddish_hostname = 'dev.freeflow.io'

 # setup handshaken and connected state
@@ -155,7 +155,7 @@
         return

       console.log 'Endpoint handshake succeeded'
-      console.log "SUCCESS: Proxying redis client at #{redis_hostname}:#{redis_port} to reddish endpoint at #{reddish_hostname}:#{reddish_monitor_port}..."
+      console.log "SUCCESS: Proxying redis client at #{redis_hostname}:#{redis_port} to reddish endpoint at #{reddish_hostname}:#{reddish_port}..."
       handshaken = true
     catch err then console.error 'ERROR: Endpoint handshake failed:', err
     return


Pass fabric.js Canvas to Game class

Pass fabric.js Canvas to Game class

--- index.coffee
+++ index.coffee
@@ -11,7 +11,7 @@
   canvas = new fabric.Canvas('canvas', {renderOnAddRemove: false})
   window.canvas = canvas

-  game = new Game()
+  game = new Game(canvas)
   game.start()
   setInterval((->
     SynchronizedTime.time += 1


Added logic for selecting port

Added logic for selecting port

--- index.coffee
+++ index.coffee
@@ -30,6 +30,7 @@

 server.use "/", (req, res)->
 	res.redirect "/browse"
-
-server.listen 3000
-console.log "Listening on port 3000"+
+port = if process.env.PORT then process.env.PORT else 3000
+server.listen port
+console.log "ZVGQ started on port " + port


filter elevators

filter elevators

--- index.coffee
+++ index.coffee
@@ -23,6 +23,9 @@

 tweet = (msg,cb=defaultCallback)->
 	twitter.post('statuses/update',{status:cleanForTweet(msg)},cb)
+
+filterEl = (headerText)->
+	/escalator/.test headerText.toLowerCase()

 eachAlert = (v)->
 	v['_id']=v['alert_id'].toString()


quests are read from db

quests are read from db

--- index.coffee
+++ index.coffee
@@ -17,7 +17,8 @@
     app.use '/', router

     router.get '/quests', (request, response) ->
-        response.send [{"name": "q1"}, {"name": "q2"}]
+        client.query 'select * from quest', (err, result) ->
+            response.send result.rows

     router.param 'quest_id', (req, res, next, id) ->
         client.query 'select * from quest where id = $1', [id], (err, result) ->


cli help and reply private

cli help and reply private

--- index.coffee
+++ index.coffee
@@ -62,6 +62,7 @@
   checkMessage(bot, message)

 QUERY_REGEX = '(query|q|column|bar|line|pie|scatter|map)( )?(\\w+)? (.+)'
+CLI_HELP = "pie model/view/field,another_field[filter_value],more_field desc"

 controller.on 'slash_command', (bot, message) ->

@@ -74,7 +75,7 @@
     message.match = match
     runCLI(spawnedBot, message)
   else
-    spawnedBot.reply(message, "Unknown command! Sorry...")
+    bot.replyPrivate(message, "Usage: `#{CLI_HELP}`")

 controller.hears [QUERY_REGEX], ['direct_mention'], (bot, message) ->
   runCLI(bot, message)


google-images.coffeeを雑な拡張

google-images.coffeeを雑な拡張

--- scripts/google-images.coffee
+++ scripts/google-images.coffee
@@ -6,6 +6,9 @@
 #   hubot animate me <query> - The same thing as `image me`, except adds a few parameters to try to return an animated GIF instead.
 #   hubot mustache me <url> - Adds a mustache to the specified URL.
 #   hubot mustache me <query> - Searches Google Images for the specified query and mustaches it.
+#   hubot iy <query> - Extention Yakyu
+#   hubot is <query> - Extention Sakka-
+#   大谷 - Extention 大谷特別版

 module.exports = (robot) ->
   robot.respond /(image|img)( me)? (.*)/i, (msg) ->
@@ -26,6 +29,19 @@
     else
       imageMe msg, imagery, false, true, (url) ->
         msg.send "#{mustachify}#{url}"
+
+#Extentions
+  robot.respond /(iy|is) (.*)/i, (msg) ->
+    exSerchType = ""
+    if msg.match[1] == "iy" then exSerchType = "野球"
+    else if msg.match[1] == "sy" then exSerchType = "サッカー"
+    imageMe msg, msg.match[2] + " " + exSerchType, (url) ->
+      msg.send url
+
+  robot.hear /(.*)大谷(.*)/i, (msg) ->
+    imageMe msg, "大谷翔平", (url) ->
+      msg.send url
+#Extentions End

 imageMe = (msg, query, animated, faces, cb) ->
   cb = animated if typeof animated == 'function'


Remove redundant method

Remove redundant method

--- src/extensions/fuzzy-finder.coffee
+++ src/extensions/fuzzy-finder.coffee
@@ -80,11 +80,6 @@
   findSelectedLi: ->
     @pathList.children('li.selected')

-  select: ->
-    selectedLi = @findSelectedLi()
-    return unless selectedLi.length
-    @open(selectedLi.text())
-
   open : (path) ->
     return unless path.length
     @rootView.open(path, {@allowActiveEditorChange})


Form: Additional class names for form rows.

Put field name and type (checkbox, input, select only) as additional
 classes for each row.

--- src/elements/Form/Form.coffee
+++ src/elements/Form/Form.coffee
@@ -705,16 +705,21 @@
 				append(table)

 			name = field.getName()
+			classes = []
 			if name
-				if table_has_left
-					cls = " cui-form-tr--"+name
-				else
-					cls = " cui-form-row--"+name
-			else
-				cls = ""
+				classes.push("cui-form-field-name--"+name)
+
+			if field instanceof Checkbox
+				classes.push("cui-form-field-type--checkbox")
+
+			if field instanceof Input
+				classes.push("cui-form-field-type--input")
+
+			if field instanceof Select
+				classes.push("cui-form-field-type--select")

 			if table_has_left
-				tr = CUI.DOM.element("DIV", class: "cui-form-tr"+cls, "data-for-field": field.getUniqueId())
+				tr = CUI.DOM.element("DIV", class: "cui-form-tr "+classes.join(" "), "data-for-field": field.getUniqueId())

 				td = CUI.DOM.element("DIV", class: "cui-form-td cui-form-key")
 				append(get_label(field), td)
@@ -733,7 +738,7 @@

 				table.appendChild(tr)
 			else
-				row = CUI.DOM.element("DIV", class: "cui-form-row"+cls, "data-for-field": field.getUniqueId())
+				row = CUI.DOM.element("DIV", class: "cui-form-row "+classes.join(" "), "data-for-field": field.getUniqueId())
 				row.appendChild(get_append(field))
 				append(get_append(field), row)
 				append(hint_div, row)


add test case for ES6 import in coffee

add test case for ES6 import in coffee

--- test/fake_modules/coffee_script/index.coffee
+++ test/fake_modules/coffee_script/index.coffee
@@ -1,3 +1,4 @@
 require 'foo'
 require('bar')
 require('baz');
+import 'fooo'


Tests:Accocunt:Accountpage: Deleted un used code.

--- tests/src/account/accountpage.coffee
+++ tests/src/account/accountpage.coffee
@@ -26,7 +26,6 @@
   editFirstName: (browser) ->

     helpers.beginTest(browser)
-    paragraph = helpers.getFakeText()
     inputSelector = '.firstname input.text'

     helpers.changeName(browser, inputSelector, yes)
@@ -36,7 +35,6 @@
   editLastName: (browser) ->

     helpers.beginTest(browser)
-    paragraph = helpers.getFakeText()
     inputSelector = '.lastname input.text'

     helpers.changeName(browser, inputSelector, no)


Tests: Environments: Domain: Disable openVMDomain test.

http://recordit.co/u6I8yEzegZ http://take.ms/ttoEN

--- tests/src/environments/domain.coffee
+++ tests/src/environments/domain.coffee
@@ -6,26 +6,26 @@
 module.exports =

-  openVmDomain: (browser) ->
+  # openVmDomain: (browser) ->

-    modalSelector = '.activity-modal.vm-settings'
-    linkSelector  = modalSelector + ' .assigned-url .custom-link-view'
+  #   modalSelector = '.activity-modal.vm-settings'
+  #   linkSelector  = modalSelector + ' .assigned-url .custom-link-view'

-    helpers.beginTest(browser)
-    helpers.waitForVMRunning(browser)
+  #   helpers.beginTest(browser)
+  #   helpers.waitForVMRunning(browser)

-    environmentHelpers.openVmSettingsModal(browser)
+  #   environmentHelpers.openVmSettingsModal(browser)

-    browser
-      .waitForElementVisible   linkSelector, 20000
-      .getAttribute            linkSelector, 'href', (result) ->
-        domain = result.value
+  #   browser
+  #     .waitForElementVisible   linkSelector, 20000
+  #     .getAttribute            linkSelector, 'href', (result) ->
+  #       domain = result.value

-        browser
-          .url domain
-          .waitForElementVisible  '#container', 20000
-          .waitForElementVisible  '#container .hellobox', 20000
-          .end()
+  #       browser
+  #         .url domain
+  #         .waitForElementVisible  '#container', 20000
+  #         .waitForElementVisible  '#container .hellobox', 20000
+  #         .end()

   addDomain: (browser) ->


modify: api server log.

modify: api server log.

--- tasks/gulp.config.coffee
+++ tasks/gulp.config.coffee
@@ -7,7 +7,6 @@
 g = require 'gulp' # Gulp 本体
 $ = do require 'gulp-load-plugins' # package.json からプラグインを自動で読み込む
 fs = require 'fs' # ファイルやディレクトリの操作
-url = require 'url'

 runSequence = require 'run-sequence' # タスクの並列 / 直列処理
 rimraf = require 'rimraf' # 単一ファイル / ディレクトリ削除
@@ -17,7 +16,7 @@

 bs = require('browser-sync').create() # Web サーバー作成
 ssi = require 'browsersync-ssi' # SSI を有効化
-jsonServer = require 'gulp-json-srv'
+jsonServer = require 'gulp-json-srv' # API サーバー

 #------------------------------------------------------
 # Load original module
@@ -744,6 +743,11 @@
 g.task 'clean-archive', ['clean-temp'], (cb) ->
   return rimraf paths.archive.dest, cb

+#------------------------------------------------------
+# Local server settings
+# ローカルサーバー設定
+#------------------------------------------------------
+
 # browserSync
 g.task 'bs', ->
   bs.init null, {
@@ -776,12 +780,19 @@
     }
   }

+#------------------------------------------------------
+# Monitoring task
+# 監視タスク
+#------------------------------------------------------
+
 # json-server watch & refresh
 g.task 'api', ->
   g.src paths.api.watch
   .pipe apiServer.pipe()

 g.task 'watch-api', ['api'], ->
+  # API サーバー起動のログを出力
+  console.log '[\u001b[34mAPI Mock Server\u001b[0m] \u001b[1mAccess URLs: \u001b[0m\u001b[35mhttp://localhost:' + paths.api.port + paths.api.dest + '/db\u001b[0m'
   $.watch paths.api.watch, ->
     g.start 'api' # json ファイルが変更または追加されたらビルド出力


test anchors to fix serifHeight issue and shape origins

--- src/glyphs/uppercases/T_cap.coffee
+++ src/glyphs/uppercases/T_cap.coffee
@@ -4,7 +4,10 @@
 		advanceWidth: contours[1].nodes[0].x - 45 * spacing
 	anchors:
 		0:
-			x: 680 * width
+			x: 710 * width
+			y: capHeight
+		1:
+			x: 45
 			y: capHeight
 	tags: [
 		'all',
@@ -17,7 +20,7 @@
 			closed: false
 			nodes:
 				0:
-					x: contours[1].nodes[1].x + ( anchors[0].x - contours[1].nodes[1].x ) / 2
+					x: anchors[1].x + ( anchors[0].x - anchors[1].x ) / 2
 					y: 0 + serifHeight + serifCurve * ( 60 / 15 )
 					dirOut: 90 + 'deg'
 					typeOut: 'line'
@@ -37,7 +40,7 @@
 			closed: false
 			nodes:
 				0:
-					x: 680 * width - serifHeight - serifCurve * ( 100 /15 )
+					x: anchors[0].x - serifHeight - serifCurve * ( 100 / 15 )
 					y: capHeight
 					dirOut: 0 + 'deg'
 					typeOut: 'line'
@@ -47,7 +50,7 @@
 						distr: 1
 					})
 				1:
-					x: 20
+					x: anchors[1].x + serifHeight + serifCurve * ( 100 / 15 )
 					y: capHeight
 					dirOut: 0 + 'deg'
 					typeOut: 'line'
@@ -73,41 +76,36 @@
 		1:
 			base: 'serif-v'
 			parentAnchors:
+				0:
+					x: anchors[0].x - serifHeight - serifCurve * ( 100 /15 )
+					y: anchors[0].y
 				1:
 					x: anchors[0].x - serifHeight - serifCurve * ( 100 /15 )
 					y: anchors[0].y - thickness * opticThickness * ( 25 / 85 )
-				0:
-					x: anchors[0].x - serifHeight - serifCurve * ( 100 /15 )
-					y: anchors[0].y
 				2:
 					anchorLine: anchors[0].x
 					leftWidth: 40
-					leftCurve: 1.2
-					# rightWidth: 20
-					corrWidth: 0.7
-					# rightCurve: 1.2
+					# maxWidth: capHeight + 40  #TODO: implement maxwidth with value on serif-v
 			parentParameters:
 				serifMedian: serifMedian * 0.75
 				midWidth: midWidth * 0.98
 			transformOrigin: Array( contours[1].nodes[0].expandedTo[1].x, contours[1].nodes[0].expandedTo[0].y )
-			transforms: Array( [ 'skewX', serifRotate * (-10) + 'deg' ] )
+			transforms: Array( [ 'skewX', serifRotate * (-20) + 'deg' ] )
 		2:
 			base: 'serif-v'
 			parentAnchors:
+				0:
+					x: anchors[1].x + serifHeight + serifCurve * ( 100 /15 )
+					y: anchors[1].y
 				1:
-					x: contours[1].nodes[1].expandedTo[0].x + serifHeight + serifCurve * ( 100 /15 )
-					y: contours[1].nodes[1].expandedTo[0].y
-				0:
-					x: contours[1].nodes[1].expandedTo[1].x + serifHeight + serifCurve * ( 100 /15 )
-					y: contours[1].nodes[1].expandedTo[1].y
+					x: anchors[1].x + serifHeight + serifCurve * ( 100 /15 )
+					y: anchors[1].y - thickness * opticThickness * ( 25 / 85 )
 				2:
-					anchorLine: contours[1].nodes[1].expandedTo[0].x
+					anchorLine: anchors[1].x
 					leftWidth: 40
-					# leftCurve: 1.2
 					directionX: -1
-					# corrWidth: 0.7
-			# parentParameters:
-			# 	serifMedian: serifMedian * 0.75
-			# 	midWidth: midWidth * 0.98
+			parentParameters:
+				serifMedian: serifMedian * 0.75
+				midWidth: midWidth * 0.98
 			transformOrigin: Array( contours[1].nodes[1].expandedTo[1].x, contours[1].nodes[1].expandedTo[0].y )
-			transforms: Array( [ 'skewX', serifRotate * (10) + 'deg' ] )
+			transforms: Array( [ 'skewX', serifRotate * (20) + 'deg' ] )


test(karma): Update karma conf to support test scripts in folder

--- test/karma.conf.coffee
+++ test/karma.conf.coffee
@@ -60,7 +60,7 @@
       "bower_components/angular-mocks/angular-mocks.js"
       "test/vendor/browserTrigger.js"
       "test/unit/*.spec.coffee"
-      "test/unit/*.spec.js"
+      "test/unit/**/*.spec.js"
     ]

     reporters: ["progress"]


Update help command to reflect /pager ack only does your incidents

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -14,7 +14,7 @@
 #   hubot pager me problems - return all open incidents
 #   hubot pager me ack <incident> - ack incident #<incident>
 #   hubot pager me resolve <incident1> <incident2> ... <incidentN> - ack all specified incidents
-#   hubot pager me ack - ack all triggered incidents
+#   hubot pager me ack - ack all triggered incidents assigned to you
 #   hubot pager me resolve <incident> - resolve incident #<incident>
 #   hubot pager me resolve <incident1> <incident2> ... <incidentN>- resolve all specified incidents
 #   hubot pager me resolve - resolve all acknowledged incidents


Ensure editorController is only set once

--- src/trix/elements/trix_editor_element.coffee
+++ src/trix/elements/trix_editor_element.coffee
@@ -86,7 +86,7 @@
   attachedCallback: ->
     autofocus(this)

-    @editorController = new Trix.EditorController
+    @editorController ?= new Trix.EditorController
       editorElement: this
       document: Trix.deserializeFromContentType(@value, "text/html")
       delegate: new Trix.EditorElementController this


Oscillator

Oscillator


revert hash reset change

revert hash reset change

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -446,6 +446,7 @@
       jumpToHash = () =>
         if currentPage.get('loaded') and not @fragmentReloaded and window.location.hash
           @fragmentReloaded = true
+
           hash = window.location.hash
           window.location.hash = ''
           window.location.hash = hash


Ensure solutions do not double toggle

Ensure solutions do not double toggle

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -384,7 +384,7 @@
         @parent.scrollToTop()

     toggleSolution: (e) ->
-      $solution = $(e.currentTarget).closest('.solution, [data-type="solution"]')
+      $solution = $(e.currentTarget).closest('.solution, [data-type="solution"]').eq(0)
       $solution.toggleClass('ui-solution-visible')

     onEditable: () -> @$el.find('.media-body').addClass('draft')


Use clientX/Y instead of pageX/Y for coordinates

--- src/scripts/modules/popover/popover.coffee
+++ src/scripts/modules/popover/popover.coffee
@@ -83,7 +83,7 @@

   # Close popovers when clicking on the document
   $(document).click (e) ->
-    $el = $(document.elementFromPoint(e.pageX, e.pageY))
+    $el = $(document.elementFromPoint(e.clientX, e.clientY))

     # Don't clear the popover if clicking in it
     if not $el.parents().hasClass('popover')


account: deny from machines and delete credentials steps added

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -310,14 +310,14 @@
   fetchRelativeGroups$: secure (client, options = {}, callback) ->

     delegate = client?.connection?.delegate
-    currentGroup = client.context.group
-
-    return callback new Error 'malformed request' unless delegate
+    currentGroup = client?.context?.group
+
+    return callback new Error 'malformed request' unless delegate or currentGroup

     [ callback, options ] = [ options, callback ]  unless callback
     options ?= {}

-    delegate.fetchRelativeGroups { roles: options?.roles ? null }, (err, groups) ->
+    delegate.fetchRelativeGroups { roles: options.roles }, (err, groups) ->

       return callback err  if err

@@ -339,7 +339,7 @@
         @fetchAllParticipatedGroups options, (err, groups) =>
           return next err  if err
           JUser = require './user'
-          username = @profile.nickname
+          username = @getAt 'profile.nickname'
           for group in groups
             group.jwtToken = JUser.createJWT { username, groupName : group.slug }
           next null, groups
@@ -1272,6 +1272,10 @@
     { delegate } = client.connection
     { profile: { nickname } } = delegate

+    if nickname isnt @getAt 'profile.nickname'
+      return callback new KodingError \
+        'You are trying to delete the account that does not belong to you'
+
     checkUserPassword delegate, password, (err) =>

       return callback new KodingError err  if err
@@ -1283,7 +1287,7 @@

     @fetchRelativeGroups { roles: ['owner'] }, (err, groups) =>

-      # remove koding team
+      # filter out the koding team
       groups = groups.filter (group) -> group.slug isnt 'koding'

       if groups.length > 1
@@ -1301,8 +1305,30 @@
       username = @getAt 'profile.nickname'
       accountId = @getId()

-      # delete the team and delete the account
+      # delete resources of the account, team and account itself
       queue = [
+        (next) ->
+          # deny from all machines that are shared with the account
+          JMachine = require './computeproviders/machine'
+          selector = { 'users.username' : username }
+          JMachine.some selector, {}, (err, machines) ->
+
+            deleteMachines = machines.map (machine) -> (fin) ->
+              machine.deny client, fin
+
+            async.parallel deleteMachines, ->
+              kallback 'JMachine', next, err
+
+        (next) ->
+          # delete the credentials that are associated with the account
+          JCredential = require './computeproviders/credential'
+          JCredential.some$ client, { originId: accountId }, {}, (err, credentials) ->
+
+            deleteCredentials = credentials.map (credential) -> (fin) ->
+              credential.delete client, fin
+
+            async.parallel deleteCredentials, ->
+              kallback 'JCredential', next, err

         (next) ->
           group.destroy client, (err) ->
@@ -1317,7 +1343,7 @@
         (next) =>
           # delete user's resources (credentials, stack templates, stacks, machines)
           ComputeProvider = require './computeproviders/computeprovider'
-          ComputeProvider.destroyAccountResources this, -> next()
+          ComputeProvider.destroyAccountResources this, next

         (next) ->
           # delete invitations


fix log replays to work with the new timeouts

--- app/assets/javascripts/helpers/mcclient.coffee
+++ app/assets/javascripts/helpers/mcclient.coffee
@@ -102,6 +102,8 @@
     $.ajax({
       url: "/actlogs/replay/"+id
       success: (data) ->
+        MCM.lastExecution = data.txid
+        data.location = window.location.href
         that.receiveTxn(data)
     })

@@ -186,7 +188,7 @@
             return

           elapsed = (new Date().getTime() / 1000) - tx.started
-          if elapsed > tx.ddl.meta.timeout + 5
+          if tx.ddl and elapsed > tx.ddl.meta.timeout + 5
             MCM.vent.trigger("action:receiveError", tx, "request timed out")
             return


changed circlemarker to circle

changed circlemarker to circle

--- app/assets/javascripts/progress_numbers.coffee
+++ app/assets/javascripts/progress_numbers.coffee
@@ -165,11 +165,11 @@

 			json = L.geoJson(data.poly,
 				pointToLayer: (f,latlng)->
-					L.circleMarker(latlng,
+					L.circle(latlng, 3,
 						color: '#d75b25'
 						fillOpacity: 0.1
 						opacity: 0.5
-						radius: 16
+						# radius: 16
 						weight: 4
 					)
 				style: (feature) ->


refactor code to a setup method

refactor code to a setup method

--- app/assets/javascripts/socializer/notes.coffee
+++ app/assets/javascripts/socializer/notes.coffee
@@ -21,37 +21,40 @@
       height: 100
     , "fast"

+@setup = (controllerName, controllerAction) ->
+  resetContent = if controllerAction == "edit" then false else true
+  tokeninput = $("[data-behavior~=tokeninput-for-note]")
+  audiencePath = tokeninput.data("source")
+  title = tokeninput.data("title")
+  currentId = tokeninput.data("current-id")
+  prepopulate = null
+
+  if currentId != null
+    prepopulate = [
+      id: currentId
+      name: title
+    ]
+
+  tokeninput.tokenInput audiencePath,
+    minChars: 0
+    preventDuplicates: true
+    prePopulate: prepopulate
+    resultsFormatter: (item) ->
+      "
 #{item.name}
"
+
+  if (currentId != null) && (title == "") || (controllerAction == "edit")
+    $(".token-input-list").hide()
+
+  resetNoteForm(resetContent)
+
+  $("[data-behavior~=cancel-note-form]").on "click", ->
+    resetNoteForm(resetContent)
+
 jQuery ->
   controllerName = $("body").data("controller")
   controllerAction = $("body").data("action")
-  resetContent = if controllerAction == "edit" then false else true

   if controllerName == "notes" || controllerName == "activities" ||
   controllerName == "people" || controllerName == "messages"

-    tokeninput = $("[data-behavior~=tokeninput-for-note]")
-    audiencePath = tokeninput.data("source")
-    title = tokeninput.data("title")
-    currentId = tokeninput.data("current-id")
-    prepopulate = null
-
-    if currentId != null
-      prepopulate = [
-        id: currentId
-        name: title
-      ]
-
-    tokeninput.tokenInput audiencePath,
-      minChars: 0
-      preventDuplicates: true
-      prePopulate: prepopulate
-      resultsFormatter: (item) ->
-        "
 #{item.name}
"
-
-    if (currentId != null) && (title == "") || (controllerAction == "edit")
-      $(".token-input-list").hide()
-
-    resetNoteForm(resetContent)
-
-    $("[data-behavior~=cancel-note-form]").on "click", ->
-      resetNoteForm(resetContent)
+    setup(controllerName, controllerAction)


Move spec

Move spec

--- spec/config-spec.coffee
+++ spec/config-spec.coffee
@@ -442,6 +442,26 @@
     schema = null

     describe '.setSchema(keyPath, schema)', ->
+      it 'creates a properly nested schema', ->
+        schema =
+          type: 'object'
+          properties:
+            anInt:
+              type: 'integer'
+              default: 12
+
+        atom.config.setSchema('foo.bar', schema)
+
+        expect(atom.config.getSchema('foo')).toEqual
+          type: 'object'
+          properties:
+            bar:
+              type: 'object'
+              properties:
+                anInt:
+                  type: 'integer'
+                  default: 12
+
       it 'sets defaults specified by the schema', ->
         schema =
           type: 'object'
@@ -480,26 +500,6 @@
           type: 'integer'
           default: 12

-      it 'creates a properly nested schema', ->
-        schema =
-          type: 'object'
-          properties:
-            anInt:
-              type: 'integer'
-              default: 12
-
-        atom.config.setSchema('foo.bar', schema)
-
-        expect(atom.config.getSchema('foo')).toEqual
-          type: 'object'
-          properties:
-            bar:
-              type: 'object'
-              properties:
-                anInt:
-                  type: 'integer'
-                  default: 12
-
     describe '.getSchema(keyPath)', ->
       schema =
         type: 'object'


sidechat: working on codemirror editors

sidechat: working on codemirror editors

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -1432,15 +1432,15 @@
         btn = @element.find("a[href=\"#split-view\"]")
         btn.find("i").hide()
         if not @_split_view
-            @element.find(".salvus-editor-codemirror-input-container-layout-1").width(width)
+            #@element.find(".salvus-editor-codemirror-input-container-layout-1").width(width)
             @element.find(".salvus-editor-resize-bar-layout-1").hide()
             @element.find(".salvus-editor-resize-bar-layout-2").hide()
             btn.find(".salvus-editor-layout-0").show()
             # one full editor
-            v = [{cm:@codemirror,height:height,width:width}]
+            v = [{cm:@codemirror, height:height, width:width}]
         else
             if @_layout == 1
-                @element.find(".salvus-editor-codemirror-input-container-layout-1").width(width)
+                #@element.find(".salvus-editor-codemirror-input-container-layout-1").width(width)
                 @element.find(".salvus-editor-resize-bar-layout-1").show()
                 @element.find(".salvus-editor-resize-bar-layout-2").hide()
                 btn.find(".salvus-editor-layout-1").show()
@@ -1475,30 +1475,19 @@
             layout_elt.find(".salvus-editor-codemirror-input-box-1").empty().append($(@codemirror1.getWrapperElement()))
             @_last_layout = @_layout

-        for {cm,height,width} in v
-            scroller = $(cm.getScrollerElement())
-            scroller.css('height':height)
-            cm_wrapper = $(cm.getWrapperElement())
-            cm_wrapper.css
-                height : height
-                width  : width
+        #for {cm, height, width} in v
+        #    scroller = $(cm.getScrollerElement())
+        #    scroller.css('height':height)
+        #    cm_wrapper = $(cm.getWrapperElement())
+        #    cm_wrapper.css(height : height)

         # This is another hack that specifically hopefully addresses an
         # issue where when I open a tab often the scrollbar is completely
         # hosed.  Zooming in and out manually always fixes it, so maybe
         # what's below will also.  Testing it.
         f = () =>
-            for {cm,height,width} in v
+            for {cm} in v
                 cm.refresh()
-                ###
-                scroll = cm.getScrollInfo(); pos = cm.getCursor()
-                # above refresh
-                scroll_after = cm.getScrollInfo(); pos_after = cm.getCursor()
-                if scroll.left != scroll_after.left or scroll.top != scroll_after.top or pos.line != pos_after.line or pos.ch != pos_after.ch
-                    console.log("WARNING: codemirror refresh lost pos -- RESETTING position; before=#{misc.to_json([scroll,pos])}, after=#{misc.to_json([scroll_after,pos_after])}")
-                    cm.setCursor(pos)
-                    cm.scrollTo(scroll.left, scroll.top)
-                ###
         setTimeout(f, 1)

         @emit('show', height)
@@ -1519,21 +1508,13 @@
         button_bar_height = @element.find(".salvus-editor-codemirror-button-row").height()
         font_height       = @codemirror.defaultTextHeight()

-
-        width         = opts.width ? $(window).width()
+        width = opts.width ? $(window).width()

         if opts.top?
             top           = opts.top

         # height of codemirror editors
         cm_height         = Math.floor((elem_height - button_bar_height)/font_height) * font_height
-
-        # position the editor element on the screen
-        @element.css(top:top, left:0)
-        @element.css(left:0)
-
-        # set overall height of the element
-        @element.height(elem_height)

         # show the codemirror editors, resizing as needed
         @_show_codemirror_editors(cm_height, width)


Simplify tests

Simplify tests

--- tests/batman/view/filter_parsing_test.coffee
+++ tests/batman/view/filter_parsing_test.coffee
@@ -430,8 +430,7 @@
       QUnit.start()

 asyncTest 'withArguments passes arguments to specified function and returns result', 2, ->
-  context =
-    foo: spy = createSpy()
+  context = foo: spy = createSpy()

   helpers.render '', context, (node) ->
     helpers.triggerClick(node[0])
@@ -440,34 +439,20 @@
     QUnit.start()

 asyncTest 'Pass arguments to accessor with Batman.TerminalAccessible', ->
-  class TestClass extends Batman.Object
-
-    @::col = ["a", "b", "c"]
-
+  context = Batman test: new class extends Batman.Object
     @accessor 'accessible', ->
-      new Batman.TerminalAccessible (id) =>
-        return @col[id]
-
-  context = Batman
-    test: new TestClass
+      new Batman.TerminalAccessible (x) -> x + 1

   helpers.render '

', context, (node) ->
-    equal node[0].innerHTML, "b"
+    equal node[0].innerHTML, "2"
     QUnit.start()

 asyncTest 'withArguments with Batman.TerminalAccessible', ->
-  class TestClass extends Batman.Object
-
-    @::col = ["a", "b", "c"]
-
+  context = Batman test: new class extends Batman.Object
     @accessor 'accessible', ->
-      new Batman.TerminalAccessible (id) =>
-        return @col[id]
-
-  context = Batman
-    test: new TestClass
+      new Batman.TerminalAccessible (x) -> x + 1

   helpers.render '

', context, (node) ->
-    equal node[0].innerHTML, "b"
-    QUnit.start()
-
+    equal node[0].innerHTML, "2"
+    QUnit.start()
+


:bug: Make specs compatible with latest version

--- spec/helper-spec.coffee
+++ spec/helper-spec.coffee
@@ -152,28 +152,28 @@
       results = helpers.parse(input, regex, {flags: "i"})
       expect(results).toEqual(output)

-  describe '::findFile', ->
-    it 'cries when no argument is passed', ->
-      expect ->
-        helpers.findFile()
-      .toThrow()
-    it 'works', ->
-      expect(helpers.findFile(__dirname, 'package.json')).toBe(fs.realpathSync("#{__dirname}/../package.json"))
+  describe '::find', ->
+    it 'cries when no argument is passed', ->
+      expect ->
+        helpers.find()
+      .toThrow()
+    it 'works', ->
+      expect(helpers.find(__dirname, 'package.json')).toBe(fs.realpathSync("#{__dirname}/../package.json"))
     it 'returns null if no file is found', ->
-      expect(helpers.findFile('/a/path/that/does/not/exist', '.gitignore')).toBe(null)
-
-  describe '::findFileAsync', ->
-    it 'cries when no argument is passed', ->
-      expect ->
-        helpers.findFileAsync()
-      .toThrow()
-    it 'works', ->
-      waitsForPromise ->
-        helpers.findFileAsync(__dirname, 'package.json').then (path) ->
+      expect(helpers.find('/a/path/that/does/not/exist', '.gitignore')).toBe(null)
+
+  describe '::findAsync', ->
+    it 'cries when no argument is passed', ->
+      expect ->
+        helpers.findAsync()
+      .toThrow()
+    it 'works', ->
+      waitsForPromise ->
+        helpers.findAsync(__dirname, 'package.json').then (path) ->
           expect(path).toBe(fs.realpathSync("#{__dirname}/../package.json"))
     it 'returns null if no file is found', ->
       waitsForPromise ->
-        helpers.findFileAsync(__dirname, '.ucompilerrc').then (path) ->
+        helpers.findAsync(__dirname, '.ucompilerrc').then (path) ->
           expect(path).toBe(null)

   describe '::exec options', ->


Update atom and window globals in beforEach

--- spec/spec-helper.coffee
+++ spec/spec-helper.coffee
@@ -18,7 +18,7 @@
 atom.themes.requireStylesheet '../static/jasmine'

 fixturePackagesPath = path.resolve(__dirname, './fixtures/packages')
-keymap.loadBundledKeymaps()
+atom.keymap.loadBundledKeymaps()
 [bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = []

 $(window).on 'core:close', -> window.close()
@@ -35,21 +35,22 @@

 beforeEach ->
   $.fx.off = true
-  window.project = new Project(specProjectPath)
+  atom.project = new Project(specProjectPath)
+  window.project = atom.project

   window.resetTimeouts()
   atom.packages.packageStates = {}
   spyOn(atom, 'saveWindowState')
-  syntax.clearGrammarOverrides()
-  syntax.clearProperties()
+  atom.syntax.clearGrammarOverrides()
+  atom.syntax.clearProperties()

   # used to reset keymap after each spec
   bindingSetsToRestore = _.clone(keymap.bindingSets)
   bindingSetsByFirstKeystrokeToRestore = _.clone(keymap.bindingSetsByFirstKeystroke)

   # reset config before each spec; don't load or save from/to `config.json`
-  window.config = new Config()
-  window.config.packageDirPaths.unshift(fixturePackagesPath)
+  config = new Config()
+  config.packageDirPaths.unshift(fixturePackagesPath)
   spyOn(config, 'load')
   spyOn(config, 'save')
   config.set "editor.fontFamily", "Courier"
@@ -57,6 +58,8 @@
   config.set "editor.autoIndent", false
   config.set "core.disabledPackages", ["package-that-throws-an-exception"]
   config.save.reset()
+  atom.config = config
+  window.config = config

   # make editor display updates synchronous
   spyOn(Editor.prototype, 'requestDisplayUpdate').andCallFake -> @updateDisplay()


Revert "Increase default fileListInterval for build"

This reverts commit 005a6d88dc84c56dc139239e33cdcf58ffb3aada.

--- src/fs_utils/file_list.coffee
+++ src/fs_utils/file_list.coffee
@@ -26,11 +26,6 @@
     @compiled = {}
     @copying = {}
     @initial = true
-
-    # increase default interval for `build`
-    @resetTime = 200 unless @config.persistent
-
-    # apply configured interval
     interval = @config.fileListInterval
     @resetTime = interval if typeof interval is 'number'


better format for data in test

better format for data in test

--- spec/twinky.spec.coffee
+++ spec/twinky.spec.coffee
@@ -28,8 +28,20 @@
     window.performance = { timing: { navigationStart: 10000000, domInteractive: 10000777, domLoading: 10000333 } }
     Twinky.send({page: 'foo', version: '789f0'})

-    expect(server.requests[0].requestBody).toEqual(JSON.stringify([
-        { "name":"domLoading","columns":["value","page","version"],"points":[[333,"foo",'789f0']] },
-        { "name":"domInteractive","columns":["value","page","version"],"points":[[444,"foo",'789f0']] },
-    ]))
+    expect(server.requests[0].requestBody).toEqual(
+        JSON.stringify(
+            [
+                {
+                    "name": "domLoading",
+                    "columns": ["value","page","version"],
+                    "points": [[333,"foo",'789f0']]
+                },
+                {
+                    "name": "domInteractive",
+                    "columns": ["value","page","version"],
+                    "points": [[444,"foo",'789f0']]
+                },
+            ]
+        )
+    )


[Gutter] Fix GutterContainerComponent spec

--- spec/gutter-container-component-spec.coffee
+++ spec/gutter-container-component-spec.coffee
@@ -5,17 +5,20 @@
   [gutterContainerComponent] = []
   mockGutterContainer = {}

-  buildTestState = (sortedDescriptions) ->
-    mockTestState =
-      gutters:
-        scrollHeight: 100
-        scrollTop: 10
-        backgroundColor: 'black'
-        sortedDescriptions: sortedDescriptions
-        customDecorations: {}
-        lineNumberGutter:
-          maxLineNumberDigits: 10
-          lineNumbers: {}
+  buildTestState = (gutters) ->
+    styles =
+      scrollHeight: 100
+      scrollTop: 10
+      backgroundColor: 'black'
+
+    mockTestState = {gutters: []}
+    for gutter in gutters
+      if gutter.name is 'line-number'
+        content = {maxLineNumberDigits: 10, lineNumbers: {}}
+      else
+        content = {}
+      mockTestState.gutters.push({gutter, styles, content, visible: gutter.visible})
+
     mockTestState

   beforeEach ->
@@ -30,7 +33,7 @@
   describe "when updated with state that contains a new line-number gutter", ->
     it "adds a LineNumberGutterComponent to its children", ->
       lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
-      testState = buildTestState([{gutter: lineNumberGutter, visible: true}])
+      testState = buildTestState([lineNumberGutter])

       expect(gutterContainerComponent.getDomNode().children.length).toBe 0
       gutterContainerComponent.updateSync(testState)
@@ -45,7 +48,7 @@
   describe "when updated with state that contains a new custom gutter", ->
     it "adds a CustomGutterComponent to its children", ->
       customGutter = new Gutter(mockGutterContainer, {name: 'custom'})
-      testState = buildTestState([{gutter: customGutter, visible: true}])
+      testState = buildTestState([customGutter])

       expect(gutterContainerComponent.getDomNode().children.length).toBe 0
       gutterContainerComponent.updateSync(testState)
@@ -57,15 +60,16 @@

   describe "when updated with state that contains a new gutter that is not visible", ->
     it "creates the gutter view but hides it, and unhides it when it is later updated to be visible", ->
-      customGutter = new Gutter(mockGutterContainer, {name: 'custom'})
-      testState = buildTestState([{gutter: customGutter, visible: false}])
+      customGutter = new Gutter(mockGutterContainer, {name: 'custom', visible: false})
+      testState = buildTestState([customGutter])

       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 1
       expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
       expect(expectedCustomGutterNode.style.display).toBe 'none'

-      testState = buildTestState([{gutter: customGutter, visible: true}])
+      customGutter.show()
+      testState = buildTestState([customGutter])
       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 1
       expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)
@@ -74,20 +78,20 @@
   describe "when updated with a gutter that already exists", ->
     it "reuses the existing gutter view, instead of recreating it", ->
       customGutter = new Gutter(mockGutterContainer, {name: 'custom'})
-      testState = buildTestState([{gutter: customGutter, visible: true}])
+      testState = buildTestState([customGutter])

       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 1
       expectedCustomGutterNode = gutterContainerComponent.getDomNode().children.item(0)

-      testState = buildTestState([{gutter: customGutter, visible: true}])
+      testState = buildTestState([customGutter])
       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 1
       expect(gutterContainerComponent.getDomNode().children.item(0)).toBe expectedCustomGutterNode

   it "removes a gutter from the DOM if it does not appear in the latest state update", ->
     lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
-    testState = buildTestState([{gutter: lineNumberGutter, visible: true}])
+    testState = buildTestState([lineNumberGutter])
     gutterContainerComponent.updateSync(testState)

     expect(gutterContainerComponent.getDomNode().children.length).toBe 1
@@ -99,7 +103,7 @@
     it "positions (and repositions) the gutters to match the order they appear in each state update", ->
       lineNumberGutter = new Gutter(mockGutterContainer, {name: 'line-number'})
       customGutter1 = new Gutter(mockGutterContainer, {name: 'custom', priority: -100})
-      testState = buildTestState([{gutter: customGutter1, visible: true}, {gutter: lineNumberGutter, visible: true}])
+      testState = buildTestState([customGutter1, lineNumberGutter])

       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 2
@@ -110,11 +114,7 @@

       # Add a gutter.
       customGutter2 = new Gutter(mockGutterContainer, {name: 'custom2', priority: -10})
-      testState = buildTestState([
-        {gutter: customGutter1, visible: true},
-        {gutter: customGutter2, visible: true},
-        {gutter: lineNumberGutter, visible: true}
-      ])
+      testState = buildTestState([customGutter1, customGutter2, lineNumberGutter])
       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 3
       expectedCustomGutterNode1 = gutterContainerComponent.getDomNode().children.item(0)
@@ -125,12 +125,9 @@
       expect(expectedLineNumbersNode).toBe atom.views.getView(lineNumberGutter)

       # Hide one gutter, reposition one gutter, remove one gutter; and add a new gutter.
+      customGutter2.hide()
       customGutter3 = new Gutter(mockGutterContainer, {name: 'custom3', priority: 100})
-      testState = buildTestState([
-        {gutter: customGutter2, visible: false},
-        {gutter: customGutter1, visible: true},
-        {gutter: customGutter3, visible: true}
-      ])
+      testState = buildTestState([customGutter2, customGutter1, customGutter3])
       gutterContainerComponent.updateSync(testState)
       expect(gutterContainerComponent.getDomNode().children.length).toBe 3
       expectedCustomGutterNode2 = gutterContainerComponent.getDomNode().children.item(0)


Fix race condition in test

Fix race condition in test

--- spec/server/functional/products.spec.coffee
+++ spec/server/functional/products.spec.coffee
@@ -18,13 +18,13 @@
   it 'shouldnt leak coupon code information', utils.wrap ->
       url = utils.getURL('/db/products/')
       [res, doc] = yield request.getAsync({url, json: true})
-      ls2 = _.find doc, ((x) -> /lifetime_subscription$/.test x.name)
+      ls2 = _.find doc, ((x) -> /^lifetime_subscription$/.test x.name)
       expect(ls2.coupons).toEqual([])

   it 'should accept the coupon code QS', utils.wrap ->
       url = utils.getURL('/db/products/')
       [res, doc] = yield request.getAsync(url: url + '?coupon=c1', json: true)
-      ls2 = _.find doc, ((x) -> /lifetime/.test x.name)
+      ls2 = _.find doc, ((x) -> /^lifetime/.test x.name)
       expect(ls2.coupons[0].amount).toBe(10)
       expect(ls2.coupons.length).toBe(1)


map ctrl-p to opening autocomplete menu for a field

and other keystrokes to closing the menu, if it's open

--- app/controllers/TranscriptionController.coffee
+++ app/controllers/TranscriptionController.coffee
@@ -55,6 +55,15 @@
     $(document).on 'keydown.nfn keypress.nfn', (e) ->
       if e.which is 8 and not (e.target.tagName is 'INPUT')
         e.preventDefault()
+      else if e.which is 80 and e.ctrlKey and $(".ui-autocomplete:visible").length == 0
+        $(".ui-autocomplete-input").first().autocomplete("search","")
+        $(".ui-autocomplete > li").parent().css("width", $(".ui-autocomplete-input").first().css("width"));
+        $(".ui-autocomplete > li").parent().css("padding", "0px");
+        e.preventDefault()
+      else if $(".ui-autocomplete:visible").length > 0
+      	# if menu is open and we press any key that has no meaning for jquery autocomplete menus (arrows, enter, escape, etc), close the menu
+        $(".ui-autocomplete-input").autocomplete("close") if jQuery.inArray(e.which, [17,27,38,40,13,9,33,34]) == -1
+        e.preventDefault()

     @render()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/string_extensions.coffee
+++ src/string_extensions.coffee
@@ -74,11 +74,7 @@
 String::constantize = ->
   target = exports ? window

-  if this.match /[A-Z][A-Za-z0-9]*/
-    eval("var that = #{this}")
-    that
-  else
-    throw "String#constantize: '#{this}' is not a valid constant name."
+

 ###*
 Returns a new string that is a more human readable version.


upped https connections to 300 and added debug logging

--- services/filestore/app/coffee/s3Wrapper.coffee
+++ services/filestore/app/coffee/s3Wrapper.coffee
@@ -1,5 +1,7 @@
 http = require('http')
 http.globalAgent.maxSockets = 300
+https = require('https')
+https.globalAgent.maxSockets = 300
 settings = require("settings-sharelatex")
 request = require("request")
 logger = require("logger-sharelatex")
@@ -10,6 +12,14 @@
 _ = require("underscore")

 thirtySeconds = 30 * 1000
+
+
+printSockets = ->
+	console.log require('https').globalAgent.sockets
+	console.log require('http').globalAgent.sockets
+	setTimeout printSockets, thirtySeconds
+
+printSockets()

 buildDefaultOptions = (bucketName, method, key)->
 	return {


Fix completed class

Fix completed class

--- app/views/task.coffee
+++ app/views/task.coffee
@@ -1,5 +1,5 @@
 module.exports = """
-

+

{{addTags name }}


Additional fixes to focus on login and on change events

--- annotran/static/scripts/widget-controller.coffee
+++ annotran/static/scripts/widget-controller.coffee
@@ -95,8 +95,6 @@
         else if selectedUser != undefined
           selectedUser = "acct:" + selectedUser.username + "@" + selectedUser.provider

-        console.log("Loading annotations for user: " + selectedUser)
-
         userAnnotations = []

         if selectedUser != undefined
@@ -109,6 +107,8 @@
           $scope.$root.userAnnotations = userAnnotations
           $scope.$root.updateUserList()

+        crossframe.call "resetDOM"
+
         if selectedUser != undefined
           if !$scope.$root.editOnly
             $scope.$root.cleanDOM = false
@@ -116,7 +116,6 @@
           else
             if $scope.$root != undefined and $scope.$root != null
               $scope.$root.cleanDOM = true
-            crossframe.call "resetDOM"
             annotationMapper.loadAnnotations(userAnnotations, null)

@@ -145,11 +144,13 @@

     $scope.$on events.USER_CHANGED, ->
+      $scope.$root.selectedUser = undefined
       _resetAnnotations(annotationMapper, drafts, threading)
       loaded = []
       loadAnnotations crossframe.frames

     $scope.$on events.GROUP_FOCUSED, ->
+      $scope.$root.selectedUser = undefined
       _resetAnnotations(annotationMapper, drafts, threading)
       loaded = []
       loadAnnotations crossframe.frames


Use localStorage to save task progress

Use localStorage to save task progress

--- views/components/main/parts/task-panel.cjsx
+++ views/components/main/parts/task-panel.cjsx
@@ -2,7 +2,6 @@
 {Panel, Table, Label, OverlayTrigger, Tooltip} = ReactBootstrap
 CSON = require 'cson'
 {join} = require 'path-extra'
-fs = require 'fs-extra'

 # Local time -> Task Refresh time(GMT + 4)
 getCurrentDay = ->
@@ -51,7 +50,7 @@
 questRecord = {}
 syncQuestRecord = ->
   questRecord.day = getCurrentDay()
-  fs.writeFileSync join(APPDATA_PATH, "quest_tracking_#{memberId}.cson"), CSON.stringify questRecord, null, 2
+  localStorage.setItem "quest_tracking_#{memberId}", JSON.stringify(questRecord)
 clearQuestRecord = (id) ->
   delete questRecord[id] if questRecord[id]?
   syncQuestRecord()
@@ -111,16 +110,17 @@
     switch path
       when '/kcsapi/api_get_member/basic'
         memberId = window._nickNameId
-        try
-          questRecord = CSON.parseCSONFile join(APPDATA_PATH, "quest_tracking_#{memberId}.cson")
+        questRecord = localStorage.getItem "quest_tracking_#{memberId}"
+        if questRecord?
+          questRecord = JSON.parse questRecord
           if getCurrentDay() != questRecord.day
             for id, q of questRecord
               delete questRecord[id] if questGoals[id].type in [2, 4, 5]
           if getCurrentDay() < questRecord.day
             for id, q of questRecord
               delete questRecord[id] if questGoals[id].type is 3
-        catch error
-          false
+        else
+          questRecord = {}
       when '/kcsapi/api_get_member/questlist'
         return unless body.api_list?
         for task in body.api_list


Delete color of task name

Delete color of task name

--- views/components/main/parts/task-panel.cjsx
+++ views/components/main/parts/task-panel.cjsx
@@ -11,28 +11,6 @@
   curTime.getDay()

 prevDay = getCurrentDay()
-
-getType = (api_category) ->
-  switch api_category
-    when 0
-      if window.isDarkTheme
-        return '#ffffff'
-      else
-        return '#000000'
-    when 1
-      return '#21bb3a'
-    when 2
-      return '#e73939'
-    when 3
-      return '#87da61'
-    when 4
-      return '#32bab8'
-    when 5
-      return '#f4df22'
-    when 6
-      return '#cd6c48'
-    when 7
-      return '#c792e8'

 getStyleByProgress = (progress) ->
   switch progress
@@ -315,7 +293,7 @@
             if @state.tasks[i].tracking

                 <OverlayTrigger placement='left' overlay={<Tooltip>{@state.tasks[i].name}
{@state.tasks[i].content}</Tooltip>}>
-                  {@state.tasks[i].name}
+                  {@state.tasks[i].name}
                 </OverlayTrigger>

                   <OverlayTrigger placement='left' overlay={<Tooltip>{getToolTip @state.tasks[i].id}</Tooltip>}>
@@ -326,7 +304,7 @@
             else

                 <OverlayTrigger placement='left' overlay={<Tooltip>{@state.tasks[i].name}
{@state.tasks[i].content}</Tooltip>}>
-                  {@state.tasks[i].name}
+                  {@state.tasks[i].name}
                 </OverlayTrigger>

                   {@state.tasks[i].progress}


Submit URLs via `zoomhub.net/http://...`

--- app._coffee
+++ app._coffee
@@ -66,8 +66,8 @@
 app.get '/health', (req, res, _) ->
     res.send 'up'

-app.get '/content', (req, res, _) ->
-    url = req.query?.url
+app.get /^\/(https?:\/\/.+)/, (req, res, _) ->
+    url = req.params[0]
     if not url?
         return res.json 400, {error: "Missing URL"}
     id = ++ID


scroll height adjusted so it's a variable

--- app/assets/javascripts/components/song.js.coffee
+++ app/assets/javascripts/components/song.js.coffee
@@ -1,13 +1,13 @@
 # # app/assets/javascripts/components/song.js.coffee
-pageScroll = () ->
-  $('.tabs').animate({scrollTop: 10000000}, 600000000, "linear")
+pageScroll = ->
+  divHeight = $('.tabs')[0].scrollHeight
+  $('.tabs').animate({scrollTop: divHeight }, divHeight * 100, "linear")
+  console.log("height: " + divHeight)

 $(document).on "click", "#play", ->
-  console.log("scrolling!!")
   pageScroll()

 $(document).on "click", "#stop", ->
-  console.log("stop!!")
   $('.tabs').stop()

@@ -26,10 +26,10 @@
         className: 'small-1 columns favorite centered'
         id: 'favorite'
         @state.my_favorite
-        if @state.my_favorite == " ❤"
-          console.log("It's a favorite")
-        else
-          console.log("Not a favorite")
+        # if @state.my_favorite == " ❤"
+        #   console.log("It's a favorite")
+        # else
+        #   console.log("Not a favorite")
       React.DOM.h2
         className: 'cursive-font small-6 columns'
         @state.song.name


zoomed out less

zoomed out less

--- app/assets/javascripts/lib/nypl_inspector.coffee
+++ app/assets/javascripts/lib/nypl_inspector.coffee
@@ -274,7 +274,7 @@
         # things are slightly different for editable polygon drawing
         @makeEditablePolygon()
       # center on the polygon
-      bounds = @geo.getBounds().pad(1)
+      bounds = @geo.getBounds().pad(.1)
       @map.fitBounds( bounds )
       # @map.setZoom( @map.getZoom()-1 ) if @options.tutorialOn
       @resetButtons()


minor cleanup for a variable that wasn’t being used.

--- app/assets/javascripts/teaspoon/base/hook.coffee
+++ app/assets/javascripts/teaspoon/base/hook.coffee
@@ -1,5 +1,5 @@
 Teaspoon.hook = (name, payload = {}) ->
-  method = "POST"
+
   xhr = null

   xhrRequest = (url, payload, callback) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/clamp_bounds.coffee
+++ test/clamp_bounds.coffee
@@ -3,7 +3,7 @@
 test "should clamp the x-axis", ->
   player = GameObject
     includedModules: ["ClampBounds"]
-
+    width:

   player.I.x = -400
   player.update()


One buggy account shouldnt stop replication ref #154

--- server/models/account.coffee
+++ server/models/account.coffee
@@ -81,7 +81,11 @@
         log.debug "refreshing account #{account.label}"
         return cb null if account.isTest()
         return cb null if account.isRefreshing()
-        account.imap_fetchMails limitByBox, onlyFavorites, cb
+        account.imap_fetchMails limitByBox, onlyFavorites, (err) ->
+            if err
+                log.error "CANT REFRESH ACCOUNT", account.id, err
+            # refresh all accounts even if one fails
+            cb null
     , callback


First pass at pointing driver directly at Fusion Tables

--- src/js/cts-cite-driver.coffee
+++ src/js/cts-cite-driver.coffee
@@ -10,8 +10,8 @@
 default_cts_cite_collection_driver_config =
   google_client_id: '429515988667-jkk0s2375vu04vasnvpotbimddag4ih8.apps.googleusercontent.com'
   google_scope: 'https://www.googleapis.com/auth/fusiontables https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'
-  cts_endpoint: 'http://www.perseus.tufts.edu/hopper/CTS'
-  cts_urn: 'urn:cts:greekLit:tlg1389.tlg001.perseus-grc1'
+  cts_endpoint: '1_DFxPLkDrZt2JTgFo04nI6zQ9AsnnqMNRlUBb2Sq'
+  cts_urn: 'urn:cts:greekLit:tlg1389.tlg001.dc3'
   cite_table_id: '11_Igu6u5961Dkz-cfbJOgKdYkQMwnoe3AQXw8T-K'
   cite_collection_editor_url: 'http://ryanfb.github.io/harpocration/src/index.html'

@@ -24,7 +24,10 @@
   "https://accounts.google.com/o/oauth2/auth?#{$.param(google_oauth_parameters_for_fusion_tables)}"

 urn_to_id = (urn) ->
-  urn.replace(/[:.-]/g,'_')
+  urn.replace(/[:.'-]/g,'_')
+
+urn_to_head = (urn) ->
+  urn.replace(/^.*:/,'').replace(/_/g,' ')

 add_translation = (translation) ->
   translation_div = $('<div>').attr('class','translation')
@@ -70,24 +73,19 @@
   add_translations(urn)

 get_passage = (urn) ->
-  request_url = "#{cts_cite_collection_driver_config['cts_endpoint']}?#{$.param(
-    request: 'GetPassage'
-    urn: urn
-  )}"
-  $.ajax request_url,
-    type: 'GET'
-    dataType: 'xml'
-    crossDomain: 'true'
-    error: (jqXHR, textStatus, errorThrown) ->
-      console.log "AJAX Error: #{textStatus}"
-    success: (data) ->
-      tei_document = $($($(data)[0]).children('TEI')[0])
-      request_urn = tei_document.find('requestUrn').text()
-      entry = tei_document.find('div[type="entry"]')
-      head = $(entry).find('head').text()
-      body = $(entry).find('p').text()
-      set_cts_text(request_urn, head, body)
-
+  console.log("get_passage #{urn}")
+  fusion_tables_query "SELECT * FROM #{cts_cite_collection_driver_config['cts_endpoint']} WHERE URN = #{fusion_tables_escape(urn)}", (fusion_tables_result) ->
+    # console.log fusion_tables_result
+    passage = fusion_tables_result.rows[0]
+    # 0 = URN
+    # 1 = Perseus
+    # 2 = text
+    # 3 = SOL
+    request_urn = passage[0]
+    head = urn_to_head(request_urn)
+    set_cts_text(request_urn, head, passage[2])
+    # call set_cts_text(request_urn, head, body)
+
 show_all = ->
   $('#toggle_group button').removeClass('active')
   $('#all_entries_button').addClass('active')
@@ -118,6 +116,7 @@
   $('#untranslated_button').click(show_untranslated)
   $('#translation_container').append $('<ul>').attr('id','valid_urns')
   translated_urns = 0
+  get_passage_delay = 0
   for urn in valid_urns
     urn_li = $('<li>').attr('id',urn_to_id(urn)).text(urn)
     $('#valid_urns').append urn_li
@@ -125,12 +124,13 @@
     if localStorage["#{urn}[head]"]?
       set_cts_text(urn, localStorage["#{urn}[head]"], localStorage["#{urn}[body]"])
     else
-      get_passage(urn)
+      setTimeout(get_passage(urn),get_passage_delay * 30)
+      get_passage_delay += 1

     if cite_collection_contains_urn(urn)
       translated_urns += 1

-  progress = translated_urns/valid_urns.length * 100.0;
+  progress = translated_urns/valid_urns.length * 100.0
   console.log("Progress: #{progress}")
   $('#translation_progress').attr('style',"width: #{progress}%;")

@@ -148,23 +148,12 @@
 # construct a list of valid URN's and pass to callback function
 get_valid_reff = (urn, callback = null) ->
   console.log('get_valid_reff')
-  request_url = "#{cts_cite_collection_driver_config['cts_endpoint']}?#{$.param(
-    request: 'GetValidReff'
-    urn: urn
-  )}"
-  console.log(request_url)
-  $.ajax request_url,
-    type: 'GET'
-    dataType: 'xml'
-    crossDomain: true
-    error: (jqXHR, textStatus, errorThrown) ->
-      console.log "AJAX Error: #{textStatus}"
-    success: (data) ->
-      console.log(data)
-      valid_urns = get_valid_reff_xml_to_urn_list($($(data)[0]).children('contents')[0])
-      console.log valid_urns.length
-      callback() if callback?
-
+  # WHERE URN STARTS WITH '#{urn}'
+  fusion_tables_query "SELECT URN FROM #{cts_cite_collection_driver_config['cts_endpoint']} WHERE URN STARTS WITH '#{urn}'", (fusion_tables_result) ->
+    valid_urns = (urn[0] for urn in fusion_tables_result.rows)
+    # console.log(valid_urns)
+    callback() if callback?
+
 check_table_access = (table_id, callback) ->
   # test table access
   if get_cookie 'access_token'
@@ -177,7 +166,7 @@
         # $('.container > h1').after $('<div>').attr('class','alert alert-error').attr('id','collection_access_error').append('You do not have permission to access this collection.')
         # disable_collection_form()
       success: (data) ->
-        console.log data
+        # console.log data
       complete: (jqXHR, textStatus) ->
         callback() if callback?

@@ -203,7 +192,7 @@
             $(this).remove()
             $('#collection_select').change()
         success: (data) ->
-          console.log data
+          # console.log data
           if callback?
             callback(data)
     when 'SELECT'
@@ -215,7 +204,7 @@
         error: (jqXHR, textStatus, errorThrown) ->
           console.log "AJAX Error: #{textStatus}"
         success: (data) ->
-          console.log data
+          # console.log data
           if callback?
             callback(data)


Precarga de los fixtures, para que sea compatible con jasmine-ajax.

--- spec/javascripts/helpers/spec_helper.js.coffee
+++ spec/javascripts/helpers/spec_helper.js.coffee
@@ -9,6 +9,10 @@
       this.actual.length == length
   })

+  preloadFixtures("adjuntos", "autosave_form", "ayuda_textile",
+    "borrar_ajax", "galeria_markitup", "autocomplete_form",
+    "live_form", "paginator", "quitar_imagen", "seleccion_diferencias")
+
   spyOn(jQuery.ajaxSettings, 'xhr').andCallFake ->
     newXhr = new FakeXMLHttpRequest()
     ajaxRequests.push(newXhr)


Rename internal Drop

Rename internal Drop

--- drop.coffee
+++ drop.coffee
@@ -62,14 +62,14 @@
         className.replace(new RegExp("\\b#{ prefix }\\S+", 'g'), '').replace(/\s+/g, ' ')

 $ ->
-    drop.updateBodyClasses()
-
-    $(document).on 'openDrop.drop, closeDrop.drop', (event) -> drop.updateBodyClasses()
-
-    $(window).on 'resize', debounce(-> drop.positionAll())
-    $(window).on 'scroll.drop', debounce(-> drop.positionAll())
-
-drop =
+    Drop.updateBodyClasses()
+
+    $(document).on 'openDrop.drop, closeDrop.drop', (event) -> Drop.updateBodyClasses()
+
+    $(window).on 'resize', debounce(-> Drop.positionAll())
+    $(window).on 'scroll.drop', debounce(-> Drop.positionAll())
+
+Drop =
     baseClassNames:
         drop: 'drop'
         dropContent: 'drop-content'
@@ -91,29 +91,29 @@
     dropTargets: []

     positionAll: ->
-        $.each drop.dropTargets, (i, $target) ->
+        $.each Drop.dropTargets, (i, $target) ->
             if $target.drop 'isOpened'
                 $target.drop 'positionDrop'

     updateBodyClasses: ->
         anyOpen = false

-        $.each drop.dropTargets, (i, $target) ->
+        $.each Drop.dropTargets, (i, $target) ->
             if $target.drop 'isOpened'
                 anyOpen = true
                 return false

         if anyOpen
-            $('body').addClass(drop.baseClassNames.opened).removeClass(drop.baseClassNames.allClosed)
+            $('body').addClass(Drop.baseClassNames.opened).removeClass(Drop.baseClassNames.allClosed)
         else
-            $('body').removeClass(drop.baseClassNames.opened).addClass(drop.baseClassNames.allClosed)
+            $('body').removeClass(Drop.baseClassNames.opened).addClass(Drop.baseClassNames.allClosed)

 jQueryMethods =
     init: (opts) -> @each ->
         $target = $ @
-        drop.dropTargets.push $target
-
-        options = $.extend {}, drop.defaults, opts
+        Drop.dropTargets.push $target
+
+        options = $.extend {}, Drop.defaults, opts

         if options.attach and not (options.attachFirst or options.attachSecond)
             attachSplit = options.attach.split('-')
@@ -130,11 +130,11 @@
         options = $target.data('drop')

         options.$drop = $ '<div>'
-        options.$drop.addClass drop.baseClassNames.drop
+        options.$drop.addClass Drop.baseClassNames.drop
         options.$drop.addClass options.className

         options.$dropContent = $ '<div>'
-        options.$dropContent.addClass drop.baseClassNames.dropContent
+        options.$dropContent.addClass Drop.baseClassNames.dropContent
         options.$dropContent.append options.content

         options.$drop.append options.$dropContent
@@ -142,7 +142,7 @@
         $target.drop 'attach', options.attachFirst, options.attachSecond

         if options.closedOnInit
-            options.$drop.addClass drop.baseClassNames.closed
+            options.$drop.addClass Drop.baseClassNames.closed

         $target

@@ -198,12 +198,12 @@
         $target.drop 'positionDrop'

         $target
-            .addClass(drop.baseClassNames.opened)
-            .removeClass(drop.baseClassNames.closed)
+            .addClass(Drop.baseClassNames.opened)
+            .removeClass(Drop.baseClassNames.closed)

         options.$drop
-            .addClass(drop.baseClassNames.opened)
-            .removeClass(drop.baseClassNames.closed)
+            .addClass(Drop.baseClassNames.opened)
+            .removeClass(Drop.baseClassNames.closed)

         options.$drop.trigger
             type: 'openDrop'
@@ -216,12 +216,12 @@
         options = $target.data('drop')

         $target
-            .addClass(drop.baseClassNames.closed)
-            .removeClass(drop.baseClassNames.opened)
+            .addClass(Drop.baseClassNames.closed)
+            .removeClass(Drop.baseClassNames.opened)

         options.$drop
-            .addClass(drop.baseClassNames.closed)
-            .removeClass(drop.baseClassNames.opened)
+            .addClass(Drop.baseClassNames.closed)
+            .removeClass(Drop.baseClassNames.opened)

         options.$drop.trigger
             type: 'closeDrop'
@@ -235,8 +235,8 @@

         $([$target[0], options.$drop[0]]).each ->
             $el = $(@)
-            removePrefixedClasses($el, drop.baseClassNames.attachPrefix)
-            $el.addClass("#{ drop.baseClassNames.attachPrefix }#{ attachFirst }-#{ attachSecond }")
+            removePrefixedClasses($el, Drop.baseClassNames.attachPrefix)
+            $el.addClass("#{ Drop.baseClassNames.attachPrefix }#{ attachFirst }-#{ attachSecond }")

     positionDrop: ->
         $target = $ @
@@ -341,7 +341,7 @@

         $target

-window.Drop = drop
+window.Drop = Drop

 $.fn.drop = (options) ->
     if jQueryMethods[options]


Remove a console.log

Remove a console.log

--- app/assets/javascripts/views/user_view.js.coffee
+++ app/assets/javascripts/views/user_view.js.coffee
@@ -178,7 +178,6 @@
       @selector.html @template_item(smiley) for smiley in @smilies

     events: ->
-      console.log @selector.find('li')
       @selector.find('img').bind 'click', @insert_smiley


Handle IP objects and legacy socket events transparently

--- src/lib/InternalSocket.coffee
+++ src/lib/InternalSocket.coffee
@@ -3,6 +3,7 @@
 #     (c) 2011-2012 Henri Bergius, Nemein
 #     NoFlo may be freely distributed under the MIT license
 {EventEmitter} = require 'events'
+IP = require './IP'

 # ## Internal Sockets
 #
@@ -58,14 +59,10 @@
   #         # Otherwise, call same method recursively
   #         @readBuffer fd, position, size, buffer
   connect: ->
-    return if @connected
-    @connected = true
-    @emitEvent 'connect', @
+    @handleSocketEvent 'connect', null

   disconnect: ->
-    return unless @connected
-    @connected = false
-    @emitEvent 'disconnect', @
+    @handleSocketEvent 'disconnect', null

   isConnected: -> @connected

@@ -81,9 +78,8 @@
   # can be constructed with more flexibility, as file buffers or
   # message queues can be used as additional packet relay mechanisms.
   send: (data) ->
-    @connect() unless @connected
     data = @dataDelegate() if data is undefined and typeof @dataDelegate is 'function'
-    @emitEvent 'data', data
+    @handleSocketEvent 'data', data

   # ## Sending information packets without open bracket
   #
@@ -92,7 +88,7 @@
   # sending semantics single IP objects can be sent without open/close brackets.
   post: (data) ->
     data = @dataDelegate() if data is undefined and typeof @dataDelegate is 'function'
-    @emitEvent 'data', data
+    @handleSocketEvent 'data', data, false

   # ## Information Packet grouping
   #
@@ -124,12 +120,10 @@
   # to pass received groupings onward if the data structures remain
   # intact through the component's processing.
   beginGroup: (group) ->
-    @groups.push group
-    @emitEvent 'begingroup', group
+    @handleSocketEvent 'begingroup', group

   endGroup: ->
-    return unless @groups.length
-    @emitEvent 'endgroup', @groups.pop()
+    @handleSocketEvent 'endgroup'

   # ## Socket data delegation
   #
@@ -167,6 +161,82 @@
     return "DATA -> #{toStr(@to)}" unless @from
     "#{fromStr(@from)} -> #{toStr(@to)}"

+  legacyToIp: (event, payload) ->
+    # No need to wrap modern IP Objects
+    return payload if payload and typeof payload is 'object' and payload.isIP
+
+    # Wrap legacy events into appropriate IP objects
+    switch event
+      when 'connect'
+        return new IP 'openBracket', null
+      when 'connect', 'begingroup'
+        return new IP 'openBracket', payload
+      when 'disconnect', 'endgroup'
+        return new IP 'closeBracket'
+      else
+        return new IP 'data', payload
+
+  ipToLegacy: (ip) ->
+    switch ip.type
+      when 'openBracket'
+        if ip.data is null
+          return legacy =
+            event: 'connect'
+            payload: @
+        return legacy =
+          event: 'begingroup'
+          payload: ip.data
+      when 'data'
+        return legacy =
+          event: 'data'
+          payload: ip.data
+      when 'closeBracket'
+        if ip.data is null
+          return legacy =
+            event: 'disconnect'
+            payload: @
+        return legacy =
+          event: 'endgroup'
+          payload: ip.data
+
+  handleSocketEvent: (event, payload, autoConnect = true) ->
+    ip = @legacyToIp event, payload
+
+    # Handle state transitions
+    if ip.type is 'data' and not @connected and autoConnect
+      # Connect before sending data
+      @handleSocketEvent 'connect', null
+
+    if ip.type is 'openBracket' and ip.data
+      if not @connected and autoConnect
+        # Connect before sending bracket
+        @handleSocketEvent 'connect', null
+      # Append bracket to socket group list
+      @groups.push ip.data
+
+    if ip.type is 'openBracket' and ip.data is null
+      # If we're already connected, no need to connect again
+      return if @connected
+      @connected = true
+
+    if ip.type is 'closeBracket'
+      if @groups.length
+        # Add group name to bracket
+        ip.data = @groups.pop()
+      else
+        # If we were already disconnected, no need to disconnect again
+        return unless @connected
+        # Last bracket was closed, we're disconnected
+        @connected = false
+        ip.data = null
+
+    # Emit the IP Object
+    @emitEvent 'ip', ip
+
+    # Emit the legacy event
+    legacyEvent = @ipToLegacy ip
+    @emitEvent legacyEvent.event, legacyEvent.payload
+
 exports.InternalSocket = InternalSocket

 exports.createSocket = -> new InternalSocket


fix opening urls with '#' #593

fix opening urls with '#' #593

--- src/ui/views/messages.coffee
+++ src/ui/views/messages.coffee
@@ -63,7 +63,9 @@
     xhr.onreadystatechange = (e) ->
         return if e.target.status is 0
         return if xhr.readyState isnt 4
-        finalUrl = xhr.responseURL
+        redirected = finalUrl.indexOf(xhr.responseURL) != 0
+        if redirected
+            finalUrl = xhr.responseURL
         shell.openExternal(finalUrl)
         xhr.abort()