More querySpec merging tests

More querySpec merging tests

--- tests/denorm-tests.coffee
+++ tests/denorm-tests.coffee
@@ -46,6 +46,41 @@
         J.fetching.tryQsPairwiseMerge(
             modelName: 'Foo'
             selector:
+                a: 6
+                b: 7
+                c: 8
+        ,
+            modelName: 'Foo'
+            selector:
+                a: 5
+                b: 7
+                c: 8
+        )
+        (
+            modelName: 'Foo'
+            selector:
+                a: $in: [5, 6]
+                b: 7
+                c: 8
+        )
+    )
+    test.isNull J.fetching.tryQsPairwiseMerge(
+        modelName: 'Foo'
+        selector:
+            a: 6
+            b: 7
+            c: 8
+    ,
+        modelName: 'Foo'
+        selector:
+            a: 5
+            b: 7
+            c: 9
+    )
+    testEqual(
+        J.fetching.tryQsPairwiseMerge(
+            modelName: 'Foo'
+            selector:
                 'a.x': $in: [4, 8]
         ,
             modelName: 'Foo'
@@ -57,6 +92,17 @@
             selector:
                 'a.x': $in: [4, 5, 7, 8]
         )
+    )
+    test.isNull J.fetching.tryQsPairwiseMerge(
+        modelName: 'Foo'
+        selector:
+            a: 5
+            b: 10
+    ,
+        modelName: 'Foo'
+        selector:
+            a: 6
+            b: $in: [10, 11]
     )
     test.isNull J.fetching.tryQsPairwiseMerge(
         modelName: 'Foo'


about: add about to projects

about: add about to projects

--- projects.coffee
+++ projects.coffee
@@ -111,6 +111,12 @@
     script        : "website/a/js/__app.features.js"
     sourceMapRoot : "Features/"

+  About           :
+    path          : "client/About"
+    style         : "website/a/css/__app.about.css"
+    script        : "website/a/js/__app.about.js"
+    sourceMapRoot : "About/"
+
 bundles           =

   KodingIn        :


adding update to sync keeper

adding update to sync keeper

Former-commit-id: c940a44711703079a963cce90ebada55a180c9e7 [formerly cb2da249808bb66ad0f42699fcffcf3c92e5eb41] [formerly aac4f705a658655e8cdc301e183bd95867ec1cac [formerly aac4f705a658655e8cdc301e183bd95867ec1cac [formerly 0b59a20ac71a0f9f437e3c41c552ac5074e05786]]]
Former-commit-id: ca6376197961ec1913d3af4d1fdac10b15021721 [formerly e34e24573bd8840a1add44ce45057be67f5dba2f]
Former-commit-id: 65087718528fd6e2f31fe10191884e891a956e06
Former-commit-id: 9ec0a76f32a2687f018ed79d302afd48609f1653

--- app/assets/javascripts/backbone/config/backbone/sync.js.coffee
+++ app/assets/javascripts/backbone/config/backbone/sync.js.coffee
@@ -13,7 +13,7 @@
       else
         sync = _sync.apply entity, [method, entity, options]

-      if !entity._fetch and method in ["read", "create"]
+      if !entity._fetch and method in ["read", "create", "update"]
         entity._fetch = sync

       sync


When an image in an entry has a relative URL, add its feed hostname and port before attempting to lazy-load it.

For the moment this only works when the "open all entries by default" config option is disabled.

--- app/assets/javascripts/ng-services/ng-LazyLoadingSvc.js.coffee
+++ app/assets/javascripts/ng-services/ng-LazyLoadingSvc.js.coffee
@@ -3,15 +3,25 @@
 ########################################################

 angular.module('feedbunch').service 'lazyLoadingSvc',
-['$rootScope', 'animationsSvc', ($rootScope, animationsSvc)->
+['$rootScope', 'animationsSvc', 'findSvc',
+($rootScope, animationsSvc, findSvc)->

   #--------------------------------------------
-  # PRIVATE FUNCTION: Lazy load a single image. Receives as argument the jQuery object wrapping the img.
+  # PRIVATE FUNCTION: Lazy load a single image. Receives as arguments:
+  # - jQuery object wrapping the img.
+  # - entry to which the image belongs
   #--------------------------------------------
-  load_image = (img)->
+  load_image = (img, entry=null)->
     # Create a clone of the image, hide it and load the actual image there. If it loads successfully,
     # hide the placeholder image and show the loaded image, otherwise hide both images.
     data_src = img.attr 'data-src'
+    uri = new URI(data_src).normalize()
+
+    # Convert relative URIs to absolute, using the feed hostname
+    if uri.is('relative') && entry?
+      feed = findSvc.find_feed entry.feed_id
+      feed_uri = new URI(feed.url).normalize()
+      uri.host feed_uri.host()

     if !data_src || data_src?.trim()?.length == 0
       # If data-src is blank, just hide the spinner
@@ -25,7 +35,7 @@
       .on 'load', ->
         img.addClass 'hidden'
         animationsSvc.show_image loaded_img
-      loaded_img.attr('src', data_src)
+      loaded_img.attr 'src', uri.toString()

   service =

@@ -34,7 +44,7 @@
     #---------------------------------------------
     load_entry_images: (entry)->
       $("#entry-#{entry.id} .entry-content img[data-src]").each ->
-        load_image $(this)
+        load_image $(this), entry

     #---------------------------------------------
     # Load images visible within the viewport (and 600px below it).


add image to douban, tqq and qq

add image to douban, tqq and qq

--- lib/assets/javascripts/social-share-button.coffee
+++ lib/assets/javascripts/social-share-button.coffee
@@ -14,13 +14,13 @@
       when "twitter"
         SocialShareButton.openUrl("https://twitter.com/home?status=#{title}: #{url}")
       when "douban"
-        SocialShareButton.openUrl("http://www.douban.com/recommend/?url=#{url}&title=#{title}&v=1&r=1")
+        SocialShareButton.openUrl("http://www.douban.com/recommend/?url=#{url}&title=#{title}&image=#{img}")
       when "facebook"
         SocialShareButton.openUrl("http://www.facebook.com/sharer.php?t=#{title}&u=#{url}")
       when "qq"
-        SocialShareButton.openUrl("http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=#{url}&title=#{title}")
+        SocialShareButton.openUrl("http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=#{url}&title=#{title}&pics=#{img}")
       when "tqq"
-        SocialShareButton.openUrl("http://share.v.t.qq.com/index.php?c=share&a=index&url=#{url}&title=#{title}")
+        SocialShareButton.openUrl("http://share.v.t.qq.com/index.php?c=share&a=index&url=#{url}&title=#{title}&pic=#{img}")
       when "baidu"
         SocialShareButton.openUrl("http://apps.hi.baidu.com/share/?url=#{url}&title=#{title}&content=")
       when "kaixin001"


Use minHeight otherwise ignored by flexbox

--- resources/assets/coffee/forum-topic-reply.coffee
+++ resources/assets/coffee/forum-topic-reply.coffee
@@ -133,7 +133,7 @@
   resizeContainer: =>
     return unless @available()

-    @container[0].style.height = "#{@box[0].getBoundingClientRect().height}px"
+    @container[0].style.minHeight = "#{@box[0].getBoundingClientRect().height}px"

   stick: =>


Removed debug statement

Removed debug statement

--- client/views/app/sideNav/directMessagesFlex.coffee
+++ client/views/app/sideNav/directMessagesFlex.coffee
@@ -188,7 +188,6 @@
 	classificationOrder = ['U','C','S','TS']

 	# user's access permissions
-	console.log 'ap subsready: ', FlowRouter.subsReady('accessPermissions')
 	userPerms = AccessPermissions.find({_id:{$in: userPermissionIds}}).fetch()
 	userCountry = _.find(userPerms, (perm) -> perm.type is 'Release Caveat')


GoalListController added

GoalListController added

--- results/front/app/coffee/controllers/main.coffee
+++ results/front/app/coffee/controllers/main.coffee
@@ -45,9 +45,24 @@
     $scope.isWelcomeVisible = false
     return

+GoalListController = ($scope, $rootScope, resource) ->
+    $scope.addGoal = ()->
+        cb = resource.postGoal($scope.goal)
+        cb.then (response)->
+            $rootScope.goalList.push(response.data)
+        $scope.goal = {}
+        return

-ContainerController = ($scope) ->
+    $scope.goal = {}
+    return
+
+ContainerController = ($scope, $rootScope, resource) ->
     $scope.WinName = "First Win"
+    resource.getGoals().then (result) ->
+        $rootScope.goalList = []
+        for goal in result._attrs
+            $rootScope.goalList.push(goal)
+
     return

 LoginController = ($scope, $rootScope, $location, $routeParams, resource, $gmAuth) ->
@@ -62,7 +77,7 @@
         $scope.loading = true

         onSuccess = (user) ->
-            $gmAuth.setUser(user)
+            $gmAuth.setUser(userGoal)
             $rootScope.auth = user
             $location.url("/")

@@ -94,7 +109,8 @@

 module = angular.module("results.controllers.main", [])
 module.controller("MainController", ["$scope","resource", "$timeout", "$routeParams", "$location", MainController])
-module.controller("ContainerController", ["$scope", ContainerController])
+module.controller("ContainerController", ["$scope", "$rootScope", "resource", ContainerController])
 module.controller("TooltipController", ["$scope", "$document", TooltipController])
 module.controller("LoginController", ["$scope","$rootScope", "$location", "$routeParams", "resource", "$gmAuth", LoginController])
 module.controller("UserListController", ["$scope","$rootScope", "resource", UserListController])
+module.controller("GoalListController", ["$scope","$rootScope", "resource", GoalListController])


just do debugging and tracing

just do debugging and tracing

--- metrics.coffee
+++ metrics.coffee
@@ -1,8 +1,10 @@
 StatsD = require('lynx')
 statsd = new StatsD(process.env["STATSD_HOST"] or "localhost", 8125, {on_error:->})

+traceAgent = require('@google-cloud/trace-agent')
+debugAgent = require('@google-cloud/debug-agent')
+
 prom = require('prom-client')
-collectDefaultMetrics = client.collectDefaultMetrics

 name = "unknown"
 hostname = require('os').hostname()
@@ -15,21 +17,10 @@
 require "./uv_threadpool_size"

-traceAgent = require('@google-cloud/trace-agent')
-debugAgent = require('@google-cloud/debug-agent')
-
-.start({
-  serviceContext: {
-	allowExpressions: true,
-	service: 'filestore-readonly',
-	version: '0.0.1'
-  }
-});

 module.exports = Metrics =
 	initialize: (_name) ->
 		name = _name
-		collectDefaultMetrics({ timeout: 5000, prefix: name })
 		traceAgent.start()
 		debugAgent.start({
 			serviceContext: {
@@ -47,19 +38,9 @@

 	inc : (key, sampleRate = 1)->
 		statsd.increment buildKey(key), sampleRate
-		counter = new prom.Counter({
-		  name: key,
-		  help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong
-		});
-		counter.inc()

 	count : (key, count, sampleRate = 1)->
 		statsd.count buildKey(key), count, sampleRate
-		counter = new prom.Counter({
-		  name: key,
-		  help: key #https://prometheus.io/docs/instrumenting/writing_exporters/#help-strings this is probably wrong
-		});
-		counter.inc(count)

 	timing: (key, timeSpan, sampleRate)->
 		statsd.timing(buildKey(key), timeSpan, sampleRate)


the RAM quota units changed from GB in the old version to MB in new, which breaks things completely -- temporary workaround

--- salvus/compute.coffee
+++ salvus/compute.coffee
@@ -1292,6 +1292,10 @@
                             quotas[k] = v
                         else
                             quotas[k] = misc.from_json(result[k])
+                    # TODO: this is a temporary workaround until I go through and convert everything in
+                    # the database, after the switch.
+                    if quotas.memory < 70
+                        quotas.memory *= 1000
                     opts.cb(undefined, quotas)

     set_quotas: (opts) =>


put timeouts in each state transition action

--- salvus/compute.coffee
+++ salvus/compute.coffee
@@ -84,28 +84,33 @@
     saving:
         desc     : 'The project is being snapshoted and saved to cloud storage.'
         to       : {}
+        timeout  : 60*60
         commands : ['address', 'copy_path', 'directory_listing', 'read_file', 'network', 'mintime', 'disk_quota', 'compute_quota', 'status']

     closing:
         desc     : 'The project is in the process of being closed, so the latest changes are being uploaded, everything is stopping, the files will be removed from this computer.'
         to       : {}
+        timeout  : 5*60
         commands : ['status', 'mintime']

     opening:
         desc     : 'The project is being opened, so all files and snapshots are being downloaded, the user is being created, etc.'
         to       : {}
+        timeout  : 60*60
         commands : ['status', 'mintime']

     starting:
         desc     : 'The project is starting up and getting ready to be used.'
         to       :
             save : 'saving'
+        timeout  : 60
         commands : ['save', 'copy_path', 'directory_listing', 'read_file', 'network', 'mintime', 'disk_quota', 'compute_quota', 'status']

     stopping:
         desc     : 'All processes associated to the project are being killed.'
         to       :
             save : 'saving'
+        timeout  : 60
         commands : ['save', 'copy_path', 'directory_listing', 'read_file', 'network', 'mintime', 'disk_quota', 'compute_quota', 'status']

 ###
@@ -970,7 +975,7 @@
                                     cb : (err) =>
                                         dbg("start finished -- #{err}")
                 else
-                    opts.cb("may only restart when state is opened or running")
+                    opts.cb("may only restart when state is opened or running or starting")

     # kill everything and remove project from this compute
     # node  (must be opened somewhere)
@@ -1814,6 +1819,7 @@
         opts = defaults opts,
             action     : required
             args       : undefined
+            timeout    : TIMEOUT
             cb         : required
         dbg = @dbg("_command(action:'#{opts.action}')")
         @_last[opts.action] = new Date()
@@ -1823,8 +1829,9 @@
         args.push(@project_id)
         dbg("args=#{misc.to_json(args)}")
         smc_compute
-            args : args
-            cb   : opts.cb
+            args    : args
+            timeout : opts.timeout
+            cb      : opts.cb

     command: (opts) =>
         opts = defaults opts,
@@ -1879,9 +1886,10 @@
                         @_update_state_db()
                         @_update_state_listeners()
                         @_command      # launch the command: this might take a long time
-                            action : opts.action
-                            args   : opts.args
-                            cb     : (err, ignored) =>
+                            action  : opts.action
+                            args    : opts.args
+                            timeout : state_info.timeout
+                            cb      : (err, ignored) =>
                                 # finished command -- will transition to new state as result
                                 @_state_error = err
                                 if err


storage: make previous commit actually work (in light of testing)

--- salvus/storage.coffee
+++ salvus/storage.coffee
@@ -2367,6 +2367,7 @@
                 f = filesystem(opts.project_id)
                 t = filesystem("DELETED-#{cassandra.now()}-#{opts.project_id}")
                 dbg("safely delete dataset (really just rename to #{t})")
+                cmd = "sudo zfs rename #{f} #{t}"   # if change this, also change arg to indexOf below!!!!
                 execute_on
                     host          : opts.host
                     command       : "ps ax | grep 'zfs rename' | grep #{opts.project_id}"
@@ -2376,13 +2377,13 @@
                     cb      : (err, output) ->
                         if err
                             cb("unable to connect to '#{opts.host}'")
-                        else if output.stdout.indexOf(opts.project_id) != -1
-                            dbg("already renaming -- left from previous attempt, since zfs is filling up with work...")
+                        else if output.stdout.indexOf("rename #{f}") != -1
+                            dbg("already renaming -- left from previous attempt, since zfs is filling up with work... --")
                             cb("unable to delete data set due zfs being too busy")
                         else
                             execute_on
                                 host    : opts.host
-                                command : "sudo zfs rename #{f} #{t}"
+                                command : cmd
                                 timeout : 360
                                 cb      : (err, output) ->
                                     if err


fdsfs

fdsfs

Signed-off-by: Sakchai Siripanyawuth <50d2926f6b388f0d7169db5beff2dc87e1537d54@artellectual.com>

--- vendor/assets/javascripts/simple_datatables.js.coffee
+++ vendor/assets/javascripts/simple_datatables.js.coffee
@@ -1,81 +0,0 @@
-//= require jquery.dataTables
-//= require jquery.datatables.fnSetFilteringDelay
-//= require jquery.datatables.fnReloadAjax
-
-root = exports ? this
-
-root.simpleDatatables = ( sSource, aoData, fnCallback ) ->
-
-  columns = [];
-  searchcolumns = [];
-  sortcolumns = [];
-
-  sEcho = 1;
-  sSearch = "";
-  bRegex = false;
-  iDisplayStart = 0;
-  iDisplayLength = 0;
-  data = [];
-
-  $.each(aoData, (index, dataObj) ->
-    switch dataObj.name
-      when "sColumns"
-        columns = dataObj.value.split(",");
-      when "sEcho"
-        sEcho = dataObj.value;
-      when "sSearch"
-        sSearch = dataObj.value;
-      when "bRegex"
-        bRegex = dataObj.value;
-      when "iDisplayStart"
-        iDisplayStart = dataObj.value;
-      when "iDisplayLength"
-        iDisplayLength = dataObj.value;
-      when "iSortCol_0"
-        console.log("yobanarot!");
-        iSortCol = dataObj.value;
-      when "sSortDir_0"
-        sSortDir = dataObj.value;
-      else
-        console.log(dataObj.name);
-  );
-
-  $.each(aoData, (index, dataObj) ->
-    search_regexp = ///sSearch_([0-9]+)///
-    if (col = dataObj.name.match(search_regexp)) and dataObj.value
-      search_value = dataObj.value.split('/')
-      console.log search_value
-      data.push({name: "search["+columns[col[1]] + search_value[1] + "]", value: search_value[0] });
-
-    search_regexp = ///bSearchable_([0-9]+)///
-    if (col = dataObj.name.match(search_regexp)) and dataObj.value
-      searchcolumns.push(columns[col[1]]);
-
-    search_regexp = ///iSortCol_([0-9]+)///
-    if (col = dataObj.name.match(search_regexp))
-      sortcolumns[parseInt(col[1])]=columns[parseInt(dataObj.value)];
-
-    search_regexp = ///sSortDir_([0-9]+)///
-    if (col = dataObj.name.match(search_regexp)) and dataObj.value
-      sortcolumns[col[1]]=sortcolumns[col[1]]+"."+dataObj.value;
-
-  );
-
-  data.push({name: "sEcho", value: sEcho});
-  data.push({name: "page", value: iDisplayStart/iDisplayLength + 1});
-  data.push({name: "per_page", value: iDisplayLength});
-  data.push({name: "search[meta_sort]", value: sortcolumns[0]});
-
-  $.each(columns, (index, val) ->
-    data.push({name: "columns["+index+"]", value: val});
-  );
-
-  if sSearch
-    op =
-      if bRegex
-        "_contains"
-      else
-        "_sw"
-    data.push({name: "search["+searchcolumns.join("_or_")+op+"]", value: sSearch});
-
-  $.ajax( { "dataType": 'json', "type": "GET", "url": sSource, "data": data, "success": fnCallback } );


Clean up confirm options handling

Clean up confirm options handling

--- src/bootstrap-dialogs.coffee
+++ src/bootstrap-dialogs.coffee
@@ -50,18 +50,21 @@
       $('body').off('keyup', returnHandler)

   confirm: (options={}) ->
-    title = options.title or 'Please confirm'
-    body = options.body
-    okText = options.ok or 'Ok'
+    defaultOptions =
+      title: 'Please confirm'
+      ok: 'Ok'
+      cancel: 'Cancel'
+      danger: false
+    options = $.extend(defaultOptions, options)
+
     okClass = if options.danger then 'danger' else 'primary'
-    cancelText = options.cancel or 'Cancel'

     promise = exports.dialog
-      title: title
-      body: body
+      title: options.title
+      body: options.body
       buttons: [
-        [ cancelText, -> promise.reject() ]
-        [ mkbutton(okText, okClass), -> promise.resolve() ]
+        [ options.cancel, -> promise.reject() ]
+        [ mkbutton(options.ok, okClass), -> promise.resolve() ]
       ]

     if options.return


do not list .shared and koding.kd.io domains

--- workers/social/lib/social/models/account/index.coffee
+++ workers/social/lib/social/models/account/index.coffee
@@ -982,25 +982,36 @@
     client.context.group = 'koding'
     oldAddTags.call this, client, tags, options, callback

-  fetchDomains: (callback) ->
+  fetchUserDomains: (callback) ->
     JDomain = require '../domain'

     Relationship.some
       targetName: "JDomain"
       sourceId  : @getId()
       sourceName: "JAccount"
+    ,
+      targetId : 1
     , (err, rels)->
       return callback err if err

-      JDomain.some {_id: $in: (rel.targetId for rel in rels)}, (err, domains)->
-        callback err, domains
+      JDomain.someData {_id: $in: (rel.targetId for rel in rels)}, {}, (err, cursor)->
+        domainList = []
+        unless err
+          cursor.toArray (err, domains)->
+            domainList = domains.filter (domain)->
+              domainName = domain.domain
+              !(/^shared[\-]?([0-9]+)?/.test domainName) and !(/(.*)\.koding\.kd\.io$/.test domainName)
+
+            callback null, domainList
+
+        callback err, domainList

   fetchDomains$: permit
     advanced: [
       { permission: 'list own domains', validateWith: Validators.own }
     ]
     success: (client, callback) ->
-      @fetchDomains callback
+      @fetchUserDomains callback

   fetchMyFollowingsFromGraph: secure (client, options, callback)->
     @fetchFollowFromGraph "fetchFollowingMembers", client, options, callback


Disable plan cache

Disable plan cache

--- workers/social/lib/social/models/recurly/index.coffee
+++ workers/social/lib/social/models/recurly/index.coffee
@@ -4,7 +4,7 @@
 createId  = require 'hat'

 forceRefresh  = yes
-forceInterval = 60 * 1
+forceInterval = 0

 module.exports = class JRecurlyPlan extends jraphical.Module

@@ -251,7 +251,7 @@
       return callback err  if err
       if subs.length > 0
         subs = subs[0]
-
+
         subs.quantity ?= 1
         subs.quantity += 1


clickOnAndWaitForElementByCss action fix

--- src/action/clickOnAndWaitForElementByCss.coffee
+++ src/action/clickOnAndWaitForElementByCss.coffee
@@ -9,7 +9,7 @@
       .click

     if typeof waitFor is 'object'
-      return @waitForTheFirstElementAction context, waitFor, asserter, timeout
+      return @waitForTheFirstElementByCssAction context, waitFor, asserter, timeout

     context.waitForElementByCss waitFor, asserter, timeout


added created message to class factory

added created message to class factory

--- Framework/ClassFactory.coffee
+++ Framework/ClassFactory.coffee
@@ -36,6 +36,7 @@
       eval("var klass = root.#{klassName}")
       if(typeof klass != 'undefined')
         @klassCache[className] = klass if @settings.cacheEnabled
+        Ti.API.info("created #{klassName}")
         return new klass(options)
     catch error
       alert(error)


Blur buttons on tap and click.

Blur buttons on tap and click.

--- src/button/ButtonView.coffee
+++ src/button/ButtonView.coffee
@@ -72,6 +72,8 @@
     if @hasIcon then @prefixedClasses.add BUTTON_HAS_ICON_CLS

     @on 'hide disable', => @unfill()
+
+    @on 'tap click', => @_blur()

     @on 'show enable ready', =>
       @emptyFill()


Don't add existing style tag again.

Don't add existing style tag again.

--- vendor/assets/javascripts/less_assets.js.coffee
+++ vendor/assets/javascripts/less_assets.js.coffee
@@ -55,7 +55,8 @@

         style.appendChild rules

-      head = doc.getElementsByTagName('head')[0]
-      head.appendChild style
+      unless doc.getElementById(id)
+        head = doc.getElementsByTagName('head')[0]
+        head.appendChild style

     result


Better comment. see #45507

Better comment. see #45507

--- src/humanize_filters.coffee
+++ src/humanize_filters.coffee
@@ -79,7 +79,7 @@

 angular.module("mpx-frontend-module-utils").filter 'humanizeBoolean', ($rootScope) ->
   (value) ->
-    # HACK: https://issues.mediapeers.com/issues/45509
+    # HACK: This should be done in mpx-core.
     txt =
       true: if $rootScope.affiliationId == 'nbcu' then 'Yes' else 'On'
       false: if $rootScope.affiliationId == 'nbcu' then 'No' else 'Off'


The coffee way, space indentation on blurry.coffee. Updated readme

--- scripts/blurry.coffee
+++ scripts/blurry.coffee
@@ -2,324 +2,292 @@
 # Functions with underscore (_) before the fn name, are utility fn,
 # they don't control flow of library
 # root.pmwc =
-# 	debug: ()->
-# 		console.log arguments
+#   debug: ()->
+#     console.log arguments
 class @Blurry
-	#
-	constructor: (options={})->
-		# To prevent Hash collisions
-		@usedHashes = []
-		# options for each instance
-		# el jQueryElement
-		this.options = options
-		# Multidim assoc-array of sharp/original data, by data-blurry-id:hash
-		this.sharpEl = {}
-		# Multidim assoc-array of blurred data, by data-blurry-id:hash
-		this.blurryEl = {}
-		# Object.prototype.toString.call(el) === '[object HTMLCanvasElement]'
-		@iteSharp = 0
-		@iteSharpList = []
-		@iteBlurry = 0
-		@iteBlurryList = []
-		for el in this.options.el
-			#this.originalCanvas.push el
-			$el = $(el)
-			hash = this.hash()
-
-			if not el.getAttribute('data-blurry-id')
-				el.setAttribute('data-blurry-id', hash)
-				if this._type(el) is 'Canvas'
-					this.sharpEl[hash] = el.toDataURL()
-					@iteSharpList.push @iteSharp
-					@iteSharp++
-				if this._type(el) is 'Image'
-					# Currently there is a problem calculating H and W
-					# I believe the problem is with the calculation done before img draws
-					# 99.99% of cases should appear if CTRL+F5 (why moved to this.cavasify)
-					# edit: This should be fixed by now: waitForImages before calling Blurry
-					if el.naturalHeight isnt 0 or el.naturalWidth isnt 0
-						canvas =  this.canvasify @options.replaceWithCanvas, @iteSharp, $el, el, el.naturalWidth, el.naturalHeight
-						this.sharpEl[hash] = canvas.toDataURL()
-						@iteSharpList.push @iteSharp
-						@iteSharp++
-		# console.log @iteSharpList
-
-		totalSharpEl = this._size(this.sharpEl)
-		if totalSharpEl >= 1
-			for sharpHash, sharpData of this.sharpEl
-				do (sharpHash, sharpData)=>
-					imgtmp = new Image()
-					imgtmp.src = sharpData
-					# console.log iteBlurry
-					# Should delay enough to permit imgtmp.src to render, so we can get data
-					# 2ms should be enough
-					# imgtmp.onload = this.blurry this, imgtmp, {sharpHash:sharpHash, sharpData:sharpData}, iteBlurry, @iteSharpList
-					# onloadInterval = setTimeout ()=>
-					# 	this.blurry this, imgtmp,
-					# 		{sharpHash:sharpHash, sharpData:sharpData}, @iteBlurry, @iteBlurryList, @iteSharpList
-					# , 2
-					imgtmp.onload = =>
-						cvstmp = new @_Canvas()
-						cvsctx = cvstmp.getContext '2d'
-						# naturalWidth/Height is HTML5 only, but since this lib uses canvas...
-						cvstmp.height = imgtmp.naturalHeight
-						cvstmp.width = imgtmp.naturalWidth
-						cvsctx.clearRect 0, 0, cvstmp.width, cvstmp.height
-						cvsctx.drawImage imgtmp, 0, 0
-						cvs = new StackBlur.canvasRGBA cvstmp, 0, 0,
-							cvstmp.width, cvstmp.height, @options.radius
-						# We have to call toDataURL anyway, even if sharp === blurry
-						@blurryEl[sharpHash] = cvs.toDataURL()
-
-						# Test and log if data (sharp and blurry) is the same
-						console.log sharpHash + ' '+ (sharpData is @blurryEl[sharpHash])
-
-						if @iteBlurry is @iteSharpList.length-1
-							@iteBlurryList.push @iteBlurry
-							@iteBlurry++
-							return @options.onComplete(this)
-
-						@iteBlurryList.push @iteBlurry
-						@iteBlurry++
-
-		@events()
-		return this
-
-	###
-	Element manipulation funs
-	-------------------------
-	###
-
-	###
-	@param replaceWithCanvas querySelector
-	@param indexInOptions querySelector
-	@param $el querySelector
-	@param el querySelector
-	@param w int
-	@param h int
-	@return HTMLImageElement
-	###
-	canvasify: (replaceWithCanvas, indexInOptions, $el, el, w, h)->
-		# console.debug 'aW:onElCalcW aH:onElCalcH'
-		# console.debug 'o_' + w + ':' + 'c_' + el.naturalWidth, h + ':' + el.naturalHeight
-		cvs = new @_Canvas()
-		cvs.height = el.naturalHeight
-		cvs.width = el.naturalWidth
-		ctx = cvs.getContext('2d')
-		ctx.clearRect(0, 0, cvs.width, cvs.height)
-		ctx.drawImage el, 0, 0
-		ctx.save
-		if replaceWithCanvas
-			for attr in el.attributes
-				attrToSkip = ['alt', 'src']
-				if attr.name in attrToSkip
-					#do nothing
-				else
-					cvs.setAttribute attr.name, attr.value
-			$el.replaceWith(cvs)
-			@options.el[indexInOptions] = cvs
-		return cvs
-
-	###
-	@param replaceWithImage boolean
-	@param el HTMLCanvasElement
-	@param $el querySelector
-	@return HTMLImageElement
-	###
-	imagify: (replaceWithImage, el, $el)->
-		imgtmp = new Image
-		imgtmp.src = el.toDataURL()
-		imgtmp.onload = =>
-			if 	replaceWithImage
-				$el.replaceWith(imgtmp)
-			return imgtmp
+  #
+  constructor: (options={})->
+    # To prevent Hash collisions
+    @usedHashes = []
+    # options for each instance
+    # el jQueryElement
+    @options = options
+    # Multidim assoc-array of sharp/original data, by data-blurry-id:hash
+    @sharpEl = {}
+    # Multidim assoc-array of blurred data, by data-blurry-id:hash
+    @blurryEl = {}
+    # Object.prototype.toString.call(el) === '[object HTMLCanvasElement]'
+    @iteSharp = 0
+    @iteSharpList = []
+    @iteBlurry = 0
+    @iteBlurryList = []
+    for el in this.options.el
+      #this.originalCanvas.push el
+      $el = $(el)
+      hash = @hash()
+
+      if not el.getAttribute('data-blurry-id')
+        el.setAttribute('data-blurry-id', hash)
+        if @_type(el) is 'Canvas'
+          @sharpEl[hash] = el.toDataURL()
+          @iteSharpList.push @iteSharp
+          @iteSharp++
+        if @_type(el) is 'Image'
+          # Currently there is a problem calculating H and W
+          # I believe the problem is with the calculation done before img draws
+          # 99.99% of cases should appear if CTRL+F5 (why moved to this.cavasify)
+          # edit: This should be fixed by now: waitForImages before calling Blurry
+          if el.naturalHeight isnt 0 or el.naturalWidth isnt 0
+            canvas =  @canvasify @options.replaceWithCanvas, @iteSharp, $el, el, el.naturalWidth, el.naturalHeight
+            this.sharpEl[hash] = canvas.toDataURL()
+            @iteSharpList.push @iteSharp
+            @iteSharp++
+    # console.log @iteSharpList
+
+    totalSharpEl = @_size @sharpEl
+    if totalSharpEl >= 1
+      for sharpHash, sharpData of @sharpEl
+        do (sharpHash, sharpData)=>
+          imgtmp = new Image()
+          imgtmp.src = sharpData
+          imgtmp.onload = =>
+            cvstmp = new @_Canvas()
+            cvsctx = cvstmp.getContext '2d'
+            # naturalWidth/Height is HTML5 only, but since this lib uses canvas...
+            cvstmp.height = imgtmp.naturalHeight
+            cvstmp.width = imgtmp.naturalWidth
+            cvsctx.clearRect 0, 0, cvstmp.width, cvstmp.height
+            cvsctx.drawImage imgtmp, 0, 0
+            cvs = new StackBlur.canvasRGBA cvstmp, 0, 0,
+              cvstmp.width, cvstmp.height, @options.radius
+            # We have to call toDataURL anyway, even if sharp === blurry
+            @blurryEl[sharpHash] = cvs.toDataURL()
+
+            # Test and log if data (sharp and blurry) is the same
+            console.log sharpHash + ' '+ (sharpData is @blurryEl[sharpHash])
+
+            if @iteBlurry is @iteSharpList.length-1
+              @iteBlurryList.push @iteBlurry
+              @iteBlurry++
+              return @options.onComplete(this)
+
+            @iteBlurryList.push @iteBlurry
+            @iteBlurry++
+
+    @events()
+    return this
+
+  ###
+  Element manipulation funs
+  -------------------------
+  ###
+
+  ###
+  @param replaceWithCanvas querySelector
+  @param indexInOptions querySelector
+  @param $el querySelector
+  @param el querySelector
+  @param w int
+  @param h int
+  @return HTMLImageElement
+  ###
+  canvasify: (replaceWithCanvas, indexInOptions, $el, el, w, h)->
+    # console.debug 'aW:onElCalcW aH:onElCalcH'
+    # console.debug 'o_' + w + ':' + 'c_' + el.naturalWidth, h + ':' + el.naturalHeight
+    cvs = new @_Canvas()
+    cvs.height = el.naturalHeight
+    cvs.width = el.naturalWidth
+    ctx = cvs.getContext('2d')
+    ctx.clearRect(0, 0, cvs.width, cvs.height)
+    ctx.drawImage el, 0, 0
+    ctx.save
+    if replaceWithCanvas
+      for attr in el.attributes
+        attrToSkip = ['alt', 'src']
+        if attr.name in attrToSkip
+          #do nothing
+        else
+          cvs.setAttribute attr.name, attr.value
+      $el.replaceWith(cvs)
+      @options.el[indexInOptions] = cvs
+    return cvs
+
+  ###
+  @param replaceWithImage boolean
+  @param el HTMLCanvasElement
+  @param $el querySelector
+  @return HTMLImageElement
+  ###
+  imagify: (replaceWithImage, el, $el)->
+    imgtmp = new Image
+    imgtmp.src = el.toDataURL()
+    imgtmp.onload = =>
+      if  replaceWithImage
+        $el.replaceWith imgtmp
+      return imgtmp
   ###
   ###
   dataToCanvas: (data)->
-		imgtmp = new Image
-		imgtmp.src = data
-		imgtmp.onload = =>
-			canvas = new @_Canvas()
-			canvas.height = imgtmp.naturalHeight
-			canvas.width = imgtmp.naturalWidth
-			cvsctx.clearRect 0, 0, canvas.width, canvas.height
-			cvsctx.drawImage imgtmp, 0, 0
-			return canvas
-	###
-	###
-	canvasDataReplacement: (canvas, data)->
-		imgtmp = new Image
-		imgtmp.src = data
-		imgtmp.onload = =>
-			canvas.height = imgtmp.naturalHeight
-			canvas.width = imgtmp.naturalWidth
-			cvsctx = canvas.getContext('2d')
-			cvsctx.clearRect 0, 0, canvas.width, canvas.height
-			cvsctx.drawImage imgtmp, 0, 0
-			return canvas
-
-	imgToCanvas : (image)->
-		cvs = document.createElement('canvas')
-		cvs.height = el.naturalHeight
-		cvs.width = el.naturalWidth
-		ctx = cvs.getContext('2d')
-		ctx.clearRect(0, 0, cvs.width, cvs.height)
-		ctx.drawImage el, 0, 0
-		ctx.save
-		return cvs
-		# $el.replaceWith(cvs)
-
-	###
-	Events
-	------
-	###
-	events: ->
-		for el in @options.el
-			do (el)=>
-				if @_type(el) is 'Image'
-					$(el).bind 'mouseover', {_this:this,el:el}, (event)->
-						# console.log event
-						data = event.data._this.blurryEl[event.data.el.dataset.blurryId]
-						event.data.el.src = data
-					$(el).bind 'mouseleave', {_this:this,el:el}, (event)->
-						# console.log event.data._this
-						data = event.data._this.sharpEl[event.data.el.dataset.blurryId]
-						event.data.el.src = data
-
-				else if @_type(el) is 'Canvas'
-					console.log 'not ready for canvas'
-					$(el.parentNode).bind 'mouseover', {_this:this,el:el,parent:el.parentNode}, (e)->
-						$parent = $(e.data.parent).find(e.data.el.tagName.toLowerCase())
-						for el in $parent
-							a = e.data._this.canvasDataReplacement el, e.data._this.blurryEl[el.dataset.blurryId]
-							a()
-					$(el.parentNode).bind 'mouseout', {_this:this,el:el,parent:el.parentNode}, (e)->
-						$parent = $(e.data.parent).find(e.data.el.tagName.toLowerCase())
-						for el in $parent
-							a = e.data._this.canvasDataReplacement el, e.data._this.sharpEl[el.dataset.blurryId]
-							a()
-					# $(el).bind 'mousemove', {_this:this,el:el}, @_mouseover
-					# $(el).bind 'mousemove', {_this:this,el:el}, (event)->
-					# 	$(el).trigger 'active'
-					# 	# data = event.data._this.sharpEl[event.data.el.dataset.blurryId]
-					# 	# event.data.el.src = data
-				else
-					return
-
-	_mouseover: (e)->
-    if not e
-        e = window.event;
-    console.log e
-    console.log e.currentTarget.parentNode
-
-	_mouseactive: (e)->
-    if not e
-        e = window.event;
-    console.log e
-    mx = e.pageX
-    my = e.pageY
-    areaX = [e.currentTarget.offsetLeft, e.currentTarget.offsetLeft + e.currentTarget.offsetWidth]
-    areaY = [e.currentTarget.offsetTop, e.currentTarget.offsetTop + e.currentTarget.offsetHeight]
-    if areaX[1] >= mx >= areaX[0] and areaY[1] >= my >= areaY[0]
-    	console.log 'over'
-    console.log areaX
-    console.log mx
+    imgtmp = new Image
+    imgtmp.src = data
+    imgtmp.onload = =>
+      canvas = new @_Canvas()
+      canvas.height = imgtmp.naturalHeight
+      canvas.width = imgtmp.naturalWidth
+      cvsctx.clearRect 0, 0, canvas.width, canvas.height
+      cvsctx.drawImage imgtmp, 0, 0
+      return canvas
+  ###
+  ###
+  canvasDataReplacement: (canvas, data)->
+    imgtmp = new Image
+    imgtmp.src = data
+    imgtmp.onload = =>
+      canvas.height = imgtmp.naturalHeight
+      canvas.width = imgtmp.naturalWidth
+      cvsctx = canvas.getContext('2d')
+      cvsctx.clearRect 0, 0, canvas.width, canvas.height
+      cvsctx.drawImage imgtmp, 0, 0
+      return canvas
+
+  imgToCanvas : (image)->
+    cvs = document.createElement('canvas')
+    cvs.height = el.naturalHeight
+    cvs.width = el.naturalWidth
+    ctx = cvs.getContext('2d')
+    ctx.clearRect(0, 0, cvs.width, cvs.height)
+    ctx.drawImage el, 0, 0
+    ctx.save
+    return cvs
+    # $el.replaceWith(cvs)
+
+  ###
+  Events
+  ------
+  ###
+  events: ->
+    for el in @options.el
+      do (el)=>
+        if @_type(el) is 'Image'
+          $(el).bind 'mouseover', {_this:this,el:el}, (event)->
+            # console.log event
+            data = event.data._this.blurryEl[event.data.el.dataset.blurryId]
+            event.data.el.src = data
+          $(el).bind 'mouseleave', {_this:this,el:el}, (event)->
+            # console.log event.data._this
+            data = event.data._this.sharpEl[event.data.el.dataset.blurryId]
+            event.data.el.src = data
+
+        else if @_type(el) is 'Canvas'
+          console.log 'not ready for canvas'
+          $(el.parentNode).bind 'mouseover', {_this:this,el:el,parent:el.parentNode}, (e)->
+            $parent = $(e.data.parent).find(e.data.el.tagName.toLowerCase())
+            for el in $parent
+              a = e.data._this.canvasDataReplacement el, e.data._this.blurryEl[el.dataset.blurryId]
+              a()
+          $(el.parentNode).bind 'mouseout', {_this:this,el:el,parent:el.parentNode}, (e)->
+            $parent = $(e.data.parent).find(e.data.el.tagName.toLowerCase())
+            for el in $parent
+              a = e.data._this.canvasDataReplacement el, e.data._this.sharpEl[el.dataset.blurryId]
+              a()
+          # $(el).bind 'mousemove', {_this:this,el:el}, @_mouseover
+          # $(el).bind 'mousemove', {_this:this,el:el}, (event)->
+          #   $(el).trigger 'active'
+          #   # data = event.data._this.sharpEl[event.data.el.dataset.blurryId]
+          #   # event.data.el.src = data
+        else
+          return
+
+  _mouseover: (e)->
+    # if not e
+    #   e = window.event;
+    # console.log e
+    # console.log e.currentTarget.parentNode
+
+  _mouseactive: (e)->
+    # if not e
+    #   e = window.event;
+    # console.log e
+    # mx = e.pageX
+    # my = e.pageY
+    # areaX = [e.currentTarget.offsetLeft, e.currentTarget.offsetLeft + e.currentTarget.offsetWidth]
+    # areaY = [e.currentTarget.offsetTop, e.currentTarget.offsetTop + e.currentTarget.offsetHeight]
+    # if areaX[1] >= mx >= areaX[0] and areaY[1] >= my >= areaY[0]
+    #   console.log 'over'
+    # console.log areaX
+    # console.log mx

   _mouseout: (_this)->
-    _this.mousePos = null
+    # _this.mousePos = null
     # if typeof canvasOnmouseout is typeof Function
     #   canvasOnmouseout(_this)

-	###
-	Blur all elements in this.options.el, except the one passed as arg[0]
-	@param except querySelector
-	@return true if replaced elements; false if none replaced, error if except not
-					found
-	###
-	blurAllExcept: (except)->
-		for el in this.options.el
-			$(el).bind 'mouseover', {_this:this}, (e)->
-				data = _this.blurryEl[el.dataset.blurryId]
-				el.src = data
-
-	###
-	Sharp all elements in this.options.el, except the one passed as arg[0]
-	@param except querySelector
-	@return true if replaced elements; false if none replaced, error if except not
-					found
-	###
-	sharpAllExcept: (except)->
-
-	hash: ->
-		hash = this._random()
-		if hash not in @usedHashes
-			@usedHashes.push hash
-			return hash
-		else
-			this.addHash()
-
-	_Canvas: ->
-		return document.createElement 'canvas'
-
-	_random: ->
-		string = ''
-		chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-		for num in [1..32]
-				string += chars.charAt(Math.floor(Math.random() * chars.length))
-		return string
-
-	_type: (obj)->
-		list = {
-			'[object HTMLCanvasElement]': 'Canvas',
-			'[object HTMLImageElement]': 	'Image',
-			'[object Object]': 						'Object',
-		}
-		if obj?
-			return list[Object.prototype.toString.call(obj)]
-		else
-			return list
-
-	_size: (obj)->
-		size = 0
-		for key, val of obj
-			if (obj.hasOwnProperty(key)) then size++
-		return size
+  ###
+  Blur all elements in this.options.el, except the one passed as arg[0]
+  @param except querySelector
+  @return true if replaced elements; false if none replaced, error if except not
+          found
+  ###
+  blurAllExcept: (except)->
+    for el in this.options.el
+      $(el).bind 'mouseover', {_this:this}, (e)->
+        data = _this.blurryEl[el.dataset.blurryId]
+        el.src = data
+
+  ###
+  Sharp all elements in this.options.el, except the one passed as arg[0]
+  @param except querySelector
+  @return true if replaced elements; false if none replaced, error if except not
+          found
+  ###
+  sharpAllExcept: (except)->
+
+  hash: ->
+    hash = @_random()
+    if hash not in @usedHashes
+      @usedHashes.push hash
+      return hash
+    else
+      this.addHash()
+
+  _Canvas: ->
+    return document.createElement 'canvas'
+
+  _random: ->
+    string = ''
+    chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+    for num in [1..32]
+        string += chars.charAt(Math.floor(Math.random() * chars.length))
+    return string
+
+  _type: (obj)->
+    list = {
+      '[object HTMLCanvasElement]': 'Canvas',
+      '[object HTMLImageElement]':  'Image',
+      '[object Object]':            'Object',
+    }
+    if obj?
+      return list[Object.prototype.toString.call(obj)]
+    else
+      return list
+
+  _size: (obj)->
+    size = 0
+    for key, val of obj
+      if (obj.hasOwnProperty(key)) then size++
+    return size

 #root.Blurry.prototype.loaded = true

 $ ->
-	$('body').waitForImages ()=>
-		blurFx = new Blurry {
-			replaceWithCanvas: true
-			parent: $('section.identity')
-			el: $('section.identity').find('h1 img')
-			# el: $('canvas')
-			radius: 3
-			onComplete: (_this)->
-				console.log 'complete'
-		}
-		console.log blurFx
-
-		for hash in blurFx.blurryEl
-			do (hash)->
-				console.log '__'+hash
-				console.log $('*[blurry-id="'+hash+'"]')
-		# for hash in blurFx.usedHashes
-		# elI = 0
-		# for el in blurFx.options.el
-		# 	do (el)=>
-		# 		# console.log el.src
-		# 		# console.log blurFx.sharpEl[el.dataset.blurryId] is blurFx.blurryEl[el.dataset.blurryId]
-		# 		# data = blurFx.hashTable.get el.dataset.blurryId
-		# 		# hashtable = new Hashtable
-		# 		# hashtable.put 'a', 'b'
-		# 		# data = hashtable.get 'a'
-		# 		data = blurFx.blurryEl[el.dataset.blurryId]
-		# 		el.src = data
-		# 		elI++
-		# #for canvas in $('img')
-		# 	#c = document.createElement 'canvas'
-		# 	#$(canvas.parentElement).append c
-		# 	#canvas = querySelector(canvas)
-		# 	#Pixastic.process(canvas, "blur", {amount:0.5})
-		# #$(canvas).pixastic("blur", {amount:1}) for canvas in $('canvas')+  $('body').waitForImages ()=>
+    blurFx = new Blurry {
+      replaceWithCanvas: true
+      parent: $('section.identity')
+      el: $('section.identity').find('h1 img')
+      # el: $('canvas')
+      radius: 3
+      onComplete: (_this)->
+        console.log 'complete'
+    }
+    console.log blurFx


use rootPath of active server as projectRoot. refs #61

--- lib/atom-ternjs-helper.coffee
+++ lib/atom-ternjs-helper.coffee
@@ -28,14 +28,15 @@
     @manager = manager

   hasTernProjectFile: ->
-    @projectRoot = atom.project.getDirectories()[0]
+    return false if !@manager.server
+    @projectRoot = @manager.server.rootPath
     return undefined unless @projectRoot
-    return true if @fileExists(path.resolve(__dirname, @projectRoot.path + '/.tern-project')) is undefined
+    return true if @fileExists(path.resolve(__dirname, @projectRoot + '/.tern-project')) is undefined
     return false

   createTernProjectFile: ->
     return unless @hasTernProjectFile() is false
-    @writeFile(path.resolve(__dirname, @projectRoot.path + '/.tern-project'))
+    @writeFile(path.resolve(__dirname, @projectRoot + '/.tern-project'))

   fileExists: (path) ->
     try fs.accessSync path, fs.F_OK, (err) =>


fixed lint error

fixed lint error

--- src/components/exercise.cjsx
+++ src/components/exercise.cjsx
@@ -108,7 +108,10 @@
     preview = <Preview exercise={exercise} closePreview={@closePreview}/>

     if ExerciseStore.isPublished(id)
-      publishedLabel =
Published: {ExerciseStore.getPublishedDate(id)}

+      publishedLabel =
+

+          Published: {ExerciseStore.getPublishedDate(id)}
+

     else
       form = @renderForm(id)


bug fix

bug fix

err check on account.updatecounts

--- workers/social/lib/social/models/account.coffee
+++ workers/social/lib/social/models/account.coffee
@@ -807,6 +807,7 @@
       targetId   : @getId()
       sourceName : $in: likeableActivities
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.likes': count), ->

     # Member Following count
@@ -815,6 +816,7 @@
       targetId   : @getId()
       sourceName : 'JAccount'
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.following': count), ->

     # Member Follower count
@@ -823,6 +825,7 @@
       sourceId   : @getId()
       sourceName : 'JAccount'
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.followers': count), ->

     # Tag Following count
@@ -831,6 +834,7 @@
       targetId   : @getId()
       sourceName : 'JTag'
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.topics': count), ->

     # Status Update count
@@ -839,6 +843,7 @@
       targetId   : @getId()
       sourceName : 'JNewStatusUpdate'
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.statusUpdates': count), ->

     # Comments count
@@ -847,12 +852,14 @@
       targetId   : @getId()
       sourceName : 'JNewStatusUpdate'
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.comments': count), ->

     # ReferredUsers count
     JAccount.count
       referrerUsername : @profile.nickname
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.referredUsers': count), ->

     # Invitations count
@@ -860,6 +867,7 @@
       username   : @profile.nickname
       invited    : true
     , (err, count)=>
+      return if err or not count
       @update ($set: 'counts.invitations': count), ->

     # Last Login date
@@ -867,6 +875,7 @@

     # Twitter follower count
     JUser.one {username: @profile.nickname}, (err, user)->
+      return if err or not user
       if user.foreignAuth?.twitter?
         followerCount = user.foreignAuth.twitter.profile.followers_count
         @update ($set: 'counts.twitterFollowers': followerCount), ->


added missing originalFsPath

added missing originalFsPath

--- services/filestore/app/coffee/FileHandler.coffee
+++ services/filestore/app/coffee/FileHandler.coffee
@@ -47,10 +47,12 @@

 	_getConvertedFileAndCache: (bucket, key, convertedKey, opts, callback)->
 		convertedFsPath = ""
+		originalFsPath = ""
 		async.series [
 			(cb) =>
 				@_convertFile bucket, key, opts, (err, fileSystemPath, originalFsPath) ->
 					convertedFsPath = fileSystemPath
+					originalFsPath = originalFsPath
 					cb err
 			(cb)->
 				ImageOptimiser.compressPng convertedFsPath, cb


revert advanced since we fixed coauth bug

--- demo/scripts/advanced.coffee
+++ demo/scripts/advanced.coffee
@@ -92,9 +92,10 @@
 listenEditor = (source, target) ->
   source.on(Scribe.Editor.events.USER_TEXT_CHANGE, (delta) ->
     console.info source.id, 'text change', delta if console?
-    setTimeout( ->
-      target.applyDelta(delta)
-    , 2500)
+    target.applyDelta(delta)
+    sourceDelta = source.doc.toDelta()
+    targetDelta = target.doc.toDelta()
+    console.assert(sourceDelta.isEqual(targetDelta), "Editor diversion!", source, target, sourceDelta, targetDelta) if console?
   ).on(Scribe.Editor.events.SELECTION_CHANGE, (range) ->
     if range?
       console.info source.id, 'selection change', range.start.index, range.end.index if console?


include latter part

include latter part

--- scripts/kintai.coffee
+++ scripts/kintai.coffee
@@ -23,7 +23,7 @@
     else
       msg.reply "#{kintaiId}\r\nなんにもないよー"

-  robot.respond /(.*(?:出勤|退勤))/i, (msg) ->
+  robot.respond /(.*(?:出勤|退勤).*)/i, (msg) ->
     user = msg.message.user.name
     date = moment()
     remarks = msg.match[1]


EventEmitter: an unused ancient method removed upon @wookiehangover's comment

--- src/core/eventemitter.coffee
+++ src/core/eventemitter.coffee
@@ -11,13 +11,6 @@
 #     ' to increase limit.', n

 module.exports = class KDEventEmitter
-
-  # FIXME (sb) - this class has no knowledge of @Wildcard (and requiring it
-  # would make a circular dependency). Also, this doesn't appear to be used
-  # anywhere in the framework.
-  @registerWildcardEmitter = ->
-    source = @Wildcard.prototype
-    @::[prop] = val  for own prop, val of source when prop isnt 'constructor'

   @registerStaticEmitter = ->
     # static listeners will be put here


fetch resources for cpu usage calculation after fetch

should call the second resource fetch after initial resourced are
fetched, where then the state is set so resources are only fetched
again during future refresh calls

--- SingularityUI/app/controllers/TaskDetail.coffee
+++ SingularityUI/app/controllers/TaskDetail.coffee
@@ -82,13 +82,6 @@

         app.showView @view

-        #  Refresh once again on page load to calculate initial CPU Usage value
-        @initialPageLoad = true
-        if @initialPageLoad
-            setTimeout (=>
-                @refresh()
-                @initialPageLoad = false
-            ), 2000

     fetchResourceUsage: ->
         @models.resourceUsage?.fetch()
@@ -96,6 +89,10 @@
                 # Store current resource usage to compare against future resource usage
                 @models.resourceUsage.setCpuUsage() if @models.resourceUsage.get('previousUsage')
                 @models.resourceUsage.set('previousUsage', @models.resourceUsage.toJSON())
+
+                if not @resourcesFetched
+                    setTimeout (=> @fetchResourceUsage() ), 2000
+                    @resourcesFetched = true

             .error =>
                 # If this 404s there's nothing to get so don't bother
@@ -103,6 +100,8 @@
                 delete @models.resourceUsage

     refresh: ->
+        @resourcesFetched = false
+
         @models.task.fetch()
             .done =>
                 @fetchResourceUsage() if @models.task.get('isStillRunning')


mov: Change the option name `--polling` to `--watch-polling`, and only leaves the long option name. opt: Optimize the comment of the `--watch-polling` option.

--- command.coffee
+++ command.coffee
@@ -34,24 +34,24 @@

 # The list of all the valid option flags that `coffee` knows how to handle.
 SWITCHES = [
-  ['-b', '--bare',            'compile without a top-level function wrapper']
-  ['-c', '--compile',         'compile to JavaScript and save as .js files']
-  ['-e', '--eval',            'pass a string from the command line as input']
-  ['-h', '--help',            'display this help message']
-  ['-i', '--interactive',     'run an interactive CoffeeScript REPL']
-  ['-j', '--join [FILE]',     'concatenate the source CoffeeScript before compiling']
-  ['-m', '--map',             'generate source map and save as .map files']
-  ['-n', '--nodes',           'print out the parse tree that the parser produces']
-  [      '--nodejs [ARGS]',   'pass options directly to the "node" binary']
-  [      '--no-header',       'suppress the "Generated by" header']
-  ['-o', '--output [DIR]',    'set the output directory for compiled JavaScript']
-  ['-p', '--print',           'print out the compiled JavaScript']
-  ['-s', '--stdio',           'listen for and compile scripts over stdio']
-  ['-l', '--literate',        'treat stdio as literate style coffee-script']
-  ['-t', '--tokens',          'print out the tokens that the lexer/rewriter produce']
-  ['-v', '--version',         'display the version number']
-  ['-w', '--watch',           'watch scripts for changes and rerun commands']
-  ['-g', '--polling [SPAN]',  'use the state polling watch mode']
+  ['-b', '--bare',                  'compile without a top-level function wrapper']
+  ['-c', '--compile',               'compile to JavaScript and save as .js files']
+  ['-e', '--eval',                  'pass a string from the command line as input']
+  ['-h', '--help',                  'display this help message']
+  ['-i', '--interactive',           'run an interactive CoffeeScript REPL']
+  ['-j', '--join [FILE]',           'concatenate the source CoffeeScript before compiling']
+  ['-m', '--map',                   'generate source map and save as .map files']
+  ['-n', '--nodes',                 'print out the parse tree that the parser produces']
+  [      '--nodejs [ARGS]',         'pass options directly to the "node" binary']
+  [      '--no-header',             'suppress the "Generated by" header']
+  ['-o', '--output [DIR]',          'set the output directory for compiled JavaScript']
+  ['-p', '--print',                 'print out the compiled JavaScript']
+  ['-s', '--stdio',                 'listen for and compile scripts over stdio']
+  ['-l', '--literate',              'treat stdio as literate style coffee-script']
+  ['-t', '--tokens',                'print out the tokens that the lexer/rewriter produce']
+  ['-v', '--version',               'display the version number']
+  ['-w', '--watch',                 'watch scripts for changes and rerun commands']
+  [      '--watch-polling [SPAN]',  'use the state polling watch mode, span unit is millisecond']
 ]

 # Top-level objects shared by all the functions.


throwing errs from fs.readFile in watch mode.

--- command.coffee
+++ command.coffee
@@ -134,7 +134,9 @@
 watch = (source, base) ->
   fs.watchFile source, {persistent: true, interval: 500}, (curr, prev) ->
     return if curr.mtime.getTime() is prev.mtime.getTime()
-    fs.readFile source, (err, code) -> compileScript(source, code.toString(), base)
+    fs.readFile source, (err, code) ->
+      throw err if err
+      compileScript(source, code.toString(), base)

 # Write out a JavaScript source file with the compiled code. By default, files
 # are written out in `cwd` as `.js` files with the same name, but the output


welp, maybe we should send up the right data...

--- command.coffee
+++ command.coffee
@@ -19,7 +19,7 @@
     @search @query(), (error, result) =>
       throw error if error?

-      connectors = @process @normalize result
+      connectors = @normalize result
       async.each connectors, @update, (error) =>
         throw error if error?
         console.log "it's done...maybe?"
@@ -46,7 +46,7 @@
       pathname: "/gateblu_device_add_history/event/#{connector.connector}"

     console.log "updating with connector...", connector
-
+
     request.put uri, json: connector, (error, response, body) =>
       return callback error if error?
       return callback new Error(JSON.stringify body) if response.statusCode >= 300
@@ -63,33 +63,11 @@
   normalize: (result) =>
     buckets = result.aggregations.addGatebluDevice.group_by_connector.buckets
     _.map buckets, (bucket) =>
-      {
-        connector: bucket.key
-        beginTime: bucket.beginRecord.beginTime.value
-        endTime:   bucket.endRecord.endTime.value
-        workflow: 'device-add-to-gateblu'
-      }
-
-  process: (connectors) =>
-    _.map connectors, (connector) =>
-      {workflow, connector, beginTime, endTime} = connector
-
-      formattedBeginTime = null
-      formattedBeginTime = moment(beginTime).toISOString() if beginTime?
-      formattedEndTime = null
-      formattedEndTime = moment(endTime).toISOString() if endTime?
-
-      elapsedTime = null
-      elapsedTime = endTime - beginTime if beginTime? && endTime?
-
-      {
-        connector: connector
-        workflow: workflow
-        beginTime: formattedBeginTime
-        endTime: formattedEndTime
-        elapsedTime: elapsedTime
-        success: endTime?
-      }
+      connector: bucket.key
+      workflow: 'device-add-to-gateblu'
+      total: bucket.beginRecord.doc_count
+      successes: bucket.endRecord.doc_count
+      failures: bucket.beginRecord.doc_count - bucket.endRecord.doc_count

 command = new Command()
 command.run()


Use fs.realpathSync instead of something hacky.

--- command.coffee
+++ command.coffee
@@ -47,7 +47,6 @@
 options      = {}
 sources      = []
 optionParser = null
-localPath    = /^.\//

 # Run `coffee` by parsing passed options and determining what action to take.
 # Many flags cause us to divert before compiling anything. Flags passed after
@@ -97,7 +96,7 @@
   o = options
   codeOpts = compileOptions source
   if o.require
-    require file.replace(localPath, process.cwd() + '/') for file in o.require
+    require fs.realpathSync file for file in o.require
   try
     CoffeeScript.emit 'compile', {source, code, base, options}
     if      o.tokens      then printTokens CoffeeScript.tokens code


Teamwork: Names for split views.

Teamwork: Names for split views.

--- client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkapp.coffee
+++ client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkapp.coffee
@@ -27,6 +27,7 @@
         layout            :
           direction       : "vertical"
           sizes           : [ "25%", null ]
+          splitName       : "BaseSplit"
           views           : [
             {
               type        : "finder"
@@ -36,7 +37,8 @@
               type        : "split"
               options     :
                 direction : "horizontal"
-                sizes     : [ "50%", null ]
+                sizes     : [ "100%", null ]
+                splitName : "InnerSplit"
               views       : [
                 {
                   type    : "tabbedEditor"


Fix typo

Fix typo

--- server/materials/data/topics/two_pointers.coffee
+++ server/materials/data/topics/two_pointers.coffee
@@ -19,7 +19,7 @@
                 s:=s+a[j]; // в переменной s подсчитываем текущую сумму
                 if s>k then begin
                     // writeln(j); // этот вывод пригодится дальше
-                    if j-i+1>min then min:=j-i+1;
+                    if j-i+1<min then min:=j-i+1;
                     break;
                 end;
             end;
@@ -34,7 +34,7 @@
             for j:=j to n do begin // цикл начинается с j!
                 s:=s+a[j];
                 if s>k then begin
-                    if j-i+1>min then min:=j-i+1;
+                    if j-i+1<min then min:=j-i+1;
                     break;
                 end;
             end;
@@ -135,4 +135,4 @@
             problem(994),
             problem(2817),
         ]
-    }+    }


add logging for ASpell worker errors

add logging for ASpell worker errors

--- services/spelling/app/coffee/ASpellWorker.coffee
+++ services/spelling/app/coffee/ASpellWorker.coffee
@@ -17,10 +17,14 @@
 			metrics.inc "aspellWorker-exit-" + @language
 		@pipe.on 'error', (err) =>
 			@state = 'error'
-			@callback err, []
+			logger.log process: @pipe.pid, error: err, stdout: output, stderr: error, lang: @language, "aspell worker error"
+			if @callback?
+				@callback err, []
 		@pipe.stdin.on 'error', (err) =>
 			@state = 'error'
-			@callback err, []
+			logger.log process: @pipe.pid, error: err, stdout: output, stderr: error, lang: @language, "aspell worker error on stdin"
+			if @callback?
+				@callback err, []

 		output = ""
 		@pipe.stdout.on "data", (chunk) =>


Specify bigger timeout for loading scripts via RequireJS

--- scripts/themis.coffee
+++ scripts/themis.coffee
@@ -1,4 +1,5 @@
 require.config
+    waitSeconds: 20
     paths:
         jquery: [
             'http://code.jquery.com/jquery-2.1.3.min'


Correct R H O to RHO, etc.

Correct R H O to RHO, etc.

--- dist/gae/scripts/view.coffee
+++ dist/gae/scripts/view.coffee
@@ -735,7 +735,11 @@
 class RuleName extends HTMLDivElement
     constructor: (@ruleName) ->
         @className = 'rule_name'
-        @textContent = @ruleName.replace(/([A-Z])/g, " $1")
+        @ruleName = @ruleName.replace(/([A-Z])/g, " $1")
+        # A couple exceptions to the spacing rules:
+        @ruleName = @ruleName.replace(/R H O/g, "RHO")
+        @ruleName = @ruleName.replace(/L H O/g, "LHO")
+        @textContent = @ruleName

     @fromRuleName: (ruleName) ->
         return alloc @, ruleName


Prefent page scroll when scrolling the dropdown by mouse wheel

--- vendor/assets/javascripts/chosen/chosen.js.coffee
+++ vendor/assets/javascripts/chosen/chosen.js.coffee
@@ -206,6 +206,7 @@

     @$dropdown.bind "mouseover", "li.chosen-option", (evt) => @dropdown_mouseover(evt)
     @$dropdown.bind "mousedown", "li.chosen-option", (evt) => @dropdown_mousedown(evt)
+    @$dropdown.bind "mousewheel DOMMouseScroll", (evt) => @prevent_page_scroll(evt)

     @$container.addClass("opened")
     @$dropdown.addClass("opened")
@@ -217,7 +218,7 @@

     @$container.removeClass("opened")
     @$dropdown.removeClass("opened")
-    @$dropdown.unbind "mouseover mousedown"
+    @$dropdown.unbind "mouseover mousedown mousewheel DOMMouseScroll"
     @$dropdown.remove()
     @opened = false

@@ -256,6 +257,14 @@

     evt.preventDefault()
     evt.stopImmediatePropagation()
+    return
+
+  prevent_page_scroll: (evt) ->
+    delta = evt.originalEvent.wheelDelta || -evt.originalEvent.detail
+
+    if (delta < 0 and @$dropdown.$list[0].scrollHeight - @$dropdown.scrollTop() == @$dropdown.innerHeight()) or (delta > 0 and @$dropdown.scrollTop() == 0)
+      evt.preventDefault()
+
     return

   keydown: (evt) ->


filter for only valid semvers

filter for only valid semvers

--- rodeo-versions.coffee
+++ rodeo-versions.coffee
@@ -36,7 +36,8 @@
     data.Contents.map (obj) ->
       v = obj.Key.split('/')[0]
       if v not in versions
-        versions.push v
+        if semver.valid(v)
+          versions.push v

     versions = versions.sort(semver.rcompare)
     versions = versions.map generateVersion


utils: add a splitTrim method for sanitizing user input

--- core/utils.coffee
+++ core/utils.coffee
@@ -355,6 +355,10 @@

     return "#{minus}#{bytes.toFixed 2} #{units[unitIndex]}"

+  splitTrim: (str, delim = ',', filterEmpty = yes) ->
+    arr = (str?.split(delim).map (part) -> do part.trim) ? []
+    arr = arr.filter Boolean  if filterEmpty
+    return arr
 ###
 //     Underscore.js 1.3.1
 //     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.


Fix inappropriate cron job

Fix inappropriate cron job

--- scripts/yamada.coffee
+++ scripts/yamada.coffee
@@ -181,6 +181,6 @@
           robot.send {room: ch}, message
   , null, true, "Asia/Tokyo"

-  new cron '00 30 17 * * *', () =>
+  new cron '00 30 17 * * 1-5', () =>
     robot.send {room: "#general"}, "社畜の通過点"
   , null, true, "Asia/Tokyo"


Further error handling in Box.create

Further error handling in Box.create

--- server/code/model/box.coffee
+++ server/code/model/box.coffee
@@ -123,6 +123,8 @@
       server: server

     box.save (err) ->
+      if err?
+        return callback err, null
       # The URI we need should have "box" between the server name and the
       # box name. Bit tricky to do. :todo: make better (by fixing cobalt?).
       uri = "#{Box.endpoint server, boxName}"
@@ -137,6 +139,8 @@
           apikey: user.apiKey
           uid: box.uid
       , (err, res, body) ->
+        if err?
+          return callback err, null
         jsonResponse = JSON.parse body
         if 'error' of jsonResponse
           return callback jsonResponse.error, null


grunt-notify の表示修正

grunt-notify の表示修正

--- root/Gruntfile.coffee
+++ root/Gruntfile.coffee
@@ -312,9 +312,9 @@
       'jsonlint'
     ]
     watcher: [
+      'notify:watch'
       'connect'
       'watch'
-      'notify:watch'
     ]
     default: [
       'css'


Handle status=0 (h2o down/busy) during xhr

--- src/ext/modules/proxy.coffee
+++ src/ext/modules/proxy.coffee
@@ -4,7 +4,12 @@
       .done (data, status, xhr) ->
         go null, data
       .fail (xhr, status, error) ->
-        message = xhr.responseJSON?.errmsg or 'Unknown error'
+        message = if xhr.responseJSON?.errmsg
+          xhr.responseJSON.errmsg
+        else if status is 0
+          'Could not connect to H2O'
+        else
+          'Unknown error'
         go new Flow.Error message, new Flow.Error "Error calling GET #{path}"

   doPost = (path, opts, go) ->
@@ -12,7 +17,12 @@
       .done (data, status, xhr) ->
         go null, data
       .fail (xhr, status, error) ->
-        message = xhr.responseJSON?.errmsg or 'Unknown error'
+        message = if xhr.responseJSON?.errmsg
+          xhr.responseJSON.errmsg
+        else if status is 0
+          'Could not connect to H2O'
+        else
+          'Unknown error'
         go new Flow.Error message, new Flow.Error "Error calling POST #{path} with opts #{JSON.stringify opts}"

   mapWithKey = (obj, f) ->


Attempting to clean up action handling

Attempting to clean up action handling

--- server/express/server.coffee
+++ server/express/server.coffee
@@ -123,22 +123,22 @@
     console.log page.story if opt.debug
     page.story = switch action.type
       when 'move'
-        _(action.order).chain()
-          .map((i) ->
-            _(page.story).find( (item) ->
-              i is item.id
-            )
-          ).value()
+        _(action.order).map((i) ->
+          _(page.story).find( (story) ->
+            console.log i, story
+            i is story.id
+          )
+        )

       when 'add'
-        _(page.story).chain()
-          .map( (i) ->
-            if i.id is action.after
-              [i, action.item]
-            else
-              i
-          ).flatten()
-          .value()
+        before = -1
+        for i in page.story
+          if i.id = action.after
+            before = page.story.indexOf(i)
+        before += 1
+        page.story.splice(before, 0, action.item)
+        page.story
+

       when 'remove'
         _(page.story).reject( (i) ->
@@ -147,10 +147,10 @@

       when 'edit'
         _(page.story).map( (i) ->
-            if i.id is action.id
-              action.item
-            else
-              i
+          if i.id is action.id
+            action.item
+          else
+            i
         )

       else


Fix #558

Fix #558

--- src/lib/interfaces/console.coffee
+++ src/lib/interfaces/console.coffee
@@ -2,6 +2,7 @@
 pathUtil = require('path')
 balUtil = require('bal-util')
 safefs = require('safefs')
+safeps = require('safeps')
 {TaskGroup} = require('taskgroup')
 extendr = require('extendr')


Moved the server import into the before_all, and changed the request to use localhost for now. In the future i'll work something out to work on both normal runtimes, and cloud9.

--- test/api/tests.coffee
+++ test/api/tests.coffee
@@ -12,17 +12,20 @@

 describe 'Test Submission', ->
-  server = require '../../lib/server'
+  server = undefined

   before_all (done) ->
+    server = require '../../lib/server'
     server.main.start undefined, done

   it 'should something', (done) ->

     http = require 'http'
     opts =
-      host: 'cling.leeolayvar.c9.io',
-      port: 80
+      #host: 'cling.leeolayvar.c9.io'
+      #port: 80
+      host: 'localhost'
+      port: 3003
       path: '/'
       method: 'GET'


Move update or create as a common layer ; deactivate edelia.

--- server/konnectors/edf.coffee
+++ server/konnectors/edf.coffee
@@ -561,7 +561,7 @@

                 return bill

-            entries.bills = bills
+            entries.bill = bills
             K.logger.info "Fetched #{bills.length} bills"
             callback()
         catch e
@@ -571,7 +571,7 @@

 fetchVisualiserHistoConso = (requiredFields, entries, data, callback) ->
     K.logger.info "fetchVisualiserHistoConso"
-    async.mapSeries entries.contracts, (contract, cb) ->
+    async.mapSeries entries.contract, (contract, cb) ->
         path = '/ws/visualiserHistoConso_rest_V3-0/invoke'
         body =
             'message:msgRequete':
@@ -690,7 +690,7 @@
             jeton_sso: data.edfToken
             bp: entries.clients[0].clientId
             # TODO : one procedure per contract !!!
-            pdl: entries.contracts[0].pdl
+            pdl: entries.contract[0].pdl
         json: true
     , (err, response, result) ->
         if err
@@ -700,7 +700,7 @@

         K.logger.info 'Fetched edelia token'
         data.edeliaToken = result.access_token
-        data.contract = entries.contracts[0]
+        data.contract = entries.contract[0]
         callback()

@@ -737,7 +737,7 @@
                 sanitoryHotWaterType: obj.sanitoryHotWaterType
                 docTypeVersion: K.docTypeVersion

-            entries.homes.push doc
+            entries.home.push doc
             K.logger.info 'Fetched fetchEdeliaProfile'

         catch e
@@ -1175,6 +1175,7 @@

     fetchOperations: [
         prepareEntries
+
         getEDFToken
         fetchListerContratClientParticulier
         fetchVisualiserPartenaire


Support SWITCH

Support SWITCH

--- src/formula/evaluator.coffee
+++ src/formula/evaluator.coffee
@@ -1035,6 +1035,20 @@
       sum += num*num
     sum

+
+  SWITCH: (args)->
+    @checkArgumentSize(args, 3, Number.MAX_VALUE)
+    args = @expandRange(TYPE_ANY, args)
+    if args.length % 2 == 1
+      @error(FormulaError.NA)
+
+    x = args[0]
+    for y,i in args when i % 2 == 1
+      if x == y
+        return args[i+1]
+    args[args.length-1]
+
+
   TAN: (args)->
     @checkArgumentSize(args, 1)
     Math.tan @expectNumber(args[0])


BufferDebugMixin: handle removed buffers

--- src/mixin/BufferDebugMixin.coffee
+++ src/mixin/BufferDebugMixin.coffee
@@ -32,6 +32,7 @@
   listenToBuffersEvents = ->
     for name, buffer of _bufferStats
       do (buffer) ->
+        return if !buffer.buffer
         buffer.buffer.on 'write', -> buffer.writes++
         buffer.buffer.on 'release', -> buffer.releases++


clampable

clampable

--- test/clampable.coffee
+++ test/clampable.coffee
@@ -12,7 +12,7 @@
       max: max

   o.update()
-
+
   equals o.I.x, max

 # Clear out the module


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/collision.coffee
+++ test/collision.coffee
@@ -47,6 +47,6 @@
   Collision.collide player, [enemy, enemy2], (p, e) ->
     ok(true)

-
+test ""
 module()


Jokes on me, mouse events are also being passed.

--- picoCTF-web/web/coffee/management-settings.coffee
+++ picoCTF-web/web/coffee/management-settings.coffee
@@ -124,7 +124,7 @@
         admin_emails: @state.admin_emails
       email_filter: @state.email_filter

-    if makeChange
+    if typeof(makeChange) == "function"
       pushData = makeChange pushData

     apiCall "POST", "/api/admin/settings/change", {json: JSON.stringify(pushData)}


fixes feed description extraction

fixes feed description extraction

--- src/javascripts/feed.coffee
+++ src/javascripts/feed.coffee
@@ -13,7 +13,9 @@
       @extract('itunes\\:subtitle').html()
     @href = @extract('link').html()
     @enclosure = @mapEnclosure()
-    @description = @extract('description').html()
+    @description = @extract('description')
+      .html()
+      .match(/<!\[CDATA\[([\s\S]*)]]>$/)[1]

   extract: (elemName) =>
     @[elemName] ?= $(@xml).find(elemName)


End refactoring

End refactoring

--- flow.coffee
+++ flow.coffee
@@ -12,14 +12,15 @@
   # Motion

   show: (query) ->
-    @slide = @getSlide(query)
-    @slides().hide().filter(@slide).show()
+    @slide = @_getSlide(query)
+    @slides().hide()
+    @slide.show()

   next: ->
-    @show @getNextSlidePosition()
+    @show @_getNextSlidePosition()

   prev: ->
-    @show @getPrevSlidePosition()
+    @show @_getPrevSlidePosition()

   first: ->
     @show 0
@@ -32,29 +33,28 @@
   size: ->
     @slides().size()

-  getCurrentSlidePosition: (element = @slide) ->
-    slide = element
-    currentIndex = -1
-    $.each @slides(), (index) ->
-      if slide.get(0) is this
-        currentIndex = index
-    currentIndex
+  _getCurrentSlidePosition: (slide = @slide) ->
+    currentPosition = -1
+    $.each @slides(), (index, element) ->
+      if slide.get(0) is element
+        currentPosition = index
+    currentPosition

-  getNextSlidePosition: ->
-    currentIndex = @getCurrentSlidePosition()
-    index = if currentIndex + 1 is @size() then 0 else currentIndex + 1
+  _getNextSlidePosition: ->
+    currentPosition = @_getCurrentSlidePosition()
+    if currentPosition + 1 is @size() then 0 else currentPosition + 1

-  getPrevSlidePosition: ->
-    currentIndex = @getCurrentSlidePosition()
-    index = if currentIndex is 0 then @size() - 1 else currentIndex - 1
+  _getPrevSlidePosition: ->
+    currentPosition = @_getCurrentSlidePosition()
+    if currentPosition is 0 then @size() - 1 else currentPosition - 1

-  getSlide: (query) ->
+  _getSlide: (query) ->
     if $.isNumeric(query)
-      @slide = @slides().eq(query)
+      @slides().eq(query)
     else if toString.call(query) is '[object String]'
-      @slide = @slides().filter(query)
+      @slides().filter(query)
     else
-      @slide = query
+      query

   # DOM manipulation

@@ -74,13 +74,13 @@
     @show @slide

   replace: (position, slideHtml) ->
-    slide = if @getCurrentSlidePosition() is position then position else @slide
+    slide = if @_getCurrentSlidePosition() is position then position else @slide
     @slides().eq(position).before(slideHtml).remove()
     @show slide

   delete: (position) ->
-    if @getCurrentSlidePosition() is position
-      slide = if @size() - 1 is position then 0 else @getCurrentSlidePosition()
+    if @_getCurrentSlidePosition() is position
+      slide = if @size() - 1 is position then 0 else @_getCurrentSlidePosition()
     else
       slide = @slide
     @slides().eq(position).remove()


adjusting the hipster glasses mapping

adjusting the hipster glasses mapping

--- mapping.coffee
+++ mapping.coffee
@@ -2,8 +2,8 @@

 module.exports =
   hipster: affine (face) -> [
-    [36, 32, face.eye_left.x, face.eye_left.y]
-    [96, 32, face.eye_right.x, face.eye_right.y]
+    [128, 60, face.eye_left.x, face.eye_left.y]
+    [329, 60, face.eye_right.x, face.eye_right.y]
   ]

   mustache: affine (face) -> [


Replace the scary assertions with deepEqual.

--- test/migration.coffee
+++ test/migration.coffee
@@ -162,23 +162,21 @@

 exports[NS].migrate =
 	'should perform some or all migratons': t ->
-		migration.migrate.sync null, conn, {dest_revision: 1}
+		migration.migrate.sync null, conn, { dest_revision: 1 }

 		rows = query.all 'SELECT column_name, data_type FROM information_schema.columns ' +
 			"WHERE table_name = 'test_table' ORDER BY column_name"
+		test.deepEqual rows, [
+			{ column_name: 'col0', data_type: 'box' }
+			{ column_name: 'col1', data_type: 'macaddr' }
+			{ column_name: 'id', data_type: 'integer' }
+		], 'should correctly perform part of migrations'
+
 		orows = query.all 'SELECT column_name, data_type FROM information_schema.columns ' +
 			"WHERE table_name = 'other_table' ORDER BY column_name"
-		test.ok rows.length is 3 and
-			rows[0].column_name is 'col0' and
-			rows[1].column_name is 'col1' and
-			rows[2].column_name is 'id' and
-			rows[0].data_type is 'box' and
-			rows[1].data_type is 'macaddr' and
-			rows[2].data_type is 'integer' and
-			orows.length is 1 and
-			orows[0].column_name is 'id' and
-			orows[0].data_type is 'integer',
-			'should correctly perform part of migrations'
+		test.deepEqual orows, [
+			{ column_name: 'id', data_type: 'integer' }
+		], 'should correctly perform part of migrations'

 		revision = migration.getCurrentRevision.sync null, conn
 		test.strictEqual revision, 1, 'should set correct revision'
@@ -188,23 +186,19 @@

 		rows = query.all 'SELECT column_name, data_type FROM information_schema.columns ' +
 			"WHERE table_name = 'test_table' ORDER BY column_name"
+		test.deepEqual rows, [
+			{ column_name: 'col0', data_type: 'box' }
+			{ column_name: 'col1', data_type: 'macaddr' }
+			{ column_name: 'col2', data_type: 'bigint' }
+			{ column_name: 'id', data_type: 'integer' }
+		], 'should correctly perform all remaining migrations'
+
 		orows = query.all 'SELECT column_name, data_type FROM information_schema.columns ' +
 			"WHERE table_name = 'other_table' ORDER BY column_name"
-		test.ok rows.length is 4 and
-			rows[0].column_name is 'col0' and
-			rows[1].column_name is 'col1' and
-			rows[2].column_name is 'col2' and
-			rows[3].column_name is 'id' and
-			rows[0].data_type is 'box' and
-			rows[1].data_type is 'macaddr' and
-			rows[2].data_type is 'bigint' and
-			rows[3].data_type is 'integer' and
-			orows.length is 2 and
-			orows[0].column_name is 'col0' and
-			orows[1].column_name is 'id' and
-			orows[0].data_type is 'lseg' and
-			orows[1].data_type is 'integer',
-			'should correctly perform all remaining migrations'
+		test.deepEqual orows, [
+			{ column_name: 'col0', data_type: 'lseg' }
+			{ column_name: 'id', data_type: 'integer' }
+		], 'should correctly perform all remaining migrations'

 		revision = migration.getCurrentRevision.sync null, conn
 		test.strictEqual revision, 3, 'should set correct revision'


Made revision to regex to prevent time input like '8:251m', even though it works correctly


Fix FocusedAccountStore: remove unnecessary accountstore listener

--- src/flux/stores/focused-perspective-store.coffee
+++ src/flux/stores/focused-perspective-store.coffee
@@ -11,7 +11,6 @@
     @_current = @_defaultPerspective()

     @listenTo CategoryStore, @_onCategoryStoreChanged
-    @listenTo AccountStore, @_onAccountStoreChanged

     @listenTo Actions.focusMailboxPerspective, @_onFocusPerspective
     @listenTo Actions.focusDefaultMailboxPerspectiveForAccounts, @_onFocusAccounts
@@ -19,9 +18,6 @@
     @_onCategoryStoreChanged()

   # Inbound Events
-
-  _onAccountStoreChanged: ->
-    @_setupFastAccountMenu()

   _onCategoryStoreChanged: ->
     if @_current.isEqual(MailboxPerspective.forNothing())


Fix CoffeeScript error/warning.

Fix CoffeeScript error/warning.

--- src/jpeg_camera_html5.coffee
+++ src/jpeg_camera_html5.coffee
@@ -104,7 +104,7 @@
       # XXX In an older spec first parameter was a string
       try
         navigator.getUserMedia get_user_media_options, success, failure
-      catch
+      catch error
         navigator.getUserMedia "video", success, failure

     _engine_play_shutter_sound: ->


add diamondtree performance test fixture

--- performance/PerformanceTest.coffee
+++ performance/PerformanceTest.coffee
@@ -51,6 +51,13 @@
 suite = new Benchmark.Suite

 cases = {
+  'diamondtree': ->
+    f.withGenerator(((gen) ->
+      tree = f.diamond(gen.stream(), 1, 100)
+      s = f.diamond(tree, 3, 5)
+      s.onValue ->
+      s
+    ),1)
   'diamond': ->
     f.withGenerator(((gen) ->
       s = f.diamond(gen.stream(), 3, 5)


re-enable killing connections that take forever

--- salvus/rethink.coffee
+++ salvus/rethink.coffee
@@ -104,8 +104,8 @@
             driver   : 'native'    # dash or native
             pool     : if process.env.DEVEL then 1 else 100  # default number of connection to use in connection pool with native driver
             all_hosts: false      # if true, finds all hosts based on querying the server then connects to them
-            warning  : 30           # display warning and stop using connection if run takes this many seconds or more
-            error    : 0            # kill any query that takes this long (and corresponding connection)
+            warning  : 30          # display warning and stop using connection if run takes this many seconds or more
+            error    : 10*60       # kill any query that takes this long (and corresponding connection)
             concurrent_warn : 500  # if number of concurrent outstanding db queries exceeds this number, put a concurrent_warn message in the log.
             cb       : undefined
         dbg = @dbg('constructor')


rethink: only allow one _update_pool at a time; make various reconnects less aggressive

--- salvus/rethink.coffee
+++ salvus/rethink.coffee
@@ -172,16 +172,16 @@
         cb()

     _connect: (cb) =>
-        #dbg = @dbg("_connect")
+        dbg = @dbg("_connect")
         hosts = misc.keys(@_hosts)
         host = misc.random_choice(hosts)
-        #dbg("connecting to #{host}...")
+        dbg("connecting to #{host}...")
         @r.connect {authKey:@_password,  host:host}, (err, conn) =>
             if err
-                #dbg("error connecting to #{host} -- #{to_json(err)}")
+                dbg("error connecting to #{host} -- #{to_json(err)}")
                 cb(err)
             else
-                #dbg("successfully connected to #{host}")
+                dbg("successfully connected to #{host}")
                 if not @_conn
                     first_conn = true
                     @_conn = {}  # initialize if not defined
@@ -214,6 +214,8 @@
                 winston.debug("created #{i} connections so far")
             misc.retry_until_success
                 f : @_connect
+                start_delay : 5000
+                max_delay   : 30000
                 cb : cb
         # first connect once (to get topology), then many more times in parallel
         g 0, () =>
@@ -222,18 +224,31 @@
                 cb(err)

     _update_pool: (cb) =>
+        if @_update_pool_cbs?
+            @_update_pool_cbs.push(cb)
+            return
+
+        @dbg("_update_pool")()
+        @_update_pool_cbs = [cb]
+
         # 1. remove any connections from the pool that aren't opened
         for id, conn of @_conn
             if not conn.isOpen()
                 delete @_conn[id]

         # 2. ensure that the pool is full
-        n = misc.len(@_conn)
-        if n >= @_num_connections
-            cb()
-        else
-             # fill the pool
-            async.map(misc.range(@_num_connections - n), ((n,cb)=>@_connect(cb)), cb)
+        f = (cb) =>
+            n = misc.len(@_conn)
+            if n >= @_num_connections
+                cb()
+            else
+                 # fill the pool
+                async.map(misc.range(@_num_connections - n), ((n,cb)=>@_connect(cb)), cb)
+
+        f (err) =>
+            for cb in @_update_pool_cbs
+                cb(err)
+            delete @_update_pool_cbs

     _monkey_patch_run: () =>
         # We monkey patch run to have similar semantics to rethinkdbdash, so that we don't have to change
@@ -337,10 +352,12 @@
                 # 'success' means that we got a connection to the database and made a query using it.
                 # It could still have returned an error.
                 misc.retry_until_success
-                    f         : f
-                    max_delay : 10000
-                    factor    : 1.3
-                    cb        : -> cb(error, result)
+                    f           : f
+                    max_delay   : 15000
+                    start_delay : 3000
+                    factor      : 1.4
+                    max_tries   : 15
+                    cb          : -> cb(error, result)

     table: (name, opts={readMode:'outdated'}) =>
         @db.table(name, opts)
@@ -2990,7 +3007,17 @@
                                             if err
                                                 cb(err)
                                             else
-                                                @table('projects').getAll(opts.account_id, index:'users').pluck('users').changes(includeStates: false, squash:3).run((err, feed) => killfeed = feed; cb(err))
+                                                @table('projects').getAll(opts.account_id, index:'users').pluck('users').changes(includeStates: false, squash:3).run (err, feed) =>
+                                                    if err
+                                                        e = misc.to_json(err)
+                                                        if e.indexOf("Did you just reshard?") != -1
+                                                            # give it time so we do not overload the server
+                                                            setTimeout((()=>cb(err)), 10000)
+                                                        else
+                                                            cb(err)
+                                                    else
+                                                        killfeed = feed
+                                                        cb()
                                     else
                                         cb()
                     else if x == "collaborators"
@@ -3014,7 +3041,17 @@
                                             if err
                                                 cb(err)
                                             else
-                                                @table('projects').getAll(opts.account_id, index:'users').pluck('users').changes(includeStates: false, squash:3).run((err, feed) =>killfeed = feed; cb(err))
+                                                @table('projects').getAll(opts.account_id, index:'users').pluck('users').changes(includeStates: false, squash:3).run (err, feed) =>
+                                                    if err
+                                                        e = misc.to_json(err)
+                                                        if e.indexOf("Did you just reshard?") != -1
+                                                            # give it time so we do not overload the server
+                                                            setTimeout((()=>cb(err)), 10000)
+                                                        else
+                                                            cb(err)
+                                                    else
+                                                        killfeed = feed
+                                                        cb()
                                     else
                                         cb()
                     else if typeof(x) == 'function'
@@ -3120,7 +3157,7 @@
                             winston.debug("FEED -- error setting up #{e}")
                             if e.indexOf("Did you just reshard?") != -1
                                 # give it time so we do not overload the server -- this happens when any auto-failover happens
-                                setTimeout((()=>cb(err)), 20000)
+                                setTimeout((()=>cb(err)), 10000)
                             else
                                 cb(err)
                         else


Add tests for 0 and 1 bytes filesize

Add tests for 0 and 1 bytes filesize

--- spec/filesize-calculator-spec.coffee
+++ spec/filesize-calculator-spec.coffee
@@ -23,6 +23,19 @@
         expect(size).toEqual(5)

   describe "when calling .makeReadable()", ->
+
+    describe "when size is 0", ->
+      it "should return 0 bytes", ->
+        filesizeCalculator.makeReadable 0, null, (size, err) ->
+          expect(err).toEqual(null)
+          expect(size).toEqual("0 bytes")
+
+    describe "when size is 1", ->
+      it "should return 1 byte", ->
+        filesizeCalculator.makeReadable 1, null, (size, err) ->
+          expect(err).toEqual(null)
+          expect(size).toEqual("1 byte")
+
     describe "when size < 1024 bytes", ->
       it "should display results in bytes when with 1024 multiple value", ->
         filesizeCalculator.makeReadable 1023, null, (size, err) ->


more making of replication less aggressive

--- salvus/storage.coffee
+++ salvus/storage.coffee
@@ -623,7 +623,7 @@
     opts = defaults opts,
         ttl     : 60*60*24  # time in seconds (up to a week)
         dry_run : true      # don't actually close the projects
-        limit   : 5         # number of projects to close simultaneously.
+        limit   : 2         # number of projects to close simultaneously.
         interval: 3000      # space out the project closing to give server a chance to do other things.
         unset_loc : false   # whether to unset the location field in the database after closing the project; if done, then projects will resume later on a random host (which is usually *NOT* desirable).
         cb      : required
@@ -2182,8 +2182,9 @@

 exports.replicate_projects_needing_replication = (opts) ->
     opts = defaults opts,
-        age_s     : 5*60  # 5 minutes
-        limit     : 10    # max number to replicate simultaneously
+        age_s     : 10*60  # 10 minutes
+        limit     : 2      # max number to replicate simultaneously
+        interval  : 3000
         cb        : required
     dbg = (m) -> winston.debug("replicate_projects_needing_replication: #{m}")
     projects = undefined
@@ -2209,7 +2210,7 @@
                         dbg("\n******************\n**** STATUS: finished #{done}/#{todo}\n**************")
                         if err
                             errors[project_id] = err
-                        cb()
+                        setTimeout(cb, opts.interval)
             async.mapLimit(projects, opts.limit, f, cb)
     ], (err) ->
         if err


Added ‘is’ and ‘isnt’ operators

Added ‘is’ and ‘isnt’ operators

--- src/liquid/condition.coffee
+++ src/liquid/condition.coffee
@@ -11,13 +11,15 @@
 #
 module.exports = class Condition
   @operators =
-    '==': (cond, left, right) ->  cond.equalVariables(left, right)
-    '!=': (cond, left, right) -> !cond.equalVariables(left, right)
-    '<>': (cond, left, right) -> !cond.equalVariables(left, right)
-    '<':  (cond, left, right) -> left < right
-    '>':  (cond, left, right) -> left > right
-    '<=': (cond, left, right) -> left <= right
-    '>=': (cond, left, right) -> left >= right
+    '==':   (cond, left, right) ->  cond.equalVariables(left, right)
+    'is':   (cond, left, right) ->  cond.equalVariables(left, right)
+    '!=':   (cond, left, right) -> !cond.equalVariables(left, right)
+    '<>':   (cond, left, right) -> !cond.equalVariables(left, right)
+    'isnt': (cond, left, right) ->  cond.equalVariables(left, right)
+    '<':    (cond, left, right) -> left < right
+    '>':    (cond, left, right) -> left > right
+    '<=':   (cond, left, right) -> left <= right
+    '>=':   (cond, left, right) -> left >= right
     'contains': (cond, left, right) ->
       if typeof left?.indexOf is 'function'
         left.indexOf(right) >= 0


Fix view next day bug

Fix view next day bug

--- view/coffee/game/game.coffee
+++ view/coffee/game/game.coffee
@@ -59,12 +59,20 @@
       _.findLastIndex _.initial(train.stops), (stop) => stop.station.id == @game.station.id
     trainDay: (trains) ->
       trains.map (t) =>
+        dayFlag = false
         nextFlag = false
         t.stops = t.stops.map (stop) =>
+          if stop.stationId == @game.station.id then nextFlag = true
           if stop.arrival
-            stop.arrival.day = if !nextFlag and @isAfter(stop.arrival) then 0 else nextFlag = true; 1
+            stop.arrival.day = if !dayFlag and @isAfter(stop.arrival) then 0
+            else
+              dayFlag = nextFlag
+              1
           if stop.departure
-            stop.departure.day = if !nextFlag and @isAfter(stop.departure) then 0 else nextFlag = true; 1
+            stop.departure.day = if !dayFlag and @isAfter(stop.departure) then 0
+            else
+              dayFlag = nextFlag
+              1
           stop
         t
     isAfter: (time) ->


hides templates

hides templates

--- app/assets/javascripts/backend/budget.js.coffee
+++ app/assets/javascripts/backend/budget.js.coffee
@@ -1,5 +1,8 @@
 (($) ->
   'use strict'
+
+  $(document).ready ->
+    $(".revenue_template, .expense_template").hide()

   $(document).on 'click keyup', "a[data-budget-add='support']", ->
     $(this).closest('table').find('tr.appendable').each ->
@@ -10,6 +13,7 @@
     template = $(this).closest('table').find('tr.expense_template')
     new_expense = template.clone(true)
     new_expense.removeClass('expense_template')
+    new_expense.show()
     template.before(new_expense)
     return false

@@ -17,6 +21,7 @@
     template = $(this).closest('table').find('tr.revenue_template')
     new_revenue = template.clone(true)
     new_revenue.removeClass('revenue_template')
+    new_revenue.show()
     template.before(new_revenue)
     return false


:space_invader: fixed toponym tweet

:space_invader: fixed toponym tweet

--- app/assets/javascripts/inspector_toponym.coffee
+++ app/assets/javascripts/inspector_toponym.coffee
@@ -11,7 +11,7 @@
       tutorialType:"simple"
       tutorialURL: "//player.vimeo.com/video/123878608?autoplay=1&title=0&byline=0&portrait=0"
       jsdataID: '#toponymjs'
-      tweetString: "_score_ toponyms found! Data mining old maps with Building Inspector from @NYPLMaps @nypl_labs"
+      tweetString: "_score_ place names found! Data mining old maps with Building Inspector from @NYPLMaps @nypl_labs"
       overlayHTML: '

         Drag around the map and identify
named places (e.g. “Carriage Factory”).
Ignore street names and addresses.
'
       task: 'toponym'


Add category ID

Add category ID

--- app/assets/javascripts/models/matcher.js.coffee
+++ app/assets/javascripts/models/matcher.js.coffee
@@ -1,5 +1,6 @@
 App.Matcher = App.Model.extend
   id: Ember.attr()
+  category_id: Ember.attr(Number)
   category: Ember.belongsTo 'App.Category',
     key: 'category_id'
   transactions: Ember.hasMany 'App.Transaction',


fix: Use correct names for properties lat() and lng()

--- app/assets/javascripts/widgets/direction.coffee
+++ app/assets/javascripts/widgets/direction.coffee
@@ -181,7 +181,7 @@
     if status == google.maps.DirectionsStatus.OK
       FOUND_ROUTE = route = result.routes[0]
       route.path = route.overview_path.map (o) ->
-        latitude: o.kb, longitude: o.lb
+        latitude: o.lat(), longitude: o.lng()

       gmap.directionsRenderer.setDirections(result)
       gmap.onNextMovement -> callback(route)


Follow the route type changes

Follow the route type changes

--- app/assets/javascripts/widgets/direction.coffee
+++ app/assets/javascripts/widgets/direction.coffee
@@ -291,7 +291,7 @@
   else
     search_params            = $('#new_search').serializeObject().search
     search_params.waypoints  = getWaypoints()
-    search_params.route_type = $('#search_route_type :selected').val()
+    search_params.route_type = $('input[name="search[route_type]"]:checked').val()
     search_params.radius     = $('#search_radius').val()

   search_params.api_key = "oz"
@@ -419,7 +419,7 @@
     ROUTE = POLYGON = null
     do searchRelics

-  $('body').on 'change', '#search_radius, #waypoints .waypoint, #search_route_type', ->
+  $('body').on 'change', '#search_radius, #waypoints .waypoint, input[name="search[route_type]"]', ->
     $(document).trigger 'params:changed'

   toggleRemoveButtons = ->


Avoid editor pile-up, clean up on closing of edit view.

--- scripts/views/workspace/content/aloha-edit.coffee
+++ scripts/views/workspace/content/aloha-edit.coffee
@@ -63,7 +63,7 @@
       $(Aloha, 'body').off 'aloha-smart-content-changed.updatemodel'

       # Kill old editable, otherwise they accumulate on Aloha.editables.
-      Aloha.getEditableById(@$el.attr('id')).destroy()
+      @$el.mahalo?()

     onRender: () ->
       # update model after the user has stopped making changes


test commit

test commit

--- scripts/banban.coffee
+++ scripts/banban.coffee
@@ -11,4 +11,7 @@
        res.reply "Opening #{doorType} doors"

     robot.hear /overlord/i, (res) ->
-    	res.send "婊子們找我?"+    	res.send "婊子們找我?"
+
+    robot.hear /boss/ig, (res) ->
+      res.send "B0ss是他馬的爽兵!"


added pause and fixed alan

added pause and fixed alan

--- scripts/fierce.coffee
+++ scripts/fierce.coffee
@@ -55,20 +55,23 @@
 ]

 module.exports = (robot) ->
-  robot.respond /(fierce|fierce me)(.*)/i, (msg) ->
+  robot.respond /(fierce|fierce me)/i, (msg) ->
     msg.send "http://www.mutatedcreativity.com/dev/f/logo/?pub=Fierce" + words[Math.floor(Math.random() * words.length)] + words[Math.floor(Math.random() * words.length)] + "&ext=.png"

-  robot.respond /(find) in (project|dir)/i, (msg) ->
+  robot.respond /(find|search) in (project|dir)/i, (msg) ->
     msg.send 'find . -type f | xargs grep -i "sharethis"'

   robot.hear /(ETC|Escalate to Carson)/i, (msg) ->
     msg.send "http://www.salem-news.com/stimg/august042010/f-bomb-2.jpg"

-  robot.respond /(what should i do about)(.*)/i, (msg) ->
+  robot.hear /what should (i|we) do about/i, (msg) ->
     msg.send "Escalate to Carson!"

-  robot.respond /(alan)/i, (msg) ->
+  robot.hear /alan/i, (msg) ->
     msg.send "http://www.youtube.com/watch?v=aXqkNF8fgs8"

-  robot.hear /(right about now)/i, (msg) ->
+  robot.hear /right about now/i, (msg) ->
     msg.send "Funk Soul Brother"
+
+  robot.hear /(pause|paws)/i, (msg) ->
+    msg.send "http://www.wppl.org/kidsteens/paws.jpg"