Play nice with other plugins

Play nice with other plugins

--- lib/index.coffee
+++ lib/index.coffee
@@ -12,7 +12,7 @@

   class PostExtension
     constructor: (@roots) ->
-      @category = "post"
+      @category = "post_#{options.folder}"
       @posts = []

     frontmatter_regexp: /^---\n([^]*?)\n---\n([^]*)$/
@@ -73,7 +73,9 @@

       _.extend(global_options, adapter_options, file_options, compile_options)

-    after_category: (ctx) ->
+    after_category: (ctx, category) ->
+      return unless category == @category
+
       adapter = @layoutFile.adapters[0]
       content = @layoutFile.originalContent
       opts = @configure_options(@layoutFile, adapter)


fix route view leg type to use backbone property style

--- web/js/views/route_view.coffee
+++ web/js/views/route_view.coffee
@@ -39,7 +39,7 @@
     _legData: () ->
       for leg in @route.get('legs')
         {
-        type: leg.type
+        type: leg.get('type')
         indicator: if leg.isWalk() then Utils.formatDistance(leg.get('length')) else leg.lineName()
         color: Utils.transportColors[leg.get('type')]
         }


Think I may have fixed the color group setting issue again.

--- app/models/CocoModel.coffee
+++ app/models/CocoModel.coffee
@@ -154,7 +154,10 @@

   markToRevert: ->
     if @type() is 'ThangType'
-      @_revertAttributes = _.clone @attributes  # No deep clones for these!
+      # Don't deep clone the raw vector data, but do deep clone everything else.
+      @_revertAttributes = _.clone @attributes
+      for smallProp, value of @attributes when value and smallProp isnt 'raw'
+        @_revertAttributes[smallProp] = _.cloneDeep value
     else
       @_revertAttributes = $.extend(true, {}, @attributes)


Remove note about subject sets

Remove note about subject sets

--- app/pages/lab/workflow.cjsx
+++ app/pages/lab/workflow.cjsx
@@ -99,7 +99,6 @@

             Associated subject sets

             Choose the set of subjects you want to use for this workflow.
-
NOTE: Assigning subject sets doesn’t quite work as expected right now. To-do on the back end.

             {@renderSubjectSets()}


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -7,6 +7,7 @@
     width: 10
     height: 20

-  player.include(C)
+  player.include(Controllable)
+

 module()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -59,7 +59,7 @@
   equals player.I.y, 18

 test "should move player down while key is pressed", ->
-  ;
+

 test "should move player back and forth when keys are changed", ->
   ;


release script #norelease

release script #norelease

--- webpack/scripts/release.coffee
+++ webpack/scripts/release.coffee
@@ -25,6 +25,21 @@
 if process.env.CIRCLE_BRANCH.startsWith('@')
   console.log("Not releasing #{process.env.CIRCLE_BRANCH}")
   process.exit(0)
+
+tags = do ->
+  regex = /(?:^|\s)(?:#)([a-zA-Z\d]+)/gm
+  matches = []
+  while match = regex.exec(process.env.CIRCLE_COMMIT_MSG)
+    matches.push(match[1])
+  return matches
+tags.push(process.env.CIRCLE_BRANCH) if process.env.CIRCLE_BRANCH.match(/^[0-9]+$/)
+tags = tags.sort().filter((item, pos, ary) -> !pos || item != ary[pos - 1])
+
+if tags.indexOf('norelease') >= 0
+  console.log("Not releasing #{process.env.CIRCLE_BRANCH} because of 'norelease' tag")
+  process.exit(0)
+
+issues = tags.filter((tag) -> !isNaN(parseInt(tag)))

 announce = Bluebird.coroutine((issue, release)->
   if process.env.CIRCLE_TAG
@@ -100,7 +115,10 @@
       content_type: 'application/rdf+xml'
     })

-    yield announce(555, release.current.tag_name) # TODO: remove after release
+    issues.push('555') # TODO: remove after release
+    issues = issues.sort().filter((item, pos, ary) -> !pos || item != ary[pos - 1]) # TODO: remove after release
+    for issue in issues
+      yield announce(issue, release.current.tag_name)

   else
     if !release.builds
@@ -121,17 +139,14 @@
       content_type: 'application/x-xpinstall'
     })

-    branch = process.env.CIRCLE_BRANCH
     if process.env.NIGHTLY == 'true'
-      issue = null
-    else if branch.match(/^[0-9]+$/)
-      issue = branch
-    else if branch == 'master' # TODO: remove after release
-      issue = '555'
-    else
-      issue = null
+      issues = []
+    else if process.env.CIRCLE_BRANCH == 'master' # TODO: remove after release
+      issues.push('555')
+      issues = issues.sort().filter((item, pos, ary) -> !pos || item != ary[pos - 1]) # TODO: remove after release

-    yield announce(issue, 'builds') if issue
+    for issue in issues
+      yield announce(issue, 'builds')

   return
 )


fix bug in casting from mongo doc back to a snapshot

--- lib/mongo.coffee
+++ lib/mongo.coffee
@@ -70,16 +70,18 @@
     delete doc._type
     delete doc._v
     delete doc._id
-    data =
+    return {
       data: doc
       type: type
       v: v
       docName: docName
-  else
-    data.type = type
-    data.v = v
-    data.docName = docName
-  return data
+    }
+  return {
+    data: data
+    type: type
+    v: v
+    docName: docName
+  }

 # mongo is a mongoskin client. Create with:
 #  mongo.db('localhost:27017/tx?auto_reconnect', safe:true)


Deferred

Deferred

- Fixed CUI.when: when, after a resolve or reject one of the
  still unresolved Promises would call "progress" we would
  throw an assert. Fix ba simply ignore progress in that
  case.

--- src/base/Deferred/when.coffee
+++ src/base/Deferred/when.coffee
@@ -48,8 +48,9 @@
 				return

 			promise.progress =>
-				# pass this through
-				dfr.notify.apply(dfr, arguments)
+				if dfr.state() == "pending"
+					# pass this through
+					dfr.notify.apply(dfr, arguments)
 				return

 	dfr.promise()


fix #15

fix #15

--- lib/autohide-tree-view.coffee
+++ lib/autohide-tree-view.coffee
@@ -35,6 +35,16 @@
       type: 'boolean'
       default: false
       order: 4
+    focusTreeViewOnOpen:
+      description: 'Focus the tree view after it opens. Not recommended because it might cause some issues with focusing other parts of the editor.'
+      type: 'boolean'
+      default: false
+      order: 5
+    unfocusTreeViewOnClose:
+      description: 'Focuses the text editor after closing the tree view. Not recommended because it might cause some issues with focusing other parts of the editor.'
+      type: 'boolean'
+      default: false
+      order: 6

   activate: (state) ->
     atom.packages.onDidActivateInitialPackages @initialize
@@ -129,6 +139,8 @@
       @animate treeViewEl.clientWidth, =>
         @visible = true
     , Number(!noDelay) * @conf.showDelay
+    if @conf.focusTreeViewOnOpen
+      @getTreeViewModel().focus()

   hide: (noDelay = false) =>
     return unless @getTreeViewResizerEl()
@@ -137,6 +149,8 @@
         @visible = false
     , Number(!noDelay) * @conf.hideDelay
     @enableHoverEvents()
+    if @conf.unfocusTreeViewOnClose
+      @getTreeViewModel().unfocus()

   toggle: =>
     console.log @visible


Fixes #2422 -- Catch clause scoping plus old IE

--- nodes.coffee
+++ nodes.coffee
@@ -1739,13 +1739,11 @@
     tryPart   = @attempt.compileToFragments o, LEVEL_TOP

     catchPart = if @recovery
-      if @error.isObject?()
-        placeholder = new Literal '_error'
-        @recovery.unshift new Assign @error, placeholder
-        @error = placeholder
+      placeholder = new Literal '_error'
+      @recovery.unshift new Assign @error, placeholder
+      @error = placeholder
       if @error.value in STRICT_PROSCRIBED
         throw SyntaxError "catch variable may not be \"#{@error.value}\""
-      o.scope.add @error.value, 'param' unless o.scope.check @error.value
       [].concat @makeCode(" catch ("), @error.compileToFragments(o), @makeCode(") {\n"),
         @recovery.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
     else unless @ensure or @recovery


Improve log hints ids.

Improve log hints ids.

--- services/web/public/coffee/ide/human-readable-logs/HumanReadableLogs.coffee
+++ services/web/public/coffee/ide/human-readable-logs/HumanReadableLogs.coffee
@@ -12,7 +12,8 @@
 			ruleDetails = _getRule entry.message

 			if (ruleDetails?)
-				entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/[^a-zA-Z0-9]/g, '_').toLowerCase() if ruleDetails.regexToMatch?
+				entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/\s/g, '_').slice(1, -1) if ruleDetails.regexToMatch?
+
 				entry.humanReadableHint = ruleDetails.humanReadableHint if ruleDetails.humanReadableHint?
 				entry.extraInfoURL = ruleDetails.extraInfoURL if ruleDetails.extraInfoURL?


Don't listen hubot's own messages with Flowdock adapter.

--- src/adapters/flowdock.coffee
+++ src/adapters/flowdock.coffee
@@ -34,6 +34,7 @@
       return unless message.event == 'message'
       flow = bot.flows.filter((flow) -> return flow.name == message.flow)[0]
       author = @userForId(message.user)
+      return if @name == author.name
       author.flow = flow
       self.receive new Robot.TextMessage(author, message.content)


n.source_path.value, not n.source_path

n.source_path.value, not n.source_path

--- lib/closure-conversion.coffee
+++ lib/closure-conversion.coffee
@@ -1990,8 +1990,8 @@
                         #
                         # let #{n.specifiers[0].id} = %import_decl.default
                         #
-                        if not @exportLists[n.source_path]?.has_default
-                                reportError(ReferenceError, "module `#{n.source_path}' doesn't have default export", @filename, n.loc)
+                        if not @exportLists[n.source_path.value]?.has_default
+                                reportError(ReferenceError, "module `#{n.source_path.value}' doesn't have default export", @filename, n.loc)

                         reportError(ReferenceError, "default imports should have only one ImportSpecifier", @filename, n.loc) if n.specifiers.length isnt 1
                         import_decls.declarations.push {


guard against null exp.param when in free(CatchClause)

--- lib/closure-conversion.coffee
+++ lib/closure-conversion.coffee
@@ -51,7 +51,7 @@
                 when syntax.BlockStatement        then exp.ejs_free_vars = free_blocklike exp, exp.body
                 when syntax.TryStatement          then exp.ejs_free_vars = Set.union.apply null, [(free exp.block)].concat (map free, exp.handlers)
                 when syntax.CatchClause
-                        param_set = if exp.param.name? then new Set [exp.param.name] else new Set
+                        param_set = if exp.param?.name? then new Set [exp.param.name] else new Set
                         exp.ejs_free_vars = (free exp.body).subtract param_set
                         exp.ejs_decls = exp.body.ejs_decls.union param_set
                         exp.ejs_free_vars


refactoring

refactoring

--- app/assets/javascripts/media_lib/jquery.nmdUploader.js.coffee
+++ app/assets/javascripts/media_lib/jquery.nmdUploader.js.coffee
@@ -31,11 +31,9 @@

       @each ->
         $uploader = $ @
-        uploader = $uploader.data()

-        uploaderId = $.md5(Math.random())[0..3]
-        if $uploader.attr 'id' then uploaderId = $uploader.attr 'id'
-        else $uploader.attr 'id', uploaderId
+        $uploader.attr('id', $.md5(Math.random())[0..3]) unless $uploader.attr('id')
+        uploaderId = $uploader.attr('id')

         getUrl = ->
           # "Живой" префикс


fancy status toggles

fancy status toggles

--- app/assets/javascripts/monitoring/views/add_trigger.js.coffee
+++ app/assets/javascripts/monitoring/views/add_trigger.js.coffee
@@ -4,13 +4,37 @@
     el: "div.monitoring_content"
     template: "monitoring/add_trigger"
     events: {
+
+      # update Sign in button text
       "click ul.trigger_sign a": (e) ->
         e.preventDefault()
         $("button.trigger_sign").text $(e.target).text()
         $("input.sign").val $(e.target).attr("value")

+      # disable auto-toggling of statuses
+      "click input.trigger_status": (e) ->
+        @no_toggle_status = true
+
+      # toggle status checkboxes when selecting severity
+      "change #severity": (e) ->
+        if @no_toggle_status? && @no_toggle_status
+          return # don't flip bits if user has manually made selections
+
+        warn = [ "WARNING", "UNKNOWN", "TIMEOUT" ]
+        if $(e.target).val() == "warning"
+          # select warning defaults
+          _.each warn, (s) ->
+            $("input.trigger_status[value='#{s}']").prop("checked", true)
+          $("input.trigger_status[value='CRITICAL']").prop("checked", false)
+
+        else
+          # select critical defaults
+          _.each warn, (s) ->
+            $("input.trigger_status[value='#{s}']").prop("checked", false)
+          $("input.trigger_status[value='CRITICAL']").prop("checked", true)
+
+      # create trigger
       "click #submit_trigger": (e) ->
-        # create trigger obj
         trigger = new Bixby.model.Trigger
         trigger.host = host = @host
         trigger.set {


jquery

jquery

--- app/assets/javascripts/store/spree_brazilian_fields.js.coffee
+++ app/assets/javascripts/store/spree_brazilian_fields.js.coffee
@@ -31,5 +31,5 @@
       enable '#spree_user_additional_information_attributes_cpf'
       enable '#spree_user_additional_information_attributes_name'

-  toggle_fields
   $('[name="spree_user[additional_information_attributes][account_type]"]').click(toggle_fields)
+toggle_fields


make loading messages persistent

make loading messages persistent

--- lib/connection/process.coffee
+++ lib/connection/process.coffee
@@ -13,7 +13,8 @@
       if @useWrapper and @proc
         @proc.kill()

-    client.handle 'welcome', ->
+    client.handle 'welcome', =>
+      @note?.dismiss()
       atom.notifications.addSuccess "Welcome to Juno!",
         detail: """
         Success! Juno is set up and ready to roll.
@@ -101,6 +102,7 @@
       'julia-client:open-console'

   bootErr: (err) ->
+    @note?.dismiss()
     switch err
       when 'juno-err-install'
         atom.notifications.addError "Error installing Atom.jl package",
@@ -121,18 +123,20 @@
           """
           dismissable: true
       when 'juno-err-installing'
-        atom.notifications.addInfo "Installing Julia packages...",
+        @note = atom.notifications.addInfo "Installing Julia packages...",
           detail: """
           Julia's first run will take a couple of minutes.
           See the console below for progress.
           """
+          dismissable: true
         @openConsole()
       when 'juno-err-precompiling'
-        atom.notifications.addInfo "Compiling Julia packages...",
+        @note = atom.notifications.addInfo "Compiling Julia packages...",
           detail: """
           Julia's first run will take a couple of minutes.
           See the console below for progress.
           """
+          dismissable: true
         @openConsole()
       else client.stderr err


Fix dynamicNick

Fix dynamicNick

--- modules/dynamicNick.coffee
+++ modules/dynamicNick.coffee
@@ -1,19 +1,22 @@
 class DynamicNick extends BotModule
+  init: ->
+    @defaultDisabled = true
+
   ready: ->
     @registerEvent 'player.playing', ({ guild }, item)=>
       iC = '▶'
       iC = '📡' if not item.duration
       iC = '📻' if item.radioStream
-      try guild.members.find('id', core.bot.user.id).setNickname("#{iC} | #{@getTitle(item)}")
+      try guild.members.find('id', Core.bot.user.id).setNickname("#{iC} | #{@getTitle(item)}")
     @registerEvent 'player.paused', ({ guild }, item)=>
-      try guild.members.find('id', core.bot.user.id).setNickname("⏸ | #{@getTitle(item)}")
+      try guild.members.find('id', Core.bot.user.id).setNickname("⏸ | #{@getTitle(item)}")
     @registerEvent 'player.suspended', ({ guild }, item)=>
       iC = '⏸'
       iC = '📡' if not item.duration
       iC = '📻' if item.radioStream
-      try guild.members.find('id', core.bot.user.id).setNickname("#{iC} | #{@getTitle(item)}")
+      try guild.members.find('id', Core.bot.user.id).setNickname("#{iC} | #{@getTitle(item)}")
     @registerEvent 'player.stopped', ({ guild })=>
-      try guild.members.find('id', core.bot.user.id).setNickname(null)
+      try guild.members.find('id', Core.bot.user.id).setNickname(null)

   getTitle: (item)->
     title = item.title.substr(0, 28)


add "$.id.[property|function]" completions 😁

--- lib/controllerProvider.coffee
+++ lib/controllerProvider.coffee
@@ -2,9 +2,12 @@
 tagRegExp =  /(<([^>]+)>)/ig
 util = require './ti-pkg-util'
 related = require './related'
+_ = require 'underscore'
+viewAutoProvider = require './viewProvider';

 propertyNamePrefixPattern = /\.([a-zA-Z]+[-a-zA-Z-_]*)$/
-alloyIdNamePatter = /\$\.([-a-zA-Z0-9-_]*)$/
+alloyIdNamePattern = /\$\.([-a-zA-Z0-9-_]*)$/
+alloyIdMemberPattern = /\$\.([-a-zA-Z0-9-_]*).([-a-zA-Z0-9-_]*)$/

 module.exports =
   # This will work on JavaScript and CoffeeScript files, but not in js comments.
@@ -31,10 +34,10 @@
     line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])

     # if(@isPropertyNameCompletion()){
-    console.log alloyIdNamePatter.test(line)
-    console.log alloyIdNamePatter.exec(line)
+    console.log alloyIdNamePattern.test(line)
+    console.log alloyIdNamePattern.exec(line)
     console.log line
-    if alloyIdNamePatter.test(line)
+    if alloyIdNamePattern.test(line) # id name
       sourceEditor = util.getFileEditor related.getTargetPath('xml')
       if(!sourceEditor.isEmpty())
         sourceEditor.scan /id="(.*?)"/g, (item) ->
@@ -44,6 +47,31 @@
             text: item.match[1]
             # description: item.match[1]'class definition'
           })
+    else if alloyIdMemberPattern.test(line)
+      idName = alloyIdMemberPattern.exec(line)[1]
+      console.log ('View lets find tag name');
+      sourceEditor = util.getFileEditor related.getTargetPath('xml')
+
+      if(!sourceEditor.isEmpty())
+        curTagName = '';
+        sourceEditor.scan new RegExp("id=[\"']#{idName}[\"']",'g'), (item) ->
+          curTagName = viewAutoProvider.getPreviousTag(sourceEditor,item.range.start);
+          item.stop();
+
+        if curTagName
+          apiName = @completions.tags[curTagName].apiName
+          curTagObject = @completions.types[apiName]
+          _.each curTagObject.functions, (value)->
+            completions.push
+              type: 'function'
+              text: value
+              rightLabel: "<#{curTagName}>"
+
+          _.each curTagObject.properties, (value)->
+            completions.push
+              type: 'attribute'
+              text: value
+              rightLabel: "<#{curTagName}>"
     else
       completions = @getPropertyNameCompletions(request)


merging in gfxmonk's fix for reporting line numbers for unclosed { [ ( opening symbols

--- rewriter.coffee
+++ rewriter.coffee
@@ -189,7 +189,7 @@
     if unclosed.length
       open: unclosed[0]
       line: open_line[open] + 1
-      throw new Error("unclosed ${open} on line ${line}")
+      throw new Error "unclosed $open on line $line"

   # We'd like to support syntax like this:
   #


Clear 'Saved' message when clicking Save button in user preferences.

--- app/assets/javascripts/discourse/controllers/preferences_controller.js.coffee
+++ app/assets/javascripts/discourse/controllers/preferences_controller.js.coffee
@@ -42,6 +42,7 @@

   save: ->
     @set('saving', true)
+    @set('saved', false)

     # Cook the bio for preview
     @get('content').save (result) =>


Only process errors for oauth routes

Only process errors for oauth routes

--- oauth.coffee
+++ oauth.coffee
@@ -72,4 +72,4 @@

 		@app.use @routes

-		@app.use @oauth.errorHandler()
+		@app.all '/oauth/*', @oauth.errorHandler()


GoogleMap#setFromLatLng added

GoogleMap#setFromLatLng added

--- vendor/assets/javascripts/rails-google-maps/google_maps.js.coffee
+++ vendor/assets/javascripts/rails-google-maps/google_maps.js.coffee
@@ -35,7 +35,6 @@
       @saveLangLat = true
       @latLng = new LatLngContainer(options['latitudeInput'], options['longitudeInput'])

-
   apply: ()->
     if($(@mapSelector).length > 0)
       @map = new google.maps.Map $(@mapSelector)[0], @gmapOptions
@@ -69,6 +68,9 @@
       @map.fitBounds geocode.geometry.viewport
       @marker.setPosition geocode.geometry.location
     @latLng.store(geocode.geometry) if @saveLangLat
+
+  setFromLatLng: ()->
+    @setMarker('latLng', new google.maps.LatLng(@latLng.lat(), @latLng.lng()))

   _addListeners: ()->
     google.maps.event.addListener @marker, 'dragend', () =>
@@ -132,6 +134,15 @@
     @latitudeInput = $(latitudeInput)
     @longitudeInput = $(longitudeInput)

+  lat: ()->
+    @latitudeInput.val()
+
+  lng: ()->
+    @longitudeInput.val()
+
+  googleLatLng: ()->
+    new google.maps.LatLng(@lat, @lng)
+
   store: (geometry)->
     @latitudeInput.val(geometry.location.lat())
     @longitudeInput.val(geometry.location.lng())


plotview no longer has request_render function

--- src/coffee/bokeh_views.coffee
+++ src/coffee/bokeh_views.coffee
@@ -210,12 +210,12 @@
     @moveCallbacks = []
     @mousedownCallbacks = []
     @keydownCallbacks = []
-    safebind(this, @viewstate, 'change', @request_render)
+    safebind(this, @viewstate, 'change', @render)
     safebind(this, @model, 'change:renderers', @build_renderers)
     safebind(this, @model, 'change:axes', @build_axes)
     safebind(this, @model, 'change:tools', @build_tools)
-    safebind(this, @model, 'change', @request_render)
-    safebind(this, @viewstate, 'change', @request_render)
+    safebind(this, @model, 'change', @render)
+    safebind(this, @viewstate, 'change', @render)
     safebind(this, @model, 'destroy', () => @remove())
     @$el.append($("""
       <div class='button_bar'/>


variable decrypted_assertion on line 544 was not used. Removed it.

--- lib/saml2.coffee
+++ lib/saml2.coffee
@@ -541,7 +541,6 @@
         return setImmediate cb, new Error("Request body does not contain SAMLResponse or SAMLRequest.")

       saml_response = null
-      decrypted_assertion = null
       response = {}

       async.waterfall [


Reuse the access token to reduce HTTP requests

ref #1

--- lib/microsoft-translator-client.coffee
+++ lib/microsoft-translator-client.coffee
@@ -11,6 +11,7 @@
   @grantType: 'client_credentials'

   accessTokenRequestOptions = null
+  accessToken = null

   constructor: (clientId, clientSecret) ->
     # Initialize the modules
@@ -29,17 +30,31 @@

   translate: (text, from, to, onSucceeded, onFailed) ->
     new Promise((resolve, reject) =>
-      # Get an access token
-      request.post(@accessTokenRequestOptions, (error, response, body) =>
-        if !error? || 200 <= response.statusCode < 400
-          resolve(body.access_token)
-        else
-          reject({
-            message: "Cannot obtain an access token"
-            statusCode: response.statusCode
-            err: error
-          })
-      )
+      # Check whether the previous access token is valid
+      currentTime = new Date().getTime()
+      if @accessToken? && @accessToken.expired > currentTime
+        # Valid
+        resolve(@accessToken.token)
+      else
+        console.log("access token", @accessToken)
+        requestedTime = new Date().getTime()
+        # Invalid, get an access token via API
+        request.post(@accessTokenRequestOptions, (error, response, body) =>
+          if !error? || 200 <= response.statusCode < 400
+            # Update the access token
+            if body.expires_in?
+              @accessToken = {
+                token: body.access_token
+                expired: requestedTime + body.expires_in * 1000 # sec -> msec
+              }
+            resolve(body.access_token)
+          else
+            reject({
+              message: "Cannot obtain an access token"
+              statusCode: response.statusCode
+              err: error
+            })
+        )
     ).then(
       (token) =>
         # Translate via Microft Translator API


add functionality to bup server for reading a file from a project.

--- salvus/bup_server.coffee
+++ salvus/bup_server.coffee
@@ -68,6 +68,7 @@
         command : "sudo"
         args    : ["/usr/local/bin/bup_storage.py", "--zpool", ZPOOL].concat(opts.args)
         timeout : opts.timeout
+        bash    : false
         path    : process.cwd()
         cb      : (err, output) =>
             winston.debug("bup_storage: finished running #{misc.to_json(opts.args)} -- #{err}")
@@ -1108,7 +1109,7 @@
             server_id : undefined
             timeout   : TIMEOUT
             cb        : required
-        dbg = (m) => winston.debug("GlobalProject.directory_listing(#{@project_id}, #{opts.path}: #{m}")
+        dbg = (m) => winston.debug("GlobalProject.directory_listing(#{@project_id}, #{opts.path}): #{m}")
         dbg()
         project = undefined
         listing = undefined
@@ -1134,6 +1135,39 @@
         ], (err) =>
             opts.cb(err, listing)
         )
+
+    # read files from this project
+    read_file: (opts) =>
+        opts = defaults opts,
+            path      : required
+            maxsize   : 3000000    # 3MB
+            server_id : undefined
+            timeout   : TIMEOUT
+            cb        : required
+        dbg = (m) => winston.debug("GlobalProject.read_file(#{@project_id}, #{opts.path}): #{m}")
+        dbg()
+        project = undefined
+        data = undefined
+        async.series([
+            (cb) =>
+                dbg("get the project")
+                @project
+                    server_id : opts.server_id
+                    cb        : (err, p) =>
+                        project = p; cb(err)
+            (cb) =>
+                dbg("do the read_file action")
+                project.read_file
+                    path    : opts.path
+                    maxsize : opts.maxsize
+                    timeout : opts.timeout
+                    cb      : (err, _data) =>
+                        data = _data
+                        cb(err)
+        ], (err) =>
+            opts.cb(err, data)
+        )
+

     # copy a path from this project to another project
     copy_path: (opts) =>
@@ -3069,7 +3103,7 @@
             cb      : undefined
         @action
             action  : 'mkdir'
-            param   : ["--path=#{opts.path}"]
+            param   : ["--path", opts.path]
             timeout : opts.timeout
             cb      : (err, resp) =>
                 if err
@@ -3089,13 +3123,33 @@
             limit   : -1
             timeout : TIMEOUT
             cb      : required
-        param =  ["--path=#{opts.path}", "--start=#{opts.start}", "--limit=#{opts.limit}"]
+        param =  ["--path", opts.path, "--start", opts.start, "--limit", opts.limit]
         if opts.hidden
             param.push("--hidden")
         if opts.time
             param.push("--time")
         @action
             action  : 'directory_listing'
+            param   : param
+            timeout : opts.timeout
+            cb      : (err, resp) =>
+                if err
+                    opts.cb(err)
+                else
+                    if resp.result?.error
+                        opts.cb(resp.result.error)
+                    else
+                        opts.cb(undefined, resp?.result)
+
+    read_file: (opts) =>
+        opts = defaults opts,
+            path    : required
+            maxsize : 3000000
+            timeout : TIMEOUT
+            cb      : required
+        param =  ["--path", opts.path, "--maxsize", opts.maxsize]
+        @action
+            action  : 'read_file'
             param   : param
             timeout : opts.timeout
             cb      : (err, resp) =>


Disable autocomplete in comment and string

--- lib/providers/abstract-provider.coffee
+++ lib/providers/abstract-provider.coffee
@@ -5,6 +5,8 @@

   inclusionPriority: 1
   excludeLowerPriority: true
+
+  disableForSelector: '.source.php .comment, .source.php .string'

   # Build the snippet from the suggestion
   getFunctionSnippet: (word, elements) ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


className isn't a propType

className isn't a propType

--- src/components/exercise-card.cjsx
+++ src/components/exercise-card.cjsx
@@ -15,7 +15,7 @@
     displayAllTags: React.PropTypes.bool
     hideAnswers: React.PropTypes.bool
     toggleExercise: React.PropTypes.func
-    className: React.PropTypes.className
+    className: React.PropTypes.string
     exercise:   React.PropTypes.shape(
       content: React.PropTypes.object
       tags:    React.PropTypes.array


Fix typo

Fix typo

--- lib/value.coffee
+++ lib/value.coffee
@@ -26,7 +26,7 @@

           unless already
             if value.indexOf('-webkit-filter') != -1 and
-               (decl.prop == 'transition' or decl.prop == 'trasition-property')
+               (decl.prop == 'transition' or decl.prop == 'transition-property')
               decl.value = value
             else
               cloned = @clone(decl, value: value)


Generate bearer only if response has code 401

--- app/assets/javascripts/angular/services/registrydata_service.coffee
+++ app/assets/javascripts/angular/services/registrydata_service.coffee
@@ -46,7 +46,7 @@
               }
               deferred.reject(res)
             else
-              if counter == 0 && $rootScope.globals != undefined && $rootScope.globals.currentUser != undefined
+              if counter == 0 && $rootScope.globals != undefined && $rootScope.globals.currentUser != undefined && response.status == 401
                 counter++
                 AuthHeader = response.headers()['www-authenticate']
                 registrytokenService.create_token(AuthHeader).then(
@@ -58,7 +58,7 @@
                 )
               else
                 res = {
-                  error: response.data["errors"][0]
+                  error: response.statusText
                   status: response.status
                   headers: response.headers()
                 }


Remove uglify task for debug compilation

--- gruntfile.coffee
+++ gruntfile.coffee
@@ -45,7 +45,7 @@
     watch:
       coffee:
         files: ['<%= source.coffee %>']
-        tasks: ['coffee:core', 'uglify']
+        tasks: ['coffee:core']
       spec:
         files: ['<%= source.spec %>']
         tasks: ['coffee:spec', 'jasmine']


move styles to top

move styles to top

--- public/app.coffee
+++ public/app.coffee
@@ -63,11 +63,11 @@

 initializeWidgets = ->
   style = """
-    <style type="text/css">
+    <style type="text/css" id="epages-shop-styles">
       .epages-shop-widget  {
         overflow: auto;
       }
-      .epages-shop-product {
+      .epages-shop-widget .epages-shop-product {
         float: left;
         width: 100px;
         margin: 10px;
@@ -75,7 +75,8 @@
       }
     </style>
   """
-  document.getElementsByTagName("head")[0].insertAdjacentHTML "beforeend", style
+  head = document.getElementsByTagName("head")[0]
+  head.insertAdjacentHTML("afterbegin", style)
   _.each Widget.all(), (widget) ->
     widget.grabShopId()
     initializeWidget(widget)


Add a description for each package

Add a description for each package

--- package.cson
+++ package.cson
@@ -1 +1,2 @@
-'main': 'lib/wrap-guide-view'
+'main': './lib/wrap-guide-view'
+'description': 'Display a vertical line at the 80th character in the editor.\n\nThis packages uses the config value of `editor.preferredLineLength` when set.'


only router navigate as fallback for book linking from cc

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -98,7 +98,7 @@
       @cc.on('open', @cc.handleOpen)
       @cc.on('book.update', @updatePageFromCCNav)

-      Backbone.on('window:optimizedResize', =>
+      Backbone.on('window:resize', =>
         @cc.handleResize()
       )

@@ -108,7 +108,7 @@
       @cc.setOptions(options)

     lookUpPageByUuid: (uuid) ->
-      {allPages} = @parent?.parent?.regions?.sidebar?.views?[0]
+      {allPages} = @parent.parent.regions.sidebar.views[0]
       _.find(allPages, (page) ->
         page.getUuid() is uuid
       )
@@ -130,12 +130,11 @@
             pageNumber = page.getPageNumber()

         href = linksHelper.getPath('contents', pathInfo)
-        @goToPage(pageNumber, href)
+        return @goToPage(page.getPageNumber(), href)

       router.navigate(link, {trigger: true})

     goToPage: (pageNumber, href) ->
-      console.info('goToPage', pageNumber, href)
       @model.setPage(pageNumber)
       router.navigate href, {trigger: false}, => @parent.parent.parent.trackAnalytics()
       $(window).scrollTop(0)


Fix creating availabilities for whole day

--- app/assets/javascripts/back/back.js.coffee
+++ app/assets/javascripts/back/back.js.coffee
@@ -134,6 +134,8 @@
     dayClick : (date, jsEvent, view) ->
       date = moment.tz(date.format(), "Europe/Paris").format()
       return if(new Date(date) <= new Date())
+      eventDiv = $(this)
+      eventDivHtml = $(this).html()
       $.ajax({
         type: 'POST'
         url: '/firemen/' + fireman_id + '/fireman_availabilities'
@@ -142,6 +144,8 @@
           fireman_availability:
             "fireman_id"   : fireman_id
             "availability" : date
+        beforeSend: ->
+          eventDiv.html('Chargement...')
         success : (data) ->
           new_event =
             title: ""
@@ -150,22 +154,34 @@
             allDay: false
             id: data["id"]
           $('#calendar').fullCalendar('renderEvent', new_event)
-      })
+      }).always ->
+        eventDiv.html(eventDivHtml)
     eventRender: (event, element) ->
       element.find('.fc-time').remove()
       element
     eventClick : (calEvent, jsEvent, view) ->
       return if(new Date(calEvent.start) <= new Date())
+      eventDiv = $(this)
+      eventDivHtml = $(this).html()
       $.ajax({
         type: 'DELETE'
         url: '/firemen/' + fireman_id + '/fireman_availabilities/' + calEvent.id
+        beforeSend: ->
+          eventDiv.html('Chargement...')
         success : (data) ->
           $('#calendar').fullCalendar('removeEvents', calEvent._id)
-      })
+      }).always ->
+        eventDiv.html(eventDivHtml)
+    viewRender : ( view, element ) ->
+      # set data for each day to handle click
+      $('.fc-day-header').each (index) ->
+        current = moment(view.start)
+        current.add(index, 'd')
+        $( this ).data('date', current)
   })

   $('#calendar').on 'click', '.fc-day-header', ->
-    currentDay = moment($(this).html(), 'ddd DD/MM/YY')
+    currentDay = $(this).data('date')
     events = $('#calendar').fullCalendar('clientEvents', (event) ->
       return (event.start.diff(currentDay.startOf('day'), 'hours') == 0)
     )
@@ -187,7 +203,7 @@
         data:
           fireman_availability:
             "fireman_id"   : fireman_id
-            "availability" : currentDay.format()
+            "availability" : moment.tz(currentDay.format(), "Europe/Paris").format()
         success : (data) ->
           $('#calendar').fullCalendar('refetchEvents')
       })
@@ -259,7 +275,7 @@
         refresh_firemen(currentView, currentId)
     eventRender: (event, element) ->
       element.find('.fc-time').remove()
-      element
+      element
     eventClick: ( event, jsEvent, view ) ->
       eventDiv = $(this)
       eventDivHtml = $(this).html()


add pxiel based height instead of percentage

--- app/assets/javascripts/main/routing.coffee
+++ app/assets/javascripts/main/routing.coffee
@@ -103,8 +103,8 @@
             #reset some attributes before invoking panZoom plugin
             $svg = $(".graph.well").find("svg")
             $svg[0].removeAttribute("viewBox") #get rid of the troublemaker. messes up transformations
-            $svg[0].setAttribute("width", "100%")
-            $svg[0].setAttribute("height", "100%")
+            $svg[0].setAttribute("width", "#{$(window).width() - 100}px")
+            $svg[0].setAttribute("height", "#{$(window).height() - 50 - $svg.offset().top}px" )
             $svg.css("max-width", "100%")

             new PanZoomSVG($svg)


OX-120 priorityOffset fix no 2

OX-120 priorityOffset fix no 2


BF-187 Bug fix in preloading

BF-187 Bug fix in preloading

--- app/assets/javascripts/model/binary.coffee
+++ app/assets/javascripts/model/binary.coffee
@@ -127,14 +127,14 @@
       console.time "ping"

       @positionBucket = [position[0] >> (5 + zoomStep), position[1] >> (5 + zoomStep), position[2] >> (5 + zoomStep)]
-      buckets   = @getBucketArray(@positionBucket, @TEXTURE_SIZE >> (6 + zoomStep), @TEXTURE_SIZE >> 6, 0).concat(
+      buckets   = @getBucketArray(@positionBucket, @TEXTURE_SIZE >> 6, @TEXTURE_SIZE >> 6, 0).concat(
                   @getBucketArray(@positionBucket, @TEXTURE_SIZE >> 6, 0, @TEXTURE_SIZE >> 6),
                   @getBucketArray(@positionBucket, 0, @TEXTURE_SIZE >> 6, @TEXTURE_SIZE >> 6))
       # Buckets of zoom step 3 so that there won't be any black
       @positionBucket3 = [position[0] >> (5 + 3), position[1] >> (5 + 3), position[2] >> (5 + 3)]
-      buckets3  = @getBucketArray(@positionBucket3, @TEXTURE_SIZE >> (6 + zoomStep), @TEXTURE_SIZE >> (6 + zoomStep), 0).concat(
-                  @getBucketArray(@positionBucket3, @TEXTURE_SIZE >> (6 + zoomStep), 0, @TEXTURE_SIZE >> (6 + zoomStep)),
-                  @getBucketArray(@positionBucket3, 0, @TEXTURE_SIZE >> (6 + zoomStep), @TEXTURE_SIZE >> (6 + zoomStep)))
+      buckets3  = @getBucketArray(@positionBucket3, @TEXTURE_SIZE >> (6 + 3 - zoomStep), @TEXTURE_SIZE >> (6 + 3 - zoomStep), 0).concat(
+                  @getBucketArray(@positionBucket3, @TEXTURE_SIZE >> (6 + 3 - zoomStep), 0, @TEXTURE_SIZE >> (6 + 3 - zoomStep)),
+                  @getBucketArray(@positionBucket3, 0, @TEXTURE_SIZE >> (6 + 3 - zoomStep), @TEXTURE_SIZE >> (6 + 3 - zoomStep)))

       Cube.extendByBucketAddressExtent6(
         @positionBucket[0] - (@TEXTURE_SIZE >> 6), @positionBucket[1] - (@TEXTURE_SIZE >> 6), @positionBucket[2] - (@TEXTURE_SIZE >> 6),
@@ -162,6 +162,8 @@
       index = buckets.length
       level = 0

+      console.time "queue 1"
+      console.log "Buckets 1: " + buckets3.length
       if zoomStep != 3            # don't do this if you need to load the lowest resolution anyway
         for coordinate in [0..2]
           i = [0, 0, 0]
@@ -171,8 +173,10 @@
               if b
                 priority = Math.max(Math.abs(b[0] - @positionBucket3[0]), Math.abs(b[1] - @positionBucket3[1]), Math.abs(b[2] - @positionBucket3[2]))
                 PullQueue.insert [b[0] + i[0], b[1] + i[1], b[2] + i[2]], 3, priority + Math.abs(indexValue)*buckets3.length
-
+      console.timeEnd "queue 1"
+
       i = buckets.length * preloading.length
+      console.log "Buckets 2: " + buckets.length
       while i--
         index--
         if buckets[index]


remove "in parallel"

remove "in parallel"

--- src/smc-hub/postgres-server-queries.coffee
+++ src/smc-hub/postgres-server-queries.coffee
@@ -2044,7 +2044,7 @@
                     else
                         elapsed_t = process.hrtime(start_t)
                         duration_s = (elapsed_t[0] + elapsed_t[1] / 1e9).toFixed(4)
-                        dbg("everything succeeded in parallel above after #{duration_s} secs -- now insert stats")
+                        dbg("everything succeeded above after #{duration_s} secs -- now insert stats")
                         # storing in local and db cache
                         stats.id = misc.uuid()
                         @_stats_cached = misc.deep_copy(stats)


Reduce amount of skus query string

Reduce amount of skus query string

--- src/coffee/queryutils.coffee
+++ src/coffee/queryutils.coffee
@@ -33,10 +33,9 @@
   # @param {object} service - SDK service object
   # @param {Array} products
   @matchBySku: (products) ->
-    skus = _.flatten(products.map((p) ->
-      [p.product.masterVariant.sku].concat(p.product.variants.map((v) ->
-        v.sku))))
-        .filter(Helpers.exists)
+    skus = products.map((p) ->
+      p.product.masterVariant.sku
+    ).filter(Helpers.exists)
     predicate = QueryUtils.formatAttributePredicate("sku", skus)
     QueryUtils.applyPredicateToVariants(predicate)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/active_bounds.coffee
+++ src/active_bounds.coffee
@@ -11,6 +11,8 @@
       velocity: Point(120, 0)

     bullet.include ActiveBounds
+
+    # =

 ActiveBounds module
 @name ActiveBounds


Try the fix suggested in StackOverflow

Try the fix suggested in StackOverflow

--- app/assets/javascripts/residents.js.coffee
+++ app/assets/javascripts/residents.js.coffee
@@ -1,4 +1,4 @@
-civic.controller "ResidentFormController", ($scope) ->
+civic.controller "ResidentFormController", ["$scope", ($scope) ->
   MINIMUM_PASSWORD_LENGTH = 4

   $scope.model =
@@ -65,3 +65,4 @@
     password_confirmation: ->
       model = $scope.model
       verify "password_confirmation", model.password_confirmation == model.password, "passwords do not match"
+  ]


should only reload page after toggle is complete.

--- app/assets/javascripts/test_mode.js.coffee
+++ app/assets/javascripts/test_mode.js.coffee
@@ -4,7 +4,6 @@
   switchSuccess = ->
     location.reload()
   elem.on('switchChange.bootstrapSwitch', ((event, state) ->
-    $.ajax(url: elem.data('update-path'), success: switchSuccess, type: 'POST', data: {"organization[testmode]": state, _method: 'PATCH' } )
-    location.reload()
+    $.ajax(url: elem.data('update-path'), complete: switchSuccess, type: 'POST', data: {"organization[testmode]": state, _method: 'PATCH' } )
   ));
 )


remove config from before hook. via @roideuniverse

--- root/init.coffee
+++ root/init.coffee
@@ -13,7 +13,7 @@
   }
 ]

-exports.before = (utils, config) ->
+exports.before = (utils) ->
   # before hook

 exports.beforeRender = (utils, config) ->


re-enable submit button on lead failure

re-enable submit button on lead failure

--- app/cells/folio/lead_form/lead_form.coffee
+++ app/cells/folio/lead_form/lead_form.coffee
@@ -16,5 +16,6 @@
           $response.trigger('folio:failure')

       .catch ->
+        alert($wrap.data('failure'))
+        $wrap.find('input[type="submit"]').prop('disabled', false)
         $wrap.removeClass('folio-lead-form-submitting')
-        alert($wrap.data('failure'))


Fix error when zendesk not loaded

Fix error when zendesk not loaded

--- app/coffee/modules/common/userpilot.coffee
+++ app/coffee/modules/common/userpilot.coffee
@@ -67,10 +67,11 @@
                 userPilotCustomer
             )

-        if @win.zE and @.checkZendeskConditions(userData)
-            @.setZendeskWidgetStatus({enabled: true})
-        else
-            @.setZendeskWidgetStatus({enabled: false})
+        if @win.zE
+            if @.checkZendeskConditions(userData)
+                @.setZendeskWidgetStatus({enabled: true})
+            else
+                @.setZendeskWidgetStatus({enabled: false})

     prepareUserPilotCustomer: (data) ->
         if not data["id"]


- added correct steps and limits to a number of visualeditor settings (visible in settings -> view, at least in chrome)

--- src/app/modules/editors/visualEditor/visualEditorSettingsView.coffee
+++ src/app/modules/editors/visualEditor/visualEditorSettingsView.coffee
@@ -25,7 +25,7 @@
           gridSize     : 'Number'
           gridStep     : 'Number'
           gridColor    : 'Text'
-          gridOpacity  : 'Number'
+          gridOpacity  : {type:'Number', editorAttrs: { step: 0.1, min: 0, max: 1 } }
           gridText     : 'Checkbox'

           showStats    : 'Checkbox'


incorrect variable used in autocomplete

incorrect variable used in autocomplete

--- modules/autocomplete/main/index.coffee
+++ modules/autocomplete/main/index.coffee
@@ -131,7 +131,7 @@
     if not filteredData?
       message.text = @options.loadingMessage
     else if searchTerm.length < @options.minLength
-      message.text = @options.minLengthMessage.replace('$minLength', @options.minLength)
+      message.text = @options.pleaseEnterMinCharactersMessage.replace('$minLength', @options.minLength)
     else if (searchTerm.length > 0 or @options.showAll) and filteredData.length is 0
       if @options.trimTrailingSpaces and _.input.value().lastIndexOf(' ') is _.input.value().length - 1
         trimAndReload = true


kerplunk-server:app now handles styles

kerplunk-server:app now handles styles

--- src/components/layout.coffee
+++ src/components/layout.coffee
@@ -1,8 +1,5 @@
 _ = require 'lodash'
 React = require 'react'
-
-routeMatcher = require 'route-matcher'
-routeMatcher = routeMatcher.routeMatcher if routeMatcher.routeMatcher

 {DOM} = React

@@ -22,10 +19,6 @@

   render: ->
     url = @props.currentUrl #window.location.pathname
-    stylesheets = []
-    for path, routes of @props.globals.public.styles
-      if routeMatcher url, routes
-        stylesheets.push path
     wrapperClasses = [
       'wrapper'
       'relative'
@@ -45,9 +38,3 @@
             height: '100%'
         ,
           @props.getComponent(@props.contentComponent) _.extend {key: @props.currentUrl}, @props
-      _.map stylesheets, (stylesheet) ->
-        DOM.link
-          rel: 'stylesheet'
-          key: stylesheet
-          href: "/plugins/#{stylesheet}"
-        , ''


Harmonizing sync events for bucket datasets.

--- src/datasets/bucket-dataset.coffee
+++ src/datasets/bucket-dataset.coffee
@@ -9,6 +9,7 @@
         { @bucketSource } = options
         currentBucketSyncState = 0
         lastBucketSyncState = 0
+        @toFetch = 0

     useBuckets: (start, end) ->
         [ isLower, definite ] = @bucketCache.isCountLower(start, end, @histogramThreshold)
@@ -23,10 +24,9 @@
         return [ticks, resolution];

     isSyncing: () ->
-        return !(@lastSyncState is @currentSyncState) || !(@currentBucketSyncState is @lastBucketSyncState)
+        return @toFetch > 0

     doFetch: (start, end, params) ->
-        # TODO: if below threshold -> do the usual fetching
         { scales } = params
         [ ticks, resolution ] = @makeTicks(scales.x)

@@ -47,7 +47,7 @@
                 bucketsToFetch.push([tick, dt])

         if bucketsToFetch.length > 0
-            fetched = 0
+            @toFetch += bucketsToFetch.length
             @listeners.syncing()

             summaryCallback = after(bucketsToFetch.length, () =>
@@ -61,9 +61,7 @@
                 b = new Date(bucket.getTime() + (dt or resolution))
                 source(a, b, params, (count) =>
                     @bucketCache.setBucket(resolution, a, dt, count)
-                    fetched += 1
-                    # if bucketsToFetch.length == fetched and @currentBucketSyncState is @lastBucketSyncState
-                    # if bucketsToFetch.length == fetched and @currentBucketSyncState is @lastBucketSyncState
+                    @toFetch -= 1
                     @listeners.synced()
                     summaryCallback()
                 )


Setup the drawer before each open.

Setup the drawer before each open.

--- src/drawer/DrawerView.coffee
+++ src/drawer/DrawerView.coffee
@@ -351,7 +351,7 @@
     # Set the pane transition type.
     if @behavior is 'push'
       @transition = 'fade'
-      @getRenderedDimensions().then (d) =>
+      p = @getRenderedDimensions().then (d) =>
         @root.style.left = -d.width + 'px'
     else
       @transition = 'overlay'
@@ -365,6 +365,8 @@
     else
       @container.classList.remove DRAWER_CONTAINER_CLS
       @viewport.classList.remove DRAWER_VIEWPORT_CLS
+
+    return p

   ###*
@@ -390,7 +392,8 @@
   open: =>
     if @canTransitionIn()
       @_setElementClasses 'opening'
-      @transitionIn().then => @_setElementClasses 'open'
+      @_setupDrawer().then =>
+        @transitionIn().then => @_setElementClasses 'open'
     else
       Promise.rejected()


updated methods

updated methods

--- src/drm-offscreen-menu.coffee
+++ src/drm-offscreen-menu.coffee
@@ -3,6 +3,7 @@
 ###############################################################################
 "use strict"

+$ = jQuery
 class @DrmOffscreen
     constructor: (@menu = $('nav.drm-offscreen-menu'), @button = $('button.drm-menu-button'), @content = $('div.drm-offscreen-content'), @holder = $('div.drm-content-holder'), @state = 'hide') ->
         self = @
@@ -14,20 +15,20 @@
         self.button.on 'click', $.proxy self.toggleMenu, self

     toggleMenu: ->
-        menuPos = @menu.css 'left'
+        _menuPos = @menu.css 'left'
         menuWidth = @getDimensions()

-        if menuPos is '0px' then @hideMenu menuWidth else @showMenu menuWidth
+        if _menuPos is '0px' then @hideMenu menuWidth else @showMenu menuWidth

     showMenu: (menuWidth) ->
-        contentWidth = 100 - menuWidth
+        _contentWidth = 100 - menuWidth

         @menu.animate {
             'left': '0'
         }

         @content.animate {
-            'left': "#{menuWidth}%", 'width': "#{contentWidth}%"
+            'left': "#{menuWidth}%", 'width': "#{_contentWidth}%"
         }

     hideMenu: (menuWidth) ->
@@ -38,16 +39,16 @@
         @addScroll()

     getDimensions: ->
-        menuWidth = parseInt @menu.css('width'), 10
-        holderWidth = parseInt @holder.css('width'), 10
+        _menuWidth = parseInt @menu.css('width'), 10
+        _holderWidth = parseInt @holder.css('width'), 10

         # calculate menuWidth as a percentage of container
-        Math.ceil (menuWidth / holderWidth) * 100
+        Math.ceil (_menuWidth / _holderWidth) * 100

     addScroll: ->
-        menuHeight = parseInt @menu.find('ul').css('height'), 10
-        contentHeight = parseInt @content.css('height'), 10
+        _menuHeight = parseInt @menu.find('ul').css('height'), 10
+        _contentHeight = parseInt @content.css('height'), 10

-        if menuHeight > contentHeight then @menu.css {'overflow-y': 'scroll'}
+        if _menuHeight > _contentHeight then @menu.css {'overflow-y': 'scroll'}

 new DrmOffscreen()


Minor fixes to the kernel config

Minor fixes to the kernel config

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -96,7 +96,7 @@
         decor = (o) -> (a...) -> level o.explain; o.routine a...
         run = arguments.length is 0 and _.isArray @$configure
         return async.series _.map @$configure, decor if run
-        return yes if not @$configure and not arguments.length
+        return no if not @$configure and not arguments.length
         assert _.isFunction(routine), "invalid config routine"
         assert _.isString(explain), "no explanation given"
         assert (@$configure ?= []).push new Object
@@ -121,7 +121,7 @@
         assert not _.isEmpty @setupListeningServers()
         assert not _.isEmpty @setupSocketServers()
         assert not _.isEmpty @setupHotloadWatcher()
-        assert @constructor.configure()
+        @constructor.configure.apply @constructor
         logger.info message.red; this

     # The public constructor of the kernel instrances. Generally


Hooking into more client side events.

Hooking into more client side events.

--- src/client/client.coffee
+++ src/client/client.coffee
@@ -29,20 +29,18 @@
         document = @document
         propName = @API.nodes.propName
         server = @server
-        MouseEvents = ['click']#, 'mousedown', 'mouseup', 'mouseover',
-                       #'mouseout', 'mousemove']
-        HTMLEvents = []
+        MouseEvents = ['click', 'mousedown', 'mouseup', 'mouseover',
+                       'mouseout', 'mousemove']
         # Note: change is not a standard DOM event, but is supported by all
-        # the browseres.  Eventually, we should use jQuery for this client
-        # side code to normalize event handlers.
-        UIEvents = ['change']
-        #HTMLEvents = ['submit', 'select', 'change', 'reset', 'focus', 'blur',
+        # the browsers.
+        UIEvents = ['change', 'DOMFocusIn', 'DOMFocusOut', 'DOMActivate']
+        HTMLEvents = [] #'submit', 'select', 'change', 'reset', 'focus', 'blur',
         #              'resize', 'scroll']
-        #UIEvents = ['DOMFocusIn', 'DOMFocusOut', 'DOMActivate']
         [MouseEvents, HTMLEvents, UIEvents].forEach (group) ->
             group.forEach (eventType) ->
                 document.addEventListener eventType, (event) ->
-                    console.log "#{event.type} #{event.target[propName]}"
+                    if eventType == 'click'
+                        console.log "#{event.type} #{event.target[propName]}"
                     event.stopPropagation()
                     event.preventDefault()
                     ev = {}


Check if phantom process is starting, otherwise start it

--- src/coffee/routes.coffee
+++ src/coffee/routes.coffee
@@ -8,8 +8,9 @@
 module.exports = (app, logger) ->

   _ph = null
+  _phIsStarting = false
   port = app.get 'port'
-
+
   filePath = (name) -> path.join(__dirname, '../tmp', name)

   createPdf = (payload, cb) ->
@@ -40,18 +41,18 @@
       res.download filePath(fileName), fileName

   app.all '*', (req, res, next) ->
-    # req.connection.setTimeout(2 * 60 * 1000) # two minute timeout
-
     if _ph
       logger.debug 'Phantom process already running, skipping...'
       next()
-    else
+    else unless _phIsStarting
+      _phIsStarting = true
       phantomOpts =
         port: (port - 1)
       phantom.create "--web-security=no", "--ignore-ssl-errors=yes",
         phantomOpts
       , (ph) ->
         _ph = ph
+        _phIsStarting = false
         logger.info "New phantom process created on port #{phantomOpts.port}"
         next()


[#83458484] remove unnecessary test

[#83458484] remove unnecessary test

--- test/javascripts/integration/admin_journal_user_roles_test.js.coffee
+++ test/javascripts/integration/admin_journal_user_roles_test.js.coffee
@@ -1,106 +0,0 @@
-module 'Integration: Admin Journal User Roles, /admin/journals/:id',
-  teardown: -> ETahi.reset()
-  setup: ->
-    setupApp integration: true
-
-    ef = ETahi.Factory
-    journal = ef.createRecord('AdminJournal')
-    TahiTest.journalId = journal.id
-
-    adminRole = ef.createJournalRole journal,
-      name: "Admin"
-      kind: "admin"
-      can_administer_journal: true
-      can_view_assigned_manuscript_managers: false
-      can_view_all_manuscript_managers: true
-      can_view_flow_manager: true
-
-    editorRole = ef.createJournalRole journal,
-      name: "Editor"
-      kind: "editor"
-      can_administer_journal: false
-      can_view_assigned_manuscript_managers: false
-      can_view_all_manuscript_managers: false
-      can_view_flow_manager: false
-    TahiTest.editorRoleId = editorRole.id
-
-    reviewerRole = ef.createJournalRole journal,
-      name: "Reviewer"
-      kind: "reviewer"
-      can_administer_journal: false
-      can_view_assigned_manuscript_managers: false
-      can_view_all_manuscript_managers: false
-      can_view_flow_manager: false
-    TahiTest.reviewerRoleId = reviewerRole.id
-
-    adminJournalPayload = ef.createPayload('adminJournal')
-    adminJournalPayload.addRecords([journal, adminRole, editorRole, reviewerRole])
-
-    TahiTest.userRoleId = 99
-    TahiTest.adminUserId = 923
-    userRoleResponse =
-      user_role:
-        id: TahiTest.userRoleId
-        user_id: TahiTest.adminUserId
-        role_id: TahiTest.editorRoleId
-
-    adminJournalUserResponse =
-      user_roles: [
-        id: TahiTest.userRoleId
-        user_id: TahiTest.adminUserId
-        role_id: TahiTest.reviewerRoleId
-      ]
-      admin_journal_users: [
-        id: TahiTest.adminUserId
-        username: "fakeuser"
-        first_name: "Fake"
-        last_name: "User"
-        info: "Test String"
-        user_role_ids: [TahiTest.userRoleId]
-      ]
-
-    TahiTest.query = 'User'
-
-    server.respondWith 'GET', "/admin/journals/#{TahiTest.journalId}", [
-      200, "Content-Type": "application/json", JSON.stringify adminJournalPayload.toJSON()
-    ]
-
-    server.respondWith 'GET', "/admin/journal_users?journal_id=#{TahiTest.journalId}", [
-      200, "Content-Type": "application/json", JSON.stringify adminJournalUserResponse
-    ]
-
-    server.respondWith 'GET', "/admin/journal_users?query=#{TahiTest.query}", [
-      200, "Content-Type": "application/json", JSON.stringify adminJournalUserResponse
-    ]
-
-    server.respondWith 'GET', "/admin/journal_users?query=#{TahiTest.query}&journal_id=#{TahiTest.journalId}", [
-      200, "Content-Type": "application/json", JSON.stringify adminJournalUserResponse
-    ]
-
-    server.respondWith 'POST', "/user_roles", [
-      201, "Content-Type": "application/json", JSON.stringify userRoleResponse
-    ]
-
-    server.respondWith 'DELETE', "/user_roles/#{TahiTest.userRoleId}", [
-      204, "Content-Type": "application/json", JSON.stringify {}
-    ]
-
-test 'admin adds a role for user', ->
-  visit "/admin/journals/#{TahiTest.journalId}"
-  .then -> ok exists 'tr.user-row'
-  fillIn '.admin-user-search-input', TahiTest.query
-  click '.admin-user-search-button'
-  click '.assign-role-button'
-  .then -> $('.add-role-input').val('Edit').trigger('input')
-  # TODO FIX THIS
-  .then -> click '.tt-suggestion'
-  andThen -> assertText('.assigned-role', 'Editor')
-
-test 'admin removes a role for user', ->
-  visit "/admin/journals/#{TahiTest.journalId}"
-  fillIn '.admin-user-search-input', TahiTest.query
-  click '.admin-user-search-button'
-  .then ->
-    ok exists '.assigned-role.token'
-    click '.token-remove'
-  andThen -> ok !exists '.assigned-role.token'


handle (maybe) promises as args to component method

--- objectives/lib/_experiment_test.coffee
+++ objectives/lib/_experiment_test.coffee
@@ -143,7 +143,7 @@

     context 'the promisified functions on the exchange', ->

-        before (done, Mesh) ->
+        before (done, bluebird, Mesh) ->

             @timeout 2000

@@ -166,6 +166,26 @@
                                 a: arg1
                                 b: arg2
                                 c: arg3
+
+
+                        func3: (arg1, arg2, arg3, $happn, arg4, callback) ->
+
+                            # handle possible promises (or not) in the inbound args
+
+                            bluebird.Promise.all([arg1, arg2, arg3, arg4])
+
+                            .spread (arg1, arg2, arg3, arg4) ->
+
+                                callback null,
+
+                                    a: arg1
+                                    b: arg2
+                                    c: arg3
+                                    d: arg4
+
+                            .catch callback # send error back
+
+

                 components: test: {}

@@ -217,5 +237,28 @@

             .catch done

+        it.only 'can handle promises as arguments if the method can', (done, t) ->
+
+            t.func3(
+                t.func1 1
+                'Not a promise.'
+                t.func1 3
+                t.func1 4
+            )
+
+            .then (r) ->
+
+                r.should.eql
+
+                    a: value: 1
+                    b: 'Not a promise.'
+                    c: value: 3
+                    d: value: 4
+
+                done()
+
+            .catch done
+
+


better lastfm behaviour

better lastfm behaviour

--- scripts/lastfm_np.coffee
+++ scripts/lastfm_np.coffee
@@ -19,14 +19,17 @@
 getSong = (msg, user) ->
   apiKey = process.env.HUBOT_LASTFM_APIKEY
   msg.http('http://ws.audioscrobbler.com/2.0/?')
-    .query(method: 'user.getrecenttracks', user: user, api_key: apiKey, format: 'json')
+    .query(method: 'user.getrecenttracks', user: user, api_key: apiKey, format: 'json', limit: 1)
     .get() (err, res, body) ->
       results = JSON.parse(body)
       if results.error
         msg.send results.message
         return
       song = results.recenttracks.track[0]
-      msg.send "#{song.name} by #{song.artist['#text']}"
+      if song["@attr"].nowplaying
+        msg.send "#{song.name} by #{song.artist['#text']}"
+      else
+        msg.send "Сейчас #{user} ничего не слушает"

 module.exports = (robot) ->
   robot.respond /что слушает (.*)/i, (msg) ->


create settings.json during make

create settings.json during make

--- src/steroids/Project.coffee
+++ src/steroids/Project.coffee
@@ -90,9 +90,10 @@

       grunt = new Grunt()
       grunt.run {tasks: ["default"]}, ->
-        console.log "WRITING YEY"
-        configXmlGenerator = new ConfigXmlGenerator()
-        configXmlGenerator.writeConfigXml()
+        unless steroidsCli.options.argv.noSettingsJson == true
+          appSettings = new AppSettings()
+          steroidsCli.debug "Creating dist/__appgyver_settings.json..."
+          appSettings.createJSONFile()
         options.onSuccess.call() if options.onSuccess?

     ).fail (errorMessage)->
@@ -105,15 +106,11 @@
   make: (options = {}) => # with pre- and post-make hooks

     steroidsCli.debug "Making with hooks."
-    appSettings = new AppSettings

     @preMake
       onSuccess: =>
         @makeOnly
           onSuccess: =>
-            unless steroidsCli.options.argv.noSettingsJson == true
-              steroidsCli.debug "Creating dist/__appgyver_settings.json..."
-              appSettings.createJSONFile()
             @postMake options

   package: (options = {}) =>


Allow numbers in user names

Allow numbers in user names

--- scripts/nostalgia.coffee
+++ scripts/nostalgia.coffee
@@ -174,7 +174,7 @@
     newQuote = res.match[2]

     # Make sure the messages don't contain non-alphabetical characters
-    if /.*[^a-zA-Z_ ].*/.test(nostalgiaName)
+    if /.*[^a-zA-Z_0-9 ].*/.test(nostalgiaName)
         res.send "I can't remember names with fancy symbols and characters"
     else
         quotePath = "#{memoryDir}/#{nostalgiaName}"


engine#add

engine#add

--- src/engine_game_state.coffee
+++ src/engine_game_state.coffee
@@ -36,7 +36,7 @@
   return
     # Just pass through to the current state
     add: (className, entityData) ->
-      # Allow optional
+      # Allow optional add "Cla
       if entityData?
         entityData.class = className
       else


triggering remove events

triggering remove events

--- src/engine_save_state.coffee
+++ src/engine_save_state.coffee
@@ -3,17 +3,25 @@

   #TODO
   rewind: () ->
-
+
   saveState: () ->
     savedState = I.objects.map (object) ->
       $.extend({}, object.I)

   loadState: (newState) ->
     if newState ||= savedState
-      I.objects = newState.map (objectData) ->
-        GameObject.construct $.extend({}, objectData)
+      I.objects.invoke "trigger", "remove"
+      I.objects = []
+
+      newState.each (objectData) ->
+        self.add $.extend({}, objectData)

   reload: () ->
-    I.objects = I.objects.map (object) ->
-      GameObject.construct object.I
+    oldObjects = I.objects
+    I.objects = []

+    oldObjects.each (object) ->
+      object.trigger "remove"
+
+      self.add object.I
+


Load health from JSON

Load health from JSON

--- src/entities/creature.coffee
+++ src/entities/creature.coffee
@@ -207,7 +207,9 @@
 		creatureSpecies = require '../creature-species'
 		items = require '../items'
 		# because of how loadFromJSON() works in Entity,
-		# @personalities and @species will be assigned their JSON reps.
+		# fields with class instances will be assigned their JSON reps.
+
+		@health = new RangedValue @health

 		@species = creatureSpecies.fromJSON @species
 		@personalities =


* emit closed event after close event

* emit closed event after close event

--- src/eventable-options.coffee
+++ src/eventable-options.coffee
@@ -104,8 +104,8 @@
         @emit 'closing'
         inherited.call @, (err, result) =>
           return @dispatchError err, callback if err
+          @emit 'close', result
           @emit 'closed', result
-          @emit 'close', result
           callback null, result if callback
       ).apply(@self)
     getBufferAsync: (key, destBuffer, options, callback) ->


remove dependency

remove dependency

--- src/exception-handler.coffee
+++ src/exception-handler.coffee
@@ -7,7 +7,7 @@
 ############################################################################################################
 CND                       = require 'cnd'
 rpr                       = CND.rpr
-badge                     = 'cndxh'
+badge                     = 'nodexh'
 log                       = CND.get_logger 'plain',     badge
 debug                     = CND.get_logger 'debug',     badge
 info                      = CND.get_logger 'info',      badge
@@ -18,7 +18,6 @@
 whisper                   = CND.get_logger 'whisper',   badge
 echo                      = CND.echo.bind CND
 stackman                  = ( require 'stackman' )()
-# require                   'longjohn'
 FS                        = require 'fs'
 PATH                      = require 'path'
 { isa_text


.

Former-commit-id: c556b7057a45072ca20d1804ab29955917c6ac3f [formerly 40aeb4f26162841e6c98c1f7d47baa1e379b6734] [formerly 8c2002d6ef77f5defc54d36251b9c1d4ac3abc63 [formerly fc9065bb953b1de1c305b39036c044d58e3b817e]] [formerly b3b67fbab0159ca3b9d9c925f49af74798361d06 [formerly d555dab1906409461bd82ac2b6fc2a3add7d6104] [formerly f77c3f74a98f059bad66cc834f33fae29e462b8b [formerly f77c3f74a98f059bad66cc834f33fae29e462b8b [formerly 855bacd65345da1b7e6861fccfd4c3124c06891a]]]]
Former-commit-id: 2a6adc155d3c1ef26884a62eb79728c43be60baa [formerly 8efebee5c3dd1209349327a92ea7c656f98b9cb2] [formerly 869a55874b6e9c03bf75f60c37beb2f3fee804b2 [formerly dfed20fa73c89c31da78e044ace4951ca642e988]]
Former-commit-id: d5fa690e604083dec0abe389a15b73e366507296 [formerly d8576be487c9892683f62a151b456457932ab33c]
Former-commit-id: b14c38e3edc5678880742e9ca9dabfa3d0c31b02
Former-commit-id: 1e241b906238405478c5c4612b8672fec6835a5c

--- @client/browser_location.coffee
+++ @client/browser_location.coffee
@@ -161,7 +161,7 @@
   # location.search returns query parameters

   # fix url encoding of /
-  search = location.search?.replace(/\%2f/g, '/')
+  search = location.search?.replace(/\%2[fF]/g, '/')
   "#{location.pathname}#{search}#{location.hash}"

 relativeURLFromStatebus = ->


fix(edgehill-server): auth uses GET token param instead of basic auth

--- src/flux/edgehill-api.coffee
+++ src/flux/edgehill-api.coffee
@@ -47,8 +47,8 @@
   urlForConnecting: (provider, email_address = '') ->
     auth = @getCredentials()
     root = @APIRoot
-    root = root.replace('://', "://#{auth.username}:#{auth.password}@") if auth
-    "#{root}/connect/#{provider}?login_hint=#{email_address}"
+    token = auth?.username
+    "#{root}/connect/#{provider}?login_hint=#{email_address}&token=#{token}"

   getCredentials: ->
     atom.config.get('edgehill.credentials')


Add method to update user references

Add method to update user references

--- services/web/app/coffee/Features/Subscription/SubscriptionGroupHandler.coffee
+++ services/web/app/coffee/Features/Subscription/SubscriptionGroupHandler.coffee
@@ -39,12 +39,27 @@

 	removeUserFromGroup: (adminUser_id, userToRemove_id, callback)->
 		SubscriptionUpdater.removeUserFromGroup adminUser_id, userToRemove_id, callback
-
+
 	removeEmailInviteFromGroup: (adminUser_id, email, callback) ->
 		SubscriptionUpdater.removeEmailInviteFromGroup adminUser_id, email, callback

+
+	replaceUserReferencesInGroups: (oldId, newId, callback) ->
+		Subscription.update {admin_id: userStubId}, {admin_id: slUserId}, (error) ->
+			callback(error) if error?
+
+			# Mongo won't let us pull and addToSet in the same query, so do it in
+			# two. Note we need to add first, since the query is based on the old user.
+			query = {member_ids: userStubId}
+			addNewUserUpdate = $addToSet: {member_ids: slUserId}
+			removeOldUserUpdate = $pull: {member_ids: userStubId}
+
+			Subscription.update query, addNewUserUpdate, { multi: true }, (error) ->
+				return callback(error) if error?
+				Subscription.update query, removeOldUserUpdate, { multi: true }, callback
+
 	getPopulatedListOfMembers: (adminUser_id, callback)->
-		SubscriptionLocator.getUsersSubscription adminUser_id, (err, subscription)->
+		SubscriptionLocator.getUsersSubscription adminUser_id, (err, subscription)->
 			users = []
 			for email in subscription.invited_emails or []
 				users.push buildEmailInviteViewModel(email)
@@ -111,7 +126,7 @@
 			async.series jobs, callback

 buildUserViewModel = (user)->
-	u =
+	u =
 		email: user.email
 		first_name: user.first_name
 		last_name: user.last_name
@@ -123,4 +138,4 @@
 	return {
 		email: email
 		holdingAccount: true
-	}+	}


Fix error 400 during FUP

Fix error 400 during FUP

--- app/src/fup/firmware_update_request.coffee
+++ app/src/fup/firmware_update_request.coffee
@@ -236,6 +236,7 @@
                 @_dongle.isBetaCertified (__, error) =>
                   @_setCurrentState(if error? and ledger.fup.versions.Nano.CurrentVersion.Overwrite is false then States.InitializingOs else States.ReloadingBootloaderFromOs)
                   @_handleCurrentState()
+                return
             when ledger.fup.FirmwareUpdater.FirmwareAvailabilityResult.Update, ledger.fup.FirmwareUpdater.FirmwareAvailabilityResult.Higher
               index = 0
               while index < ledger.fup.updates.OS_INIT.length and !ledger.fup.utils.compareVersions(@_dongleVersion, ledger.fup.updates.OS_INIT[index][0]).eq()
@@ -250,6 +251,7 @@
                 @_setCurrentState(States.ReloadingBootloaderFromOs)
                 @_handleCurrentState()
             else return @_failure(Errors.HigherVersion)
+          return

   _processErasing: ->
     @_waitForUserApproval('erasure')


Fix optimizer sourcemap handling #623

Fix optimizer sourcemap handling #623

--- src/fs_utils/generate.coffee
+++ src/fs_utils/generate.coffee
@@ -71,7 +71,7 @@
   root.toStringWithSourceMap file: path

 mapOptimizerChain = (optimizer) -> (params, next) ->
-  {data, code, map, path} = params
+  {data, code, map, path, sourceFiles} = params
   debug "Optimizing '#{path}' with '#{optimizer.constructor.name}'"

   optimizerArgs = if optimizer.optimize.length is 2
@@ -89,22 +89,18 @@
     else
       optimizedCode = optimized
     if optimizedMap?
-      json = optimizedMap.toJSON()
       newMap = SourceMapGenerator.fromSourceMap new SourceMapConsumer optimizedMap
-      newMap._sources.add path
-      newMap._mappings.forEach (mapping) ->
-        mapping.source = path
       newMap._sourcesContents ?= {}
-      newMap._sourcesContents["$#{path}"] = ''  # data
-      newMap.applySourceMap smConsumer
+      sourceFiles.forEach ({path, source}) ->
+        newMap._sourcesContents["$#{path}"] = source
     else
       newMap = map
-    next error, {data: optimizedCode, code: optimizedCode, map: newMap, path}
+    next error, {data: optimizedCode, code: optimizedCode, map: newMap, path, sourceFiles}

   optimizer.optimize.apply optimizer, optimizerArgs

-optimize = (data, map, path, optimizers, callback) ->
-  initial = {data, code: data, map, path}
+optimize = (data, map, path, optimizers, sourceFiles, callback) ->
+  initial = {data, code: data, map, path, sourceFiles}
   first = (next) -> next null, initial
   waterfall [first].concat(optimizers.map mapOptimizerChain), callback

@@ -122,7 +118,7 @@
   withMaps = (map and config.sourceMaps)
   mapPath = "#{path}.map"

-  optimize code, map, path, optimizers, (error, data) ->
+  optimize code, map, path, optimizers, sourceFiles, (error, data) ->
     return callback error if error?

     if withMaps


GameObject.Effect

GameObject.Effect

--- src/game_object_effect.coffee
+++ src/game_object_effect.coffee
@@ -1,3 +1,13 @@
+###*
+The Fadeable module provides a method to fade a sprite to transparent.
+You may also provide a callback function that is executed when the sprite has finished fading out.
+
+@name Ef
+@module
+@constructor
+@param {Object} I Instance variables
+@param {Core} self Reference to including object
+###
 GameObject.Effect = (I={}, self) ->

   ###*


GameObject.Effect

GameObject.Effect

--- src/game_object_effect.coffee
+++ src/game_object_effect.coffee
@@ -22,7 +22,7 @@
       # => true

   @name fadeOut
-  @methodOf Fadeable#
+  @methodOf GameObject#
   @param {Number} [duration=30] How long the effect lasts
   @param {Function} [callback=null] The function to execute when the sprite has finished fading.
   ###


wrong context, fixed

wrong context, fixed

--- src/zombie/resources.coffee
+++ src/zombie/resources.coffee
@@ -722,6 +722,9 @@
         response.body = bdy
         callStruct.response = response

+        # Add to HAR
+        @resources.browser.har.entries.push(entry)
+
         callStruct.callbacks.forEach( (cbak)=>
           makeTheCall(cbak, response)
         )
@@ -741,8 +744,6 @@
       if protocol == 'h2'
         resp.headers = HTTP2.convertHeadersFromH2(response.headers)

-      # Add to HAR
-      @resources.browser.har.entries.push(entry)
       setImmediate(cbak, null, resp)

     # TODO: Handle push!


fix user panel on clear local storage

fix user panel on clear local storage

--- BackofficeBundle/Resources/public/coffee/table/TableviewAction.coffee
+++ BackofficeBundle/Resources/public/coffee/table/TableviewAction.coffee
@@ -48,12 +48,10 @@
     options = @options
     viewContext = @
     links = options.element.get('links')
-    panelKeys = []
     for key in Object.keys(links)
       if /^_self_panel_/.test(key)
-        panelKeys.push(key)
-    if panelKeys.length > 0
-      appConfigurationView.setConfiguration(viewContext.options.entityType, 'edit', FullPagePanelView)
+        appConfigurationView.setConfiguration(viewContext.options.entityType, 'editEntity', FullPagePanelView)
+        break
     $.ajax
       url: links._self_form
       method: "GET"


Removed name from hound.annoying, since it only is used in DMs

--- src/helpers/constants.coffee
+++ src/helpers/constants.coffee
@@ -123,8 +123,8 @@
     userhelp:             "Use `@ibizan user [slack name]` to view a user's slack info!"
   hound:
     annoying:             "\n\nIf you think I'm being an annoying dog, you can adjust your
-                           hounding settings with `@ibizan hound`, or your active hours
-                           with `@ibizan active`! Use `@ibizan status` to see when I think
+                           hounding settings with `hound`, or your active hours
+                           with `active`! Use `status` to see when I think
                            you are active."
     houndhelp:            "Change hounding settings using `hound (scope) (command)`!
                            Try something like `hound (self/org) (on/off/pause/reset/status/X hours)`"


fix: iframe width bug on mobile safari

fix: iframe width bug on mobile safari

--- src/javascripts/embed.coffee
+++ src/javascripts/embed.coffee
@@ -68,7 +68,8 @@
     @iframe.style.border = '0'
     @iframe.style.overflowY = 'hidden'
     @iframe.style.transition = 'height 100ms linear'
-    @iframe.width = '100%'
+    @iframe.style.minWidth = '100%'
+    @iframe.width = '1px'
     @iframe.title = 'Podcast'
     @iframe.setAttribute('aria-label', 'Podcast')
     @iframe


:lipstick: Use single quotes for consistency

--- src/jquery-extensions.coffee
+++ src/jquery-extensions.coffee
@@ -129,7 +129,7 @@
     options  = selector
     selector = null

-  @document(eventName, _.humanizeEventName(eventName, options?["doc"]))
+  @document(eventName, _.humanizeEventName(eventName, options?['doc']))
   @on(eventName, selector, options?['data'], handler)

 $.fn.iconSize = (size) ->


Fixup 5476c48, remove debug statement. :sweat:

--- src/js/jquery.hlf.tip.coffee
+++ src/js/jquery.hlf.tip.coffee
@@ -337,7 +337,6 @@
       $stem = @selectByClass 'stem'
       wrapped = @_wrapStealthRender =>
         size = Math.abs parseInt($stem.css('margin').replace(/0px/g, ''), 10)
-        debugger if size is 0
         @$tip.data key, size
         size
       return wrapped()


added %O delimiter

added %O delimiter

--- src/lib/mist-resolver.coffee
+++ src/lib/mist-resolver.coffee
@@ -194,7 +194,7 @@
 ###
 # Make sure to always include `$1` in the replacement
 ###
-MistResolver.delimiterPattern = /((?!\%).)?%([fbBo])/g
+MistResolver.delimiterPattern = /((?!\%).)?%([fbBoO])/g

 ###
 # Returns whether or not a string has filename delimiters present
@@ -235,6 +235,7 @@
   else
     dict['f'] = pathname
     dict['o'] = '%o'
+    dict['O'] = '%O'
     dict['b'] = path.basename pathname
     dict['B'] = dict['b'].replace /\..+$/, ''
   return dict
@@ -254,6 +255,7 @@
   for input in inputs.map MistResolver.generateDict
     for k, v of input
       if k is 'o' then v = outputs
+      if k is 'O' then v = outputs.map path.dirname
       k = "D_#{k}"
       result[k] = [] if k not of result
       result[k] = result[k].concat v


fix(send): Don't queue an upload task if there are no files

--- src/flux/stores/draft-store.coffee
+++ src/flux/stores/draft-store.coffee
@@ -314,7 +314,8 @@
   _onEnsureDraftSynced: (draftClientId) =>
     @sessionForClientId(draftClientId).then (session) =>
       @_prepareForSyncback(session).then =>
-        Actions.queueTask(new SyncbackDraftFilesTask(draftClientId))
+        if session.draft().files.length or session.draft().uploads.length
+          Actions.queueTask(new SyncbackDraftFilesTask(draftClientId))
         Actions.queueTask(new SyncbackDraftTask(draftClientId))

   _onSendDraft: (draftClientId) =>
@@ -324,7 +325,8 @@
       @_prepareForSyncback(session).then =>
         if NylasEnv.config.get("core.sending.sounds")
           SoundRegistry.playSound('hit-send')
-        Actions.queueTask(new SyncbackDraftFilesTask(draftClientId))
+        if session.draft().files.length or session.draft().uploads.length
+          Actions.queueTask(new SyncbackDraftFilesTask(draftClientId))
         Actions.queueTask(new SendDraftTask(draftClientId))
         @_doneWithSession(session)


support multiple event types in expect

support multiple event types in expect

--- benchmarks/clients/benchmark_config.coffee
+++ benchmarks/clients/benchmark_config.coffee
@@ -1,4 +1,5 @@
 fs = require('fs')
+util = require('util')

 lodash = require('lodash')
 debug = require('debug')
@@ -124,8 +125,13 @@
     getExpectingEventName : ()->
         if @expectIndex >= @descriptor.expect.length
             return null
-        return @descriptor.expect[@expectIndex].event
-
+        expectedEvent = @descriptor.expect[@expectIndex].event
+        if typeof expectedEvent is 'string'
+            return expectedEvent
+        if util.isArray(expectedEvent)
+            return expectedEvent.join(' or ')
+        return null
+
     # 1 means waiting, 2 means fully matched
     # we are not reject anything, if the expected event
     # does not showup, we will detect a timeout for waiting
@@ -133,7 +139,7 @@
         if @expectIndex >= @descriptor.expect.length
             return 2
         currentExpect = @descriptor.expect[@expectIndex]
-        if eventName isnt currentExpect.event
+        if not @_matchEventName(eventName,currentExpect)
             return 1
         if currentExpect.containsText
             if not @_matchText(args, currentExpect.containsText)
@@ -145,6 +151,13 @@
         if @expectIndex is @descriptor.expect.length
             return 2
         return 1
+
+    _matchEventName : (eventName, expect) ->
+        expectedEvent = expect.event
+        return true if eventName is expectedEvent
+        if util.isArray(expectedEvent)
+            return expectedEvent.indexOf(eventName) >= 0
+        return false

     _matchText : (args, matchRules)->
         str = JSON.stringify(args)


Improved title update.

Improved title update.

--- app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee
+++ app/assets/javascripts/app/controllers/agent_ticket_zoom.js.coffee
@@ -337,6 +337,8 @@
     title = $this.html()
     title = ('' + title)
       .replace(/<.+?>/g, '')
+    title = ('' + title)
+      .replace(/ /g, ' ')
     if title is '-'
       title = ''
     @ticket.title = title


#172963368 implemented result to form translation layer for all supported answer types

--- app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
+++ app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
@@ -445,6 +445,7 @@
   updateCalculation: (rule) ->
     parameters = {}
     $target = $('[data-question-id="' + rule.question_id + '"]').find('.form-control')
+    targetType = $('[data-question-id="' + rule.question_id + '"]').data('element-type')

     $.each rule.conditions, (index, condition) ->
       $question = $('[data-question-id="' + condition.question_id + '"]')
@@ -464,17 +465,61 @@
         value = self.getNativeValue($conditionElement, elementType)
         parameters[columnName] = value

-    interpreter = new Interpreter(rule.script, (interpreter, globalObject) ->
-      outputWrapper = (result) -> self.setCalculationResult($target, result)
+    self.interpreter = new Interpreter(rule.script, (interpreter, globalObject) ->
+      outputWrapper = (result) -> self.setCalculationResult($target, result, targetType)
       interpreter.setProperty(globalObject, 'setResult', interpreter.createNativeFunction(outputWrapper))
-      $.each parameters, (key, value) ->
-        interpreter.setProperty(globalObject, '$' + key, interpreter.nativeToPseudo(value))
+      $.each parameters, (key, value) -> interpreter.setProperty(globalObject, '$' + key, interpreter.nativeToPseudo(value))
     )

-    interpreter.run()
-
-  setCalculationResult: ($target, result) ->
-    $target.val(result)
+    self.interpreter.run()
+
+  setCalculationResult: ($target, pseudoResult, elementType) ->
+    result = self.interpreter.pseudoToNative(pseudoResult)
+
+    if elementType == 'checkbox' && typeof result == 'boolean'
+      $target.prop("checked", result).trigger('change')
+
+    else if (elementType == 'number' || elementType == 'counter') && typeof result == 'number'
+      $target.val(result).trigger('change')
+
+    else if (elementType == 'text' || elementType ==  'textarea' || elementType == 'time') && typeof result == 'string'
+      $target.val(result).trigger('change')
+
+    else if elementType == 'date' && typeof result == 'number'
+      $target.datepicker("setDate", new Date(result))
+
+    else if elementType == 'checkboxes' && Array.isArray(result)
+      $.each $target, (index, checkbox) ->
+        $(checkbox).prop("checked", result.indexOf($(checkbox).attr('data-label-value')) != -1).trigger('change')
+
+    else if elementType == 'multiselect' && Array.isArray(result)
+      if $target.hasClass('chosen-multiselect')
+        $target.find('option').prop('selected', false)
+        $.each result, (index, optionText) -> $target.find('option:contains(' + optionText + ')').prop('selected', true);
+        $target.trigger("chosen:updated")
+
+      else if $target.hasClass('selectized')
+        $target[0].selectize.clear(true)
+        $.each $target[0].selectize.options, (index, option) ->
+          if result.indexOf(option.text) != -1
+            $target[0].selectize.addItem(option.value, false)
+
+    else if elementType == 'select' && typeof result == 'string'
+      if $target.hasClass('chosen-select')
+        $target.find('option').prop('selected', false)
+        $target.find('option:contains(' + result + ')').prop('selected', true);
+        $target.trigger("chosen:updated")
+
+      else if $target.hasClass('selectized')
+        $target[0].selectize.clear(true)
+        $.each $target[0].selectize.options, (index, option) ->
+          if option.text == result
+            $target[0].selectize.addItem(option.value, false)
+            return
+
+    else if elementType == 'radio' && typeof result == 'string'
+      $.each $target, (index, radio) ->
+        $(radio).prop("checked", $(radio).attr('data-label-value') == result).trigger('change')

   getNativeValue: ($input, elementType) ->
     stringValue = self.getValue($input)


fixed date calc fields

fixed date calc fields

--- app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
+++ app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
@@ -504,7 +504,7 @@
     else if (elementType == 'text' || elementType ==  'textarea' || elementType == 'time') && typeof result == 'string'
       $target.val(result).trigger('change')

-    else if elementType == 'date' && typeof result == 'number'
+    else if elementType == 'date' && typeof result == 'string'
       $target.datepicker("setDate", new Date(result))
       $target.trigger('change')


make copy, hide, stamp convenient module-level verbs


Help text.

Help text.

--- src/quote.coffee
+++ src/quote.coffee
@@ -13,6 +13,8 @@
 #   hubot howmany <query> - Return the number of quotes that contain each word of <query>.
 #   hubot reload quotes - Reload the quote file.
 #   hubot quotestats - Show who's been quoted the most!
+#   hubot verbatim quote: [...] - Enter a quote into the quote file exactly as given.
+#   hubot slackapp quote: [...] - Parse a quote from the Slack app's paste format.
 #
 # Author:
 #   smashwilson


deprecate steroids.layers.array

deprecate steroids.layers.array

--- src/models/LayerCollection.coffee
+++ src/models/LayerCollection.coffee
@@ -1,14 +1,11 @@
 class LayerCollection
   constructor: ->
-    @array = []

-  pop: (options={}, callbacks={})->
-    defaultOnSuccess = ()=>
-      @array.pop()
+  pop: (options={}, callbacks={}) ->

     steroids.nativeBridge.nativeCall
       method: "popLayer"
-      successCallbacks: [defaultOnSuccess, callbacks.onSuccess]
+      successCallbacks: [callbacks.onSuccess]
       failureCallbacks: [callbacks.onFailure]

   popAll: (options={}, callbacks={}) ->
@@ -19,10 +16,7 @@
       failureCallbacks: [callbacks.onFailure]

-  push: (options={}, callbacks={})->
-    defaultOnSuccess = ()=>
-      @array.push view
-
+  push: (options={}, callbacks={}) ->
     view = if options.constructor.name == "WebView"
       options
     else
@@ -55,15 +49,11 @@
     steroids.nativeBridge.nativeCall
       method: "openLayer"
       parameters: parameters
-      successCallbacks: [defaultOnSuccess, callbacks.onSuccess]
+      successCallbacks: [callbacks.onSuccess]
       failureCallbacks: [callbacks.onFailure]

-  replace: (options={}, callbacks={})->
+  replace: (options={}, callbacks={}) ->
     steroids.debug "steroids.layers.replace called"
-
-    defaultOnSuccess = ()=>
-      steroids.debug "steroids.layers.replace defaultOnSuccess"
-      @array = [view]

     view = if options.constructor.name == "WebView"
       steroids.debug "steroids.layers.replace using view shorthand"
@@ -84,5 +74,5 @@
     steroids.nativeBridge.nativeCall
       method: "replaceLayers"
       parameters: parameters
-      successCallbacks: [defaultOnSuccess, callbacks.onSuccess]
+      successCallbacks: [callbacks.onSuccess]
       failureCallbacks: [callbacks.onFailure]


:art: buses -> bus

:art: buses -> bus

--- src/notational/setup-panel.coffee
+++ src/notational/setup-panel.coffee
@@ -11,7 +11,7 @@

 # Encapsulates the general logic
 module.exports = ({matchedItemsProp, searchBus, columnsProp, bodyHeightStream, rowHeightStream}) ->
-  buses = {
+  bus = {
     bodyHeight : new Bacon.Bus()
     keydown    : new Bacon.Bus()
     scrollTop  : new Bacon.Bus()
@@ -21,24 +21,24 @@
   }
   rowHeightProp = rowHeightStream.toProperty()

-  bodyHeightProp = bodyHeightStream.merge(buses.bodyHeight)
+  bodyHeightProp = bodyHeightStream.merge(bus.bodyHeight)
     .skipDuplicates()
     .filter (height) -> height > 0
     .toProperty()

-  resetStream        = buses.keydown.filter (ev) -> ev.keyCode is 27 #esc
-  openSelectedStream = buses.keydown.filter (ev) -> ev.keyCode is 13 #enter
-  moveSelectedStream = buses.keydown.filter((ev) -> ev.keyCode is 38).doAction((ev) -> ev.preventDefault()).map(-1) #up
-                .merge(buses.keydown.filter((ev) -> ev.keyCode is 40).doAction((ev) -> ev.preventDefault()).map(1)) #down
+  resetStream        = bus.keydown.filter (ev) -> ev.keyCode is 27 #esc
+  openSelectedStream = bus.keydown.filter (ev) -> ev.keyCode is 13 #enter
+  moveSelectedStream = bus.keydown.filter((ev) -> ev.keyCode is 38).doAction((ev) -> ev.preventDefault()).map(-1) #up
+                .merge(bus.keydown.filter((ev) -> ev.keyCode is 40).doAction((ev) -> ev.preventDefault()).map(1)) #down

   selectedItemProp = Bacon.update(undefined,
-    [buses.search], -> undefined
-    [buses.selectItem], (..., newItem) -> newItem
+    [bus.search], -> undefined
+    [bus.selectItem], (..., newItem) -> newItem
     [moveSelectedStream, matchedItemsProp], selectItemByRelativeOffset
   ).skipDuplicates()

   scrollTopProp = Bacon.update 0,
-    [buses.scrollTop], (..., scrollTop) -> scrollTop
+    [bus.scrollTop], (..., scrollTop) -> scrollTop
     [selectedItemProp.changes(), matchedItemsProp, rowHeightProp, bodyHeightProp], adjustScrollTopForSelectedItem

   visibleBeginProp = Bacon.combineWith (scrollTop, rowHeight) ->
@@ -61,7 +61,7 @@
           items.slice(begin, end)
         , matchedItemsProp, visibleBeginProp, visibleEndProp
       }).map (data) ->
-        content(data, buses.selectItem)
+        content(data, bus.selectItem)
     topOffset: Bacon.combineWith (scrollTop, rowHeight) ->
         -(scrollTop % rowHeight)
       , scrollTopProp, rowHeightProp
@@ -69,19 +69,19 @@
         items.length * rowHeight - scrollTop - bodyHeight
       , matchedItemsProp, rowHeightProp, scrollTopProp, bodyHeightProp
   }).map (data) ->
-    scrollableContent(data, buses.scrollTop)
+    scrollableContent(data, bus.scrollTop)

   resizeHandleProp = bodyHeightProp.map (bodyHeight) ->
-    resizeHandle(bodyHeight, buses.bodyHeight)
+    resizeHandle(bodyHeight, bus.bodyHeight)

   headerProp = columnsProp.map (columns) ->
     header(columns)

   vdomTreeProp = Bacon.combineWith (contentHeader, scrollableContent, resizeHandle) ->
     h 'div.atom-notational-panel', {
-      onclick: -> buses.focus.push undefined
+      onclick: -> bus.focus.push undefined
     }, [
-      search(buses.search, buses.keydown)
+      search(bus.search, bus.keydown)
       contentHeader
       scrollableContent
       resizeHandle
@@ -94,12 +94,12 @@
       # Scroll item into the view if outside the visible border and was triggered by selectItem change
       if selectedRow = el.querySelector('.is-selected')
         selectedRow.scrollIntoViewIfNeeded(false) # centerIfNeeded=false => croll minimal possible to avoid jumps
-    [buses.focus, elementProp], (..., el) ->
+    [bus.focus, elementProp], (..., el) ->
       el.querySelector('.search').focus()
     [resetStream, elementProp], (..., el) ->
       el.querySelector('.search').value = ''
-      buses.search.push('')
-    [buses.search, elementProp], (..., el) ->
+      bus.search.push('')
+    [bus.search, elementProp], (..., el) ->
       el.querySelector('.tbody').scrollTop = 0 #return to top
   )


clearing search whenever modal is closed/cancel is pressed

--- src/scripts/modules/media/tabs/contents/popovers/add/modals/add-page.coffee
+++ src/scripts/modules/media/tabs/contents/popovers/add/modals/add-page.coffee
@@ -86,7 +86,12 @@
     cancelSearch: () ->
       if @results?.get('promise')
         @results.get('promise').abort()
-        @regions.results.empty()
+
+      @clearSearch()
+
+    clearSearch: () ->
+      @regions.results.empty()
+      @$el.find('.page-title').val('')

     updateUrl: () ->
       # Update the url bar path


Small test change

Small test change

--- test/test.coffee
+++ test/test.coffee
@@ -23,7 +23,7 @@
 assertEquals '<>"&', html4Entities.encode('<>"&')
 assertEquals '<>"&©', html4Entities.encode('<>"&©')
 assertEquals '<>"&©∆', html4Entities.encodeNonUTF('<>"&©∆')
-assertEquals '<>"&©®', html4Entities.encodeNonASCII('<>"&©®')
+assertEquals '<>"&©®∆', html4Entities.encodeNonASCII('<>"&©®∆')

 assertEquals '<>"&', html4Entities.decode('<>"&')
 assertEquals '<>"&∾̳©', html4Entities.decode('<>"&∾̳©')
@@ -34,7 +34,7 @@
 assertEquals '<>"&', html5Entities.encode('<>"&')
 assertEquals '<>"&©', html5Entities.encode('<>"&©')
 assertEquals '<>"&©∆', html5Entities.encodeNonUTF('<>"&©∆')
-assertEquals '<>"&©®', html5Entities.encodeNonASCII('<>"&©®')
+assertEquals '<>"&©®∆', html5Entities.encodeNonASCII('<>"&©®∆')

 assertEquals '≪>"&', html5Entities.decode('≪>"&')
 assertEquals '<>"&', html5Entities.decode('<>"&')


cute name

cute name

--- test_meta.coffee
+++ test_meta.coffee
@@ -4,7 +4,7 @@

 now = () -> new Date().toISOString()

-and_log_it = (err, updated_asset) ->
+and_log_callback = (err, updated_asset) ->
     if err?
         console.log "Error!"
     else
@@ -20,7 +20,7 @@
         transaction.iter (story) ->
             story.Name = 'Something Else'
             issue = Story.create_in_context('Issue', {Name: 'New Issue'})
-        transaction.commit and_log_it
+        transaction.commit and_log_callback

 v1.with_poller (poller) ->
@@ -29,6 +29,6 @@
         (story) ->
             console.log story
             story.Touched = now()
-    poller.commit and_log_it
+    poller.commit and_log_callback


Render after handling input, if requested

--- src/trix/controllers/editor_controller.coffee
+++ src/trix/controllers/editor_controller.coffee
@@ -147,9 +147,16 @@

   inputControllerWillHandleInput: ->
     @handlingInput = true
+    @requestedRender = false
+
+  inputControllerDidRequestRender: ->
+    @requestedRender = true

   inputControllerDidHandleInput: ->
     @handlingInput = false
+    if @requestedRender
+      @requestedRender = false
+      @render()

   inputControllerWillPerformTyping: ->
     @recordTypingUndoEntry()
@@ -187,9 +194,6 @@
   inputControllerDidCancelDrag: ->
     @selectionManager.setLocationRange(@locationRangeBeforeDrag)
     delete @locationRangeBeforeDrag
-
-  inputControllerDidRequestRender: ->
-    @render()

   # Selection manager delegate


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_levels.coffee
+++ src/engine_levels.coffee
@@ -65,7 +65,7 @@
   engine.realodLevel
   </pre></code>

-  @name goToLevel
+  @name reloadLevel
   @methodOf Engine#
   ###
   reloadLevel: ->


Dont crash all the tests if stripe is 403

--- test/server/functional/prepaid.spec.coffee
+++ test/server/functional/prepaid.spec.coffee
@@ -115,6 +115,7 @@
               redeemer = { userID: otherUser.id }
               request.post {uri: url, json: redeemer }, (err, res, body) ->
                 expect(res.statusCode).toBe(200)
+                return done() unless res.statusCode is 200
                 expect(body.redeemers.length).toBe(0)
                 done()


bug fix

bug fix

--- src/plugins/faction/weather.coffee
+++ src/plugins/faction/weather.coffee
@@ -2,7 +2,8 @@
 request = require 'request'
 async = require 'async'
 cheerio = require 'cheerio'
-cache = require 'lru-cache'
+lru = require 'lru-cache'
+cache = lru
     max:    500
     maxAge: 30 * 60 * 1000


Sidebar: Fix missing participant representation

--- client/app/lib/activity/sidebar/sidebarmessageitemtext.coffee
+++ client/app/lib/activity/sidebar/sidebarmessageitemtext.coffee
@@ -52,7 +52,7 @@

   createSingle: (origin) ->

-    origin = { constructorName : 'JAccount', id : origin._id }
+    origin.id = origin._id  if origin
     @text  = new ProfileTextView {origin}


should give them a link to follow too

should give them a link to follow too

--- src/hubot/scripts/maps.coffee
+++ src/hubot/scripts/maps.coffee
@@ -1,16 +1,24 @@
 # Interacts with the Google Maps API.
 #
 # map me <query> - Returns a map view of the area returned by `query`.
+
 module.exports = (robot) ->
+
   robot.respond /(?:(satellite|terrain|hybrid)[- ])?map me (.+)/i, (msg) ->
     mapType  = msg.match[1] || "roadmap"
     location = msg.match[2]
-    url      = "http://maps.google.com/maps/api/staticmap?markers=" +
+    mapUrl      = "http://maps.google.com/maps/api/staticmap?markers=" +
                escape(location) +
                "&size=400x400&maptype=" +
                mapType +
                "&sensor=false" +
                "&format=png" # So campfire knows it's an image
+    url         = "http://maps.google.com/maps?q=" +
+                  escape(location) +
+                  "&hl=en&sll=37.0625,-95.677068&sspn=73.579623,100.371094&vpsrc=0&hnear=" +
+                  escape(location) +
+                  "&t=m&z=11"

+    msg.send mapUrl
     msg.send url


Removing v1 script

Removing v1 script

--- index.bak.coffee
+++ index.bak.coffee
@@ -1,119 +0,0 @@
-###
-Determines if the view is in visible in the browser window.
-
-Example usage:
-	Just require the mixin from your component.
-	Use the optional offset props like:
-
-	large-copy(
-		:in-viewport-offset-top="300"
-		:in-viewport-offset-bottom="0.5"
-
-		# Only add the `in-viewport` class once per page load
-		:in-viewport-once="false"
-	)
-
-###
-
-# Deps
-win = require 'window-event-mediator'
-check = require './check'
-
-# Mixin definiton
-module.exports =
-
-	# Settings
-	props:
-
-		# Add listeners and check if in viewport immediately
-		inViewportActive:
-			type: 'Boolean'
-			default: true
-
-		# Whether to only update in-viewport class once
-		inViewportOnce:
-			type: 'Boolean'
-			default: true
-
-		# Whether to only update in-viewport class once
-		inViewportClass:
-			type: 'string'
-			default: 'in-viewport'
-
-		# Whether to only update in-viewport class once
-		inViewportEntrelyClass:
-			type: 'string'
-			default: 'in-viewport-entirely'
-
-		# A positive offset triggers "late" when scrolling down
-		inViewportOffsetTop:
-			type: Number
-			default: 0
-
-		# A negative offset triggers "early" when scrolling down
-		inViewportOffsetBottom:
-			type: Number
-			default: 0
-
-	# Boolean stores whether component is in viewport
-	data: ->
-		inViewport: false
-		inViewportEntirely: false
-
-	# Add handlers when vm is added to dom unless init is false
-	ready: -> @addInViewportHandlers() if @inViewportActive
-
-	# If comonent is destroyed, clean up listeners
-	destroyed: -> @removeInViewportHandlers()
-
-	# Vars to watch
-	watch:
-
-		# Adds handlers if they weren't added at runtime
-		inViewportActive: (ready) ->
-			@addInViewportHandlers() if ready
-
-		# Adds the `in-viewport` class when the component is in bounds/
-		inViewport: (visible) ->
-			@removeInViewportHandlers() if @inViewportOnce and visible
-			$(@$el).toggleClass(@inViewportClass, visible) if @inViewportClass
-
-		# Adds the `in-viewport-entirely` class when the component is in bounds
-		inViewportEntirely: (visible) ->
-			$(@$el).toggleClass(@inViewportEntrelyClass, visible) if @inViewportEntrelyClass
-
-	# Public API
-	methods:
-
-		# Run the check function and map it's response to our data attributes
-		onInViewportScroll: ->
-			@[prop] = val for prop, val of check @$el,
-				offsetTop:    @inViewportOffsetTop
-				offsetBottom: @inViewportOffsetBottom
-
-		# Add listeners
-		addInViewportHandlers: ->
-			return if @inViewportHandlersAdded
-			@inViewportHandlersAdded = true
-			win.on 'scroll', @onInViewportScroll
-			win.on 'resize', @onInViewportScroll
-			@onInViewportScroll()
-
-		# Remove listeners
-		removeInViewportHandlers: ->
-			return unless @inViewportHandlersAdded
-			@inViewportHandlersAdded = false
-			win.off 'scroll', @onInViewportScroll
-			win.off 'resize', @onInViewportScroll
-
-		###
-		# Public API for invoking visibility tests
-		###
-
-		# Check if the element is visible at all in the viewport
-		isInViewport: (el, options) ->
-			check(el, options).inViewport
-
-		# Check if the elemetn is entirely visible in the viewport
-		isInViewportEntirely: (el, options) ->
-			check(el, options).isInViewportEntirely