log function will cull out the msg property to simplify debugging

--- src/giphy.coffee
+++ src/giphy.coffee
@@ -78,8 +78,10 @@
 """.trim()

   ### istanbul ignore next ###
-  log: ->
-    console.log.apply this, arguments if DEBUG
+  log: (msg, state) ->
+    state = extend({}, state)
+    delete state.msg
+    console.log.call this, msg, state if DEBUG

   error: (msg, reason) ->
     if msg and reason


Clean up code

Clean up code

--- lib/autoprefixer/hacks/border-image.coffee
+++ lib/autoprefixer/hacks/border-image.coffee
@@ -5,8 +5,7 @@

   # Remove fill parameter for prefixed declarations
   set: (decl, prefix) ->
-    decl = super
     decl.value = decl.value.replace(/\s+fill(\s)/, '$1')
-    decl
+    super(decl, prefix)

 module.exports = BorderImage


CSS text setting bug with '<br>' fixed

CSS text setting bug with '<br>' fixed

Now text with this tags is properly showed.

--- impl/css/level0/text.coffee
+++ impl/css/level0/text.coffee
@@ -64,7 +64,7 @@
 	updatePlainTextSize = (item) ->
 		data = item._impl

-		text = item._text
+		text = data.text
 		{fontFamily} = data.innerElemStyle
 		if font = item._font
 			pixelSize = font._pixelSize
@@ -140,7 +140,7 @@
 		updateItem = (item) ->
 			data = item._impl
 			isAutoSize = item._autoWidth or item._autoHeight
-			if (text = item._text)
+			if (text = data.text)
 				if data.containsHTML
 					data.innerElem.innerHTML = text
 					if isAutoSize
@@ -217,6 +217,7 @@
 		uid: 0
 		contentUpdatePending: false
 		containsHTML: false
+		text: ''
 		font: "14px #{implUtils.DEFAULT_FONTS['sans-serif']}, sans-serif"

 	exports =
@@ -245,6 +246,7 @@

 	setText: (val) ->
 		val = val.replace /<[bB][rR]\s?\/?>/g, "\n"
+		@_impl.text = val
 		@_impl.containsHTML = CONTAINS_HTML_RE.test(val)
 		updateContent @
 		return


Preserve parameters in OAuth state.

Preserve parameters in OAuth state.

--- src/js/collection-editor.coffee
+++ src/js/collection-editor.coffee
@@ -480,6 +480,11 @@

   cite_collection_editor_config = $.extend({}, default_cite_collection_editor_config, window.cite_collection_editor_config)
   google_oauth_parameters_for_fusion_tables['client_id'] = cite_collection_editor_config['google_client_id']
+
+  if location.hash.substring(1).length
+     console.log "Setting OAuth URL parameter state: #{location.hash.substring(1)}"
+     google_oauth_parameters_for_fusion_tables['state'] = location.hash.substring(1)
+
   return cite_collection_editor_config

 # main collection editor entry point


optimization: Use hash instead of _.unique when building autocomplete word list

--- src/extensions/autocomplete.coffee
+++ src/extensions/autocomplete.coffee
@@ -79,7 +79,11 @@
       @buildWordList() unless @isAutocompleting

   buildWordList: () ->
-    @wordList = _.unique(@currentBuffer.getText().match(@wordRegex))
+    wordHash = {}
+    for word in @currentBuffer.getText().match(@wordRegex)
+      wordHash[word] ?= true
+
+    @wordList = Object.keys(wordHash)

   confirm: ->
     @confirmed = true


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/flickerable.coffee
+++ src/flickerable.coffee
@@ -18,11 +18,10 @@
   self.bind 'update', ->
     I.flickerDuration = I.flickerDuration.approach(0, 1)

-    if I.flickerDuration
-      if I.age.mod(I.flickerFrequency) is 0
-        if I.alpha is I.flickerAlpha
-          I.alpha = originalAlpha
-        else
+    if I.flickerDuration and I.age.mod(I.flickerFrequency) is 0
+      if I.alpha is I.flickerAlpha
+        I.alpha = originalAlpha
+      else
         I.alpha = I.flickerAlpha
     else
       I.alpha = originalAlpha


Fix indentation :|

Fix indentation :|

--- src/honeybadger.coffee
+++ src/honeybadger.coffee
@@ -6,39 +6,39 @@
   configured: false

   configure: (options = {}) ->
-   if @configured == false
-     options['disabled'] = false if typeof options.disabled == 'undefined'
-     @configured = true
-   for k,v of options
-     @configuration[k] = v
-   @TraceKit.collectWindowErrors = @configuration.onerror
-   @
+    if @configured == false
+      options['disabled'] = false if typeof options.disabled == 'undefined'
+      @configured = true
+    for k,v of options
+      @configuration[k] = v
+    @TraceKit.collectWindowErrors = @configuration.onerror
+    @

   configuration: new Configuration()

   context: {}

   resetContext: (options = {}) ->
-   @context = if typeof(options) == 'object' then options else {}
-   @
+    @context = if typeof(options) == 'object' then options else {}
+    @

   setContext: (options = {}) ->
-   if typeof(options) == 'object'
-     for k,v of options
-       @context[k] = v
-   @
+    if typeof(options) == 'object'
+      for k,v of options
+        @context[k] = v
+    @

   beforeNotifyHandlers: []
   beforeNotify: (handler) ->
     @beforeNotifyHandlers.push handler

   notify: (error, options = {}) ->
-   return false if !@configured || @configuration.disabled == true
-   options['error'] = error if error
-   return false if (k for own k of options).length == 0
-   notice = new Notice(options)
-   (if handler(notice) == false then return false) for handler in @beforeNotifyHandlers
-   @_sendRequest(notice.toJSON())
+    return false if !@configured || @configuration.disabled == true
+    options['error'] = error if error
+    return false if (k for own k of options).length == 0
+    notice = new Notice(options)
+    (if handler(notice) == false then return false) for handler in @beforeNotifyHandlers
+    @_sendRequest(notice.toJSON())

   wrap: (func) ->
     () ->
@@ -61,36 +61,36 @@
     @

   _sendRequest: (data) ->
-   url = 'http' + ((@configuration.ssl && 's') || '' ) + '://' + @configuration.host + '/v1/notices.html'
-   @_crossDomainPost(url, data)
+    url = 'http' + ((@configuration.ssl && 's') || '' ) + '://' + @configuration.host + '/v1/notices.html'
+    @_crossDomainPost(url, data)

   # http://www.markandey.com/2011/10/design-of-cross-domain-post-api-in.html
   _crossDomainPost: (url, payload) ->
-   iframe = document.createElement('iframe')
-   uniqueNameOfFrame = '_hb_' + (new Date).getTime()
-   document.body.appendChild iframe
-   iframe.style.display = 'none'
-   iframe.contentWindow.name = uniqueNameOfFrame
+    iframe = document.createElement('iframe')
+    uniqueNameOfFrame = '_hb_' + (new Date).getTime()
+    document.body.appendChild iframe
+    iframe.style.display = 'none'
+    iframe.contentWindow.name = uniqueNameOfFrame

-   form = document.createElement('form')
-   form.target = uniqueNameOfFrame
-   form.action = url
-   form.method = 'POST'
+    form = document.createElement('form')
+    form.target = uniqueNameOfFrame
+    form.action = url
+    form.method = 'POST'

-   input = document.createElement('input')
-   input.type = 'hidden'
-   input.name = "payload"
-   input.value = payload
-   form.appendChild input
+    input = document.createElement('input')
+    input.type = 'hidden'
+    input.name = "payload"
+    input.value = payload
+    form.appendChild input

-   input = document.createElement('input')
-   input.type = 'hidden'
-   input.name = "api_key"
-   input.value = @configuration.api_key
-   form.appendChild input
+    input = document.createElement('input')
+    input.type = 'hidden'
+    input.name = "api_key"
+    input.value = @configuration.api_key
+    form.appendChild input

-   document.body.appendChild form
-   form.submit()
+    document.body.appendChild form
+    form.submit()

   _handleTraceKitSubscription: (stackInfo) ->
     Honeybadger.notify(null, { stackInfo: stackInfo })


Okay so I'm finished playing with this stupid procedure

--- src/ihackernews.coffee
+++ src/ihackernews.coffee
@@ -58,36 +58,21 @@
     #    (if (>= a 1440) (pr (plural (trunc (/ a 1440)) "day")    " ago")
     #        (>= a   60) (pr (plural (trunc (/ a 60))   "hour")   " ago")
     #                    (pr (plural (trunc a)          "minute") " ago"))))
-    now = Date.now()
-
-    minute = 60 * 1000
-    hour   = 60 * minute
-    day    = 24 * hour
-
-    match = /([0-9]+) ([a-z]+) ago/.exec(str)
+    match = /([0-9]+) ((day)|(hour)|(minute))s? ago/.exec(str)

     return null unless match?

-    [_, num, scale] = match
+    [_, num, unit] = match

-    num = Number(num)
+    units =
+        minute:        60 * 1000
+        hour:     60 * 60 * 1000
+        day: 24 * 60 * 60 * 1000

-    switch scale
-        when "day", "days" then
-            diff = num * day
-
-        when "hour",   "hours"
-            diff = num * hour
-
-        when "minute", "minutes"
-            diff = num * minute
-
-        else return null
-
-    new Date(now - diff)
+    new Date Date.now() - (units[unit] * Number(num))

 smiley = (name) ->
-    eyes = "$^*@;TQs><?uveazoO096~"
+    eyes = "$^*@;TQs><?UuVveazoO096~pq"

     name_to_num = (str) ->
         total = 0


Tiny optimization

Tiny optimization

--- src/lib/Helpers.coffee
+++ src/lib/Helpers.coffee
@@ -185,7 +185,7 @@
   component.defaultsSent = false

   sendDefaultParams = ->
-    if not component.defaultsSent and component.defaultedParams.length > 0
+    if component.defaultedParams.length > 0
       for param in component.defaultedParams
         tempSocket = InternalSocket.createSocket()
         component.inPorts[param].attach tempSocket
@@ -361,7 +361,7 @@
               component.beforeProcess outs

             # Sending defaults if not sent already
-            sendDefaultParams()
+            sendDefaultParams() unless component.defaultsSent

             # Group forwarding
             if outPorts.length is 1


Remove spaces at end of line.

Remove spaces at end of line.

Deleted spaces at the end of lines. They appear colored in red in my
`git` diffs, as if they were something evil. There are not, but I
removed them anyway.

--- src/lib/strata._coffee
+++ src/lib/strata._coffee
@@ -9,7 +9,7 @@
 #
 # Strata is faster than a flat file, lighter than a database, with more capacity
 # than an in‑memory tree.
-#
+#
 # Strata is a [b‑tree](http://en.wikipedia.org/wiki/B-tree)
 # implementation for [Node.js](http://nodejs.org/) that is **evented**,
 # **concurrent**, **persistent** and **durable**.
@@ -29,7 +29,7 @@
 #
 # Strata is **durable**. It only appends records to to file, so a hard shutdown
 # will only ever lose the few last records added. Pages are journaled when they
-# are vacuumed or rewritten.
+# are vacuumed or rewritten.
 #
 # Strata is a b‑tree. A b‑tree is a database primitive. Using
 # Strata, you can start to experiment with database designs of your own. You can
@@ -44,7 +44,7 @@
 # Strata runs anywhere that Node.js runs, in pure JavaScript.
 #
 # ## Collaboration
-#
+#
 # Documentation for Strata is presented here, in literate programming style. API
 # documentation is not yet available, so scoot down to the `Strata` class for an
 # in-depth look at the API. Have a look at the extensive test suite for examples
@@ -89,7 +89,7 @@
 # the leaves.
 #
 # Terms specific to our implementation will be introduced as they are
-# encountered in the document.
+# encountered in the document.
 #
 # ## What is a b‑tree?
 #
@@ -201,7 +201,7 @@
 #
 class IO
   # ### Checksummed Lines of JSON
-
+
   # Each page is stored in its own ***page file***. The page files are all kept
   # in a single directory. The directory is specified by the application
   # developer when the `Strata` object is constructed.
@@ -237,13 +237,13 @@
   # and records, so we can avoid loading records we don't need.
   #
   # **TK**: Damage mentioned above ends here.
-  #
+  #
   # We count on our JavaScript array implementation to be [clever about memory
   # usage](http://stackoverflow.com/questions/614126/why-is-array-push-sometimes-faster-than-arrayn-value/614255\#614255).
-
+
   # Set directory and extractor. Initialize the page cache and most-recently
   # used list.
-  #
+  #
   # The checksum will become CRC 32 by default in future releases and
   # configurable to use any of the `crypto` module hashes or no checksum at all.
   constructor: (@directory, @options) ->
@@ -395,9 +395,9 @@
   #
   # There is no way to get the size of a JavaScript object in memory, so we
   # don't have a way to know the actual size of cached pages in memory.
-  #
+  #
   # We can get a pretty good relative measure of the size of a page, however,
-  # using the length of the JSON strings used to store records and references.
+  # using the length of the JSON strings used to store records and references.
   #
   # The ***JSON size*** of a branch page is the string length of the address
   # array when serialized to JSON, plus the string length of each key loaded
@@ -416,7 +416,7 @@
   heft: (page, size) ->
     page.size += size
     @size += size
-
+
   # #### Pages Held for Housekeeping
   #
   # There may be page objects loaded for housekeeping only. When balancing the
@@ -550,7 +550,7 @@
   # Each leaf page cache entry contains the record, key and the size of the
   # object at the time of caching.

-  #
+  #
   cacheRecord: (page, position, record, key) ->
     # Uncache the exisiting record.
     @uncacheRecord page, position
@@ -584,7 +584,7 @@
   # essentially a log. Each time we write to the log, we open and close the
   # file, so that the operating system will flush our writes to disk. This gives
   # us durability.
-  #
+  #
   # The caller determines which file should be written, so it opens and closes
   # the file descriptor. For record insertions and deletions, a file descriptor
   # is opened and closed for a single append. When rewriting an existing leaf
@@ -696,7 +696,7 @@
   # When we read the insert entry, we will place the record in the record cache
   # for the page, mapping the position to the record.

-  # Write an insert object.
+  # Write an insert object.
   writeInsert: (fd, page, index, record, _) ->
     entry = [ index + 1, page.length - page.ghosts + 1, ++page.entries, record ]
     @_writeJSON fd, page, entry, _
@@ -743,8 +743,8 @@
   # When we read a leaf page file, if we read from the back of the file toward
   # the front, we can read backward until we find a position array entry. Then
   # we can read forward to the end of the file, applying the inserts and deletes
-  # that occurred after we wrote the position array entry.
-  #
+  # that occurred after we wrote the position array entry.
+  #
   # When a leaf page file is large, stashing the constructed position array at
   # the end means that the leaf page can be loaded quickly, because we will only
   # have to read backwards a few entries to find a mostly completed position
@@ -767,7 +767,7 @@
   # change when the leaf page file is rewritten.
   #
   # The JSON array elements of a delete entry form a structure as follows.
-  #
+  #
   #  * Zero to indicate a position array entry.
   #  * Leaf page file format version number.
   #  * Address of the right sibling leaf page.
@@ -791,7 +791,7 @@
   # Here is the backward search for a position in array in practice. We don't
   # really ever start from the beginning. The backwards than forwards read is
   # just as resilient.
-
+
   #
   readLeaf: (page, _) ->
     # We don't cache file descriptors after the leaf page file read. We will
@@ -863,7 +863,7 @@
         page.ghosts++
       else
         @splice page, -(index + 1), 1
-
+
     # Cache the records we read while searching for the position array object.
     for position in page.positions
       if cache[position]
@@ -924,7 +924,6 @@
       @length += @length >>> 1
     fs.close fd, _
     entry.pop()
-

   # Over time, a leaf page file can grow fat with deleted records. Each deleted
   # record means there's an insert object that is no longer useful. The delete
@@ -1066,7 +1065,7 @@
   # split page in the parent page.
   #
   # Our implementation does not store the keys, as you may have noticed, but
-  # descends down to the leaf page to fetch the record to use as a key.
+  # descends down to the leaf page to fetch the record to use as a key.
   #
   # We start from a penultimate page as a root page. When a leaf page fills, we
   # split it, creating a new right leaf page. The penultimate page uses the
@@ -1347,7 +1346,7 @@
   #
   # Probably need "r" to not create the crash file, in case we're reading from a
   # read only file system, or something.
-
+
   # —
   open: (_) ->
     try
@@ -1447,7 +1446,7 @@
   # lock. If a descent holds an exclusive write lock, then all lock requests by
   # other descents are blocked. If one or more descents hold a shared read lock,
   # then any request for an exclusive write lock is blocked. Any request for a
-  # shared read lock is granted, unless an exclusive write lock is queued.
+  # shared read lock is granted, unless an exclusive write lock is queued.
   #
   # The locks are not re-entrant.

@@ -1477,7 +1476,7 @@
     #
     # We don't use mutexes, of course, because Node.js doesn't have the concept
     # of mutexes to protect critical sections of code the way that threaded
-    # programming platforms do.
+    # programming platforms do.
     #
     # Nor do we use file system locking.
     #
@@ -1621,7 +1620,7 @@
       stash = @cacheRecord page, position, record
     stash

-
+
   # A note on the theoretical `null` key. If the collation order places `null`
   # before all other values, that's a good choice, because that means that it
   # will never be used for a branch key. If it is used as a branch key, the
@@ -1683,7 +1682,7 @@
 #
 # We use the term descent to describe the both traversal of the b‑tree
 # and the subsequent actions performed when when the desired page is found.
-#
+#
 # The descent is the unit of work in our concurrency model.  A descent is
 # analogous to a thread, because when a descent waits on I/O, other descents can
 # make progress.
@@ -1747,7 +1746,7 @@
 # that compares our search key against the keys in the root page. We determine
 # the correct child page to visit to continue our search. We lock the child
 # page. We then release the lock on the parent page.
-#
+#
 # We repeat the process of locking a page, searching it, locking a child, and
 # then releasing the lock on the child's parent.
 #
@@ -1770,7 +1769,7 @@
 # #### Deadlock Prevention and Traversal Direction
 #
 # To prevent deadlock, we always move form a parent node to a child node, or
-# form a left sibling to a right sibling.
+# form a left sibling to a right sibling.
 #
 # **TK**: Chunky.
 #
@@ -1816,7 +1815,7 @@
   # may be at any level of the tree. We need to hold our lock on the branch page
   # that contains the key, while still descending the tree to find the two pages
   # that need to be merged. The two pages to merge may not be immediate children
-  # of the same penultimate branch page.
+  # of the same penultimate branch page.
   #
   # **TK** Glurgh: We need to leave the key page locked, then go left and right
   # to find two separate pages. We do not need to hold locks on all the pages
@@ -1824,12 +1823,12 @@
   # hand-over-hand logic works fine. Descending hand-over-hand exclusive will
   # cause us to wait for other descents to finish, squeezing the other descents
   # out.
-
+
   # We create a new `Descent` which creates a dummy first page. We then assign
   # the addresses current descent to the dummy page, and copy the current index.
   fork: ->
     extend (new Descent @io), { @page, @exclusive, @index }
-
+
   @key: (key) ->
     (_) -> @io.find @page, key, (if @page.address < 0 then @page.ghosts else 1), _

@@ -1875,9 +1874,9 @@
       @unlock = true
       if @page.address >= 0 and @index < 0
         @index = (~@index) - 1
-
+
 # ## Cursors
-#
+#
 # Application developers navigate the b‑tree using one of two types of
 # ***cursor***. To read records in the b&x2011;tree they use an ***iterator***.
 # To read records, as well as insert and delete records, they use ***mutator***.
@@ -1913,7 +1912,7 @@
 # **TK**: Definition of keys and records. Go back up and make sure one is there.
 #
 # #### Record Ranges
-#
+#
 # The cursor will define an `offset` property and a `length` property. The
 # `offset` is positioned at the first record in the page whose key is equal to
 # or greater than the search key. The `length` is the count of records in the
@@ -2035,7 +2034,7 @@
 # and insert them in one fell swoop.
 #
 # #### Ambiguous Insert Locations
-#
+#
 # Insert locations for ranged inserts can be ambiguous if the binary search
 # indicates that a record should be inserted at the end of the leaf page, after
 # the current last record in the leaf page. If the insert location is after the
@@ -2224,7 +2223,7 @@
 # client may obtain a cursor to the leaf pages, iterate through them deleting
 # records along the way. As the client alters leaf records, they are marked as
 # candidates for balance. Balancing will take place periodically, where a single
-# thread of control **TK** will
+# thread of control **TK** will
 #
 # #### Staccato Balance Operations
 #
@@ -2265,7 +2264,7 @@
 #
 # There are compromises, but rather than create a complicated locking apparatus,
 # with upgrades, we're going to simplify our algorithm greatly, by descending
-# the tree once for each split or merge.
+# the tree once for each split or merge.
 #
 # When we travel to the unbalanced page, we acquire shared locks in the hand
 # over hand fashion used for search. We acquire exclusive locks only on those
@@ -2295,7 +2294,7 @@
 #
 # We can see that a descent of the tree is analogous to a thread in
 # multi-threaded operation. A decent is an actor on the tree, performing a
-# single balance operation, searching
+# single balance operation, searching
 #
 # ##### Delayed Balance
 #
@@ -2458,8 +2457,8 @@
 # always balance the upper levels immediately, we perform the cascade. Our tree
 # descent logic would have to account for these empty sub‑trees. Much
 # better to balance and keep things orderly.
-#
-# This raises a concerns about live lock, that we might be balancing
+#
+# This raises a concerns about live lock, that we might be balancing
 #
 # **TK**: Yes file times are enough. Even if the system clock changes
 # drastically, the file times are all relative to one another. It it changes
@@ -2486,7 +2485,7 @@
 # Merge is from right to left. When we merge we always merge a page into its
 # left sibling. If we've determined that a page from which records have been
 # deleted is supposed to merge with its right sibling, we apply our merge
-# algorithm to the right sibling, so that is is merged with its left sibling.
+# algorithm to the right sibling, so that is is merged with its left sibling.
 #
 # When we compare a page from which records have been deleted against its
 # siblings, if the left sibling is to be merged, we use the page itself, the
@@ -2599,7 +2598,7 @@
 # merge page. We have to make an exception when the empty page is the left most
 # page in the entire tree, which is not uncommon for time series data where the
 # oldest records are regularly purged.
-#
+#
 # #### Purging Deleted First Keys
 #
 # Now we merge the parents. We find a penultimate page by the key of the left
@@ -2722,13 +2721,13 @@
   # every page that has been added to the balancer, regardless of whether it has
   # grown, shrunk or returned to its original reported size. If the page is to
   # be deleted, because the leaf page is empty, that negates any fussing with
-  # the key. Same goes for the case where the page is to be merged.
+  # the key. Same goes for the case where the page is to be merged.

   # Ah, also, when we do load these, when we want to get them from the cache, we
   # don't really need them to be loaded. We should reach in a probe the cache
   # ourselves. My former Java self would have to spend three days thinking about
   # encapsulation, probably create a new sub-project. Agony.
-
+
   # Balancing will continue until morale improves. It may feel like a race
   # condition, but that can't be helped. There may be degenerate use cases where
   # the b‑tree cannot reach a balanced state. Inserts and deletes may be
@@ -2768,7 +2767,7 @@

     ghosts = {}
     max = @io.options.leafSize
-
+
     # We put a new balancer in place of the current balancer. Any edits will be
     # considered by the next balancer.
     @io.balancer = new Balancer
@@ -2783,7 +2782,7 @@
     # page size. When we detect that we can't make an informed decision on a
     # page, we pass it onto the next balancer for consideration at the next
     # balance.
-
+
     # For each page that has changed we add it to a doubly linked list.
     ordered = {}
     for address in addresses
@@ -2795,14 +2794,14 @@
       # We create linked lists that contain the leaf pages we're considering in
       # our balance plan. This is apart from the most-recently used list that
       # the pages themselves form.
-      #
+      #
       # The linked list nodes contain a reference to the page, plus a reference
       # to the node containing the previous sibling, and a reference to the node
       # containing the next sibling. If a sibling is not participating in our
       # balance plan, then its link is null. This gives us one or more linked
       # lists that reference a series of leaf pages ordered according to their
       # order in the b‑tree.
-      #
+      #
       # We are always allowed to get a lock on a single page, so long as we're
       # holding no other locks.
       if not node = ordered[address]
@@ -2818,7 +2817,7 @@
         ghosts[node.page.address] = node

       # If the page has shrunk in size, we gather the size of the left sibling
-      # page and the right sibling page. The right sibling page
+      # page and the right sibling page. The right sibling page
       if node.length - length < 0
         hit "f349ecda729348fd6584808d362ccbe0"
         if node.page.address isnt -1
@@ -2873,7 +2872,7 @@
           right.left = null
       right

-    # Link a node
+    # Link a node
     link = (node, right) ->
       if right
         right.left = node
@@ -2955,7 +2954,7 @@
         else
           delete ordered[address]

-    # Rewrite position arrays to remove ghosts.
+    # Rewrite position arrays to remove ghosts.
     for address, node of ghosts
       @operations.unshift
         method: "deleteGhost"
@@ -3046,7 +3045,7 @@

       # Never a remainder record on the first page.
       offset = split.length
-
+
       # Create new pages.
       while --pages
         # Create a new leaf page.
@@ -3116,7 +3115,7 @@
       # bad, but great example. Imagine a page that has been full, but has a
       # sibling that has only one record. We add a record to the full page and
       # split it so that it is half empty. We then add it to the balancer with
-      # its half full record count. We want to check for merge and see
+      # its half full record count. We want to check for merge and see
       #
       # **TODO**: Swipe — This always balance until perfect balance is
       # still imperfect.  We may still manage to create a b‑tree that has
@@ -3128,14 +3127,14 @@
       @io.balancer.unbalanced(page, true)

     # Release the pages locked during descent. Seems premature because we're not
-    # done yet, but no other descent makes progress unless we invoke a callback.
+    # done yet, but no other descent makes progress unless we invoke a callback.
     @io.unlock(descent.page) for descent in descents

     # Although we've unlocked the penultimate branch page, we know that only the
     # balancer edit a branch page, so we are safe to make a decision about
     # whether to split the penultimate branch page while it is unlocked.
     @shouldSplitBranch penultimate.page, key, _
-
+

   splitBranch: ({ key, depth }, _) ->
     descents = []
@@ -3286,7 +3285,7 @@
     descents.push pivot = new Descent(@io)
     pivot.descend(sought = Descent.key(key), Descent.found(key), _)
     pivot.upgrade()
-
+
     # Descend to the penultimate page, but first, take note of whether or not
     # the branch page that contains our key is also the penultimate page. We go
     # to the right-most descendant of the left child to find the left leaf page
@@ -3301,7 +3300,7 @@

     penultimate.right = pivot.fork()
     penultimate.right.descend sought, Descent.penultimate, _
-
+
     # If the leaf page key was found in the penultimate page, then we do not
     # want to key the penultimate pages for release, because they are the same
     # as the branch key page, and the branch key page is already queued for
@@ -3313,7 +3312,7 @@
     # Descend to the leaves. Note that if we're on the penultimate page, the
     # next descent will follow the index we decremented above, the leaf page to
     # the left of the keyed page, instead of going to the right-most leaf page.
-    #
+    #
     # We use `leftMost` in both cases, because we don't need an index into the
     # leaf page, only a lock on the leaf page.
     leaves = {}
@@ -3332,7 +3331,7 @@

     # Determine if we still have candidates for merge.
     if leaves.left.page.length - leaves.left.page.ghosts + leaves.right.page.length - leaves.right.page.ghosts <= @io.options.leafSize
-      # Uncache the pivot key.
+      # Uncache the pivot key.
       @io.uncacheKey pivot.page, pivot.page.addresses[pivot.index]

       # The right leaf page of of the merged page is the right leaf page of the
@@ -3368,9 +3367,9 @@
       # **TODO**: If I succeed, how will I know to test the parents for balance?
       # **TODO**: Uh, can't the medic just note that this page needs to be
       # rebalanced? It can force a propagation of balance and merge checking of
-      # the parent.
-
-      # Renaming pending to commit will cause the merge to roll forward.
+      # the parent.
+
+      # Renaming pending to commit will cause the merge to roll forward.
       @io.rename penultimate.right.page, ".pending", ".commit", _

       @io.replace leaves.left.page, ".replace", _
@@ -3395,7 +3394,7 @@

     # Roughly: First choose which to merge. Then merge.
     #
-    # I believe that, once we find the key, we have found
+    # I believe that, once we find the key, we have found

     # We need to go left then right when we see the key.
     descent = new Descent(@io)
@@ -3519,7 +3518,7 @@

     @io.unlink page, "unlink", _ for page in [ left, right ]
     @io.replace root, "commit", _
-
+
     @io.unlock page for page in pages

 class Cassette
@@ -3600,6 +3599,6 @@
   balance: (_) -> @_io.balancer.balance(@_io, _)

 # ## Glossary
-#
+#
 # * <a name="map">**map**</a> — A JavaScript Object that is used as a key
 # value store. We use the term *map*, because the term *object* is ambiguous.


Fix help text

Fix help text

--- src/philips-hue.coffee
+++ src/philips-hue.coffee
@@ -35,15 +35,9 @@
 #   hubot hue hash - get a hash code (press the link button)
 #   hubot hue set config (name|linkbutton) <value>- change the name or programatically press the link button
 #   hubot hue (alert|alerts) light <light number> - blink once or blink for 10 seconds specific light
-#   hubot hue hsb light <light number> <hue> <saturation> <brightness>
-#   - hue range: 0-6553
-#   - saturation range: 0-254
-#   - brightness range: 0-254
-#   hubot hue xy light <light number> <x> <y>
-#   - valid x: 0.0-1.0
-#   - valid y: 0.0-1.0
-#   hubot hue ct light <light number> <color temp>
-#   - color temperature range: 153-500 (153 appears 6500K, 500 appears 2000K)
+#   hubot hue hsb light <light number> <hue 0-65535> <saturation 0-254> <brightness 0-254>
+#   hubot hue xy light <light number> <x 0.0-1.0> <y 0.0-1.0>
+#   hubot hue ct light <light number> <color temp 153-500>
 #   hubot hue group <group name>=[<comma separated list of light indexes>]
 #   hubot hue ls groups - lists the groups of lights
 #   hubot hue rm group <group name> - remove grouping of lights named <group name>


Add word boundary to zen.coffee

Add word boundary to zen.coffee

--- src/scripts/zen.coffee
+++ src/scripts/zen.coffee
@@ -15,7 +15,7 @@
 #

 module.exports = (robot) ->
-  robot.hear /zen/i, (msg) ->
+  robot.hear /\b(zen)\b/i, (msg) ->
     msg
       .http("https://api.github.com/zen")
       .get() (err, res, body) ->


fix opening element as class

fix opening element as class

--- src/spTransform.coffee
+++ src/spTransform.coffee
@@ -168,7 +168,7 @@
                     ++state.level

                 when 'JSXOpeningElement'
-                    if ast.attributes and /[a-z]/.test(ast.name.name[0])
+                    if ast.attributes and ast.name?.name and /[a-z]/.test(ast.name.name[0])
                         attributes = ast.attributes.filter (node)-> node.name?.name is 'className'
                         if attributes.length
                             value = attributes[attributes.length - 1].value


trying to fix swag config errors after swag.coffee change

--- src/swag.config.coffee
+++ src/swag.config.coffee
@@ -1,2 +1,2 @@
 Swag.Config =
-    partialsPath: ''
+  partialsPath: ''


pause/resume should work during split

pause/resume should work during split

--- src/test/stream.coffee
+++ src/test/stream.coffee
@@ -71,3 +71,24 @@

         stream.pipe buffer

+    'pause/resume split': (æ) ->
+        stream = new BufferStream size:'flexible'
+        stream.on 'data', (chunk) -> æ.equal chunk.toString(), results.shift()
+        stream.on 'end', ->
+            æ.equal stream.length, 0
+            æ.equal stream.toString(), ""
+            æ.done()
+
+        stream.split '/', (part) ->
+            stream.pause()
+            process.nextTick ->
+                results.push(part.toString())
+                stream.resume()
+
+        results = "buffer".split('')
+
+        stream.write "b/u/f/f/e/r/"
+        stream.end()
+
+
+


Note characterIndexForPosition converts to Point

--- src/text-buffer.coffee
+++ src/text-buffer.coffee
@@ -1561,7 +1561,7 @@
   #
   # The position is clipped prior to translating.
   #
-  # * `position` A {Point}.
+  # * `position` A {Point} or point-compatible {Array}.
   #
   # Returns a {Number}.
   characterIndexForPosition: (position) ->


Strip punctuation from guess and answer.

--- src/trivia-game.coffee
+++ src/trivia-game.coffee
@@ -40,6 +40,7 @@
       index = Math.floor(Math.random() * @questions.length)
       @currentQ = @questions[index]
       robot.logger.debug "Answer is #{@currentQ.answer}"
+      # remove optional portions of answer that are in parens
       @currentQ.validAnswer = @currentQ.answer.replace /\(.*\)/, ""

     $question = Cheerio.load ("<span>" + @currentQ.question + "</span>")
@@ -60,7 +61,10 @@

   answerQuestion: (resp, guess) ->
     if @currentQ
-      if guess.toLowerCase().indexOf(@currentQ.validAnswer.toLowerCase()) >= 0
+      # remove all punctuation and spaces, and see if the answer is in the guess.
+      checkGuess = guess.toLowerCase().replace /[\.,-\/#!$%\^&\*;:{}=\-_`~()\s]/g, ""
+      checkAnswer = @currentQ.validAnswer.toLowerCase().replace /[\.,-\/#!$%\^&\*;:{}=\-_`~()\s]/g, ""
+      if checkGuess.indexOf(checkAnswer) >= 0
         resp.reply "YOU ARE CORRECT!!1!!!111!! The answer is #{@currentQ.answer}"
         name = resp.envelope.user.name.toLowerCase().trim()
         value = @currentQ.value.replace /[^0-9.-]+/g, ""


Disable refacter, remove global node

Disable refacter, remove global node

Since refacter syntax error seemed to affect JSX syntax again.
Also global node location is machine specific

--- .atom/config.cson
+++ .atom/config.cson
@@ -34,6 +34,8 @@
       "cursor-history"
       "react"
       "atom-typescript"
+      "js-refactor"
+      "refactor"
     ]
     packagesWithKeymapsDisabled: [
       "git-diff-popup"
@@ -77,8 +79,7 @@
     transpileOnSave: true
   linter:
     errorPanelHeight: 112
-  "linter-eslint":
-    globalNodePath: "/Users/BBoyKelvin/.nvm/versions/node/v5.8.0"
+  "linter-eslint": {}
   refactor: {}
   "split-diff":
     ignoreWhitespace: true
@@ -104,7 +105,7 @@
   wakatime:
     apikey: "Saved in your ~/.wakatime.cfg file"
   "wakatime-hidden":
-    lastInit: 1468394468
+    lastInit: 1470117818
   welcome:
     showOnStartup: false
 ".babel.regexp.source":


Chose atom colors

Chose atom colors

--- .atom/config.cson
+++ .atom/config.cson
@@ -61,6 +61,10 @@
       "lisp-paredit"
     ]
     telemetryConsent: "limited"
+    themes: [
+      "one-light-ui"
+      "newton-dark-syntax"
+    ]
     titleBar: "custom"
   editor:
     autoIndent: false


disable prose lint

disable prose lint

--- .atom/config.cson
+++ .atom/config.cson
@@ -15,6 +15,7 @@
     disabledPackages: [
       "rubocop-auto-correct"
       "linter-rubocop"
+      "linter-proselint"
     ]
     excludeVcsIgnoredPaths: false
     telemetryConsent: "no"
@@ -44,8 +45,7 @@
     enableNotice: true
     shellcheckExecutablePath: "/usr/local/bin/shellcheck"
     userParameters: "-x"
-  "linter-ui-default":
-    panelHeight: 99
+  "linter-ui-default": {}
   "linter-write-good": {}
   "markdown-preview":
     useGitHubStyle: true


more options

more options

--- .atom/config.cson
+++ .atom/config.cson
@@ -12,11 +12,11 @@
     ]
     telemetryConsent: "limited"
     themes: [
-      "solarized-light-ui"
-      "solarized-light-syntax"
+      "solarized-dark-ui"
+      "solarized-dark-syntax"
     ]
   editor:
-    fontSize: 16
+    fontSize: 17
     preferredLineLength: 120
   "exception-reporting":
     userId: "9363c2a1-ce13-c340-7351-14b4c86035b6"
@@ -30,6 +30,9 @@
   "prettier-atom":
     formatOnSaveOptions:
       enabled: true
+    prettierOptions:
+      singleQuote: true
+    useEslint: true
   "tree-view":
     hideVcsIgnoredFiles: true
   welcome:


Update Atom config

Update Atom config

--- .atom/config.cson
+++ .atom/config.cson
@@ -4,13 +4,10 @@
     showInvisibles: true
     showIndentGuide: true
     preferredLineLength: 120
-    invisibles:
-      {}
+    invisibles: {}
   core:
     disabledPackages: [
       "metrics"
-      "tabs"
-      "tree-view"
       "editorconfig"
     ]
   "exception-reporting":
@@ -19,15 +16,10 @@
     showOnStartup: false
   "atom-beautify":
     _analyticsUserId: "1d4703af-c0bf-4e61-8894-f8865aaabf2b"
-  linter:
-    {}
+  linter: {}
   tabs:
     showIcons: true
-  "tree-view":
-    hideVcsIgnoredFiles: false
-    hideIgnoredNames: false
-    showOnRightSide: false
-    sortFoldersBeforeFiles: true
+  "tree-view": {}
 ".git-rebase.text":
   editor:
     preferredLineLength: 120


Fixed a nasty bug where an error in Recorder.sync() could cause an infinite loop with data-goal tags.

The error callback to sync in BaseExperiment wasn't correctly implemented. It didn't cache the rewarded
variant, which meant the retriggering of the click event would attempt to reward and sync again... and again...

--- src/main/base-experiment.coffee
+++ src/main/base-experiment.coffee
@@ -101,8 +101,10 @@
             @saveVariantFromReward(variant)
             success.call(this, variant, amount, true)
             @trigger('reward', variant, amount, true)
-          (args...) =>
-            error.call(this, args...)
+          =>
+            @saveVariantFromReward(variant)
+            error.call(this)
+            return
     else
       error(Myna.problem("no-variant"))


fix new line creation

fix new line creation

--- src/document.coffee
+++ src/document.coffee
@@ -26,12 +26,7 @@
     this.buildLines()

   appendLine: (lineNode) ->
-    line = new Tandem.Line(this, lineNode)
-    @lines.append(line)
-    @lineMap[line.id] = line
-    @length += line.length
-    @length += 1 if @lines.length > 1
-    return line
+    return this.insertLineBefore(lineNode, null)

   buildLines: ->
     this.reset()
@@ -123,7 +118,10 @@

   insertLineBefore: (newLineNode, refLine) ->
     line = new Tandem.Line(this, newLineNode)
-    @lines.insertAfter(refLine.prev, line)
+    if refLine != null
+      @lines.insertAfter(refLine.prev, line)
+    else
+      @lines.append(line)
     @lineMap[line.id] = line
     @length += line.length
     @length += 1 if @lines.length > 1
@@ -164,10 +162,7 @@
     [lineNode1, lineNode2] = Tandem.Utils.splitNode(line.node, offset, true)
     line.node = lineNode1
     this.updateLine(line)
-    newLine = new Tandem.Line(this, lineNode2)
-    @lines.insertAfter(line, newLine)
-    @lineMap[newLine.id] = newLine
-    @length += 1
+    this.insertLineBefore(lineNode2, line.next)

   toDelta: ->
     lines = @lines.toArray()


Faster list proxying.

Faster list proxying.

--- src/document.coffee
+++ src/document.coffee
@@ -13,6 +13,10 @@

 ###
 util = require 'util'
+
+
+# TODO: Expose this?
+auto_map_queries = true

 ###
@@ -214,8 +218,8 @@
               if util.isArray existing
                 # If we have an array, we need to map all the embedded
                 # documents in that array
-                for item, i in existing
-                  existing[i] = _proxy item, embed_proto
+                for item in existing
+                  _proxy item, embed_proto
                 # As well as add the 'new' method to the array itself
                 existing = _proxy existing, array_proto
               else


Adding Color.mix

Adding Color.mix

--- test/color.coffee
+++ test/color.coffee
@@ -251,5 +251,16 @@
   equals darkColor.g(), 24
   equals darkColor.b(), 12

+test "Color.mix", ->
+  color1 = Color(33, 55, 100)
+  color2 = Color(50, 90, 200)
+
+  mixedColor = Color.mix(color1, color2)
+
+  ok mixedColor.equals
+    r: -> 41
+    g: -> 72
+    b: -> 150
+
 module()


Updated packages

Updated packages

--- src/index.coffee
+++ src/index.coffee
@@ -1,16 +1,15 @@
-
-yaml_front = require 'yaml-front-matter'
+_assign = require 'lodash/assign'
+_find = require 'lodash/find'
+_has = require 'lodash/has'
+fs = require 'fs'
 highlight = require 'highlight.js'
 marked = require 'marked'
+mkdirp = require 'mkdirp'
+moment = require 'moment'
+path = require 'path'
 pug = require 'pug'
 slug = require 'slug'
-_assign = require 'lodash/assign'
-_has = require 'lodash/has'
-_find = require 'lodash/find'
-mkdirp = require 'mkdirp'
-fs = require 'fs'
-path = require 'path'
-moment = require 'moment'
+yaml_front = require 'yaml-front-matter'

 module.exports = class ClumsyBrunch


fix stupid error

fix stupid error

--- src/index.coffee
+++ src/index.coffee
@@ -85,7 +85,7 @@
   d = Q.defer()
   try
     cassandraConfig = config.cassandra
-    if cassandraConfig.datacenterName? && cassandraConfig.useSingleNode?
+    if cassandraConfig.datacenterName? && cassandraConfig.useSingleNode
       dcAwareRoundRobinPolicy = new cassandra.policies.loadBalancing.DCAwareRoundRobinPolicy(cassandraConfig.datacenterName)
       tokenAwarePolicy = new cassandra.policies.loadBalancing.TokenAwarePolicy(dcAwareRoundRobinPolicy)
       nodeWhiteList = [ firstNodeWithPort(cassandraConfig) ]


Allow deselecting an item with ctrlKey

Allow deselecting an item with ctrlKey

--- src/index.coffee
+++ src/index.coffee
@@ -138,6 +138,16 @@
       @_firstSelectedNode = startElement
       selectedNode.classList.add 'selected' for selectedNode in @selectedNodes
     else
+      if event.ctrlKey
+        index = @selectedNodes.indexOf element
+        if index != -1
+          @selectedNodes.splice index, 1
+          element.classList.remove 'selected'
+
+          if @_firstSelectedNode = element
+            @_firstSelectedNode = @selectedNodes[0]
+          return
+
       @addToSelection element
     return


Addresses #1: make *search* a *lookup* alias

--- src/index.coffee
+++ src/index.coffee
@@ -22,6 +22,7 @@

 commands =
   lookup: lookup
+  search: lookup # alias
   add: add
   watch: watch
   'watch-till': watchTill


https support

https support

use like this:

gulp.task('connect', function() { plugins.connect.server({
      root: ['../resource-bundles/myNewAppDev.resource'],
      https: {
        key:gulp.src('node_modules/gulp-connect/server.key'),
        cert:gulp.src('node_modules/gulp-connect/server.crt'),
        ca:gulp.src('node_modules/gulp-connect/ca.crt'),
        passphrase: 'gulp'
      },
      port: 9000,
      livereload: true
  })
});

--- src/index.coffee
+++ src/index.coffee
@@ -21,7 +21,15 @@
   server: ->
     middleware = @middleware()
     app = connect.apply(null, middleware)
-    server = http.createServer(app)
+    if opt.https?
+      server = https.createServer
+        key: opt.https.key || fs.readFileSync 'certs/server.key'
+        cert: opt.https.cert || fs.readFileSync 'certs/server.crt'
+        ca: opt.https.ca || fs.readFileSync 'certs/ca.crt'
+        passphrase: opt.https.passphrase || 'gulp'
+        app
+    else
+      server = http.createServer app
     app.use connect.directory(if typeof opt.root == "object" then opt.root[0] else opt.root)
     server.listen opt.port
     @log "Server started http://#{opt.host}:#{opt.port}"


Fix class name of footnotes

Fix class name of footnotes

--- src/index.coffee
+++ src/index.coffee
@@ -130,7 +130,7 @@
             $ 'a', {key: k+'-p-a', href: "#fnref#{def.footnoteNumber}"}, '↩'
           ]
         $ 'li', {key: k, id: "fn#{def.footnoteNumber}"}, defBody
-      $ 'div', {key, class: 'footnotes'}, [
+      $ 'div', {key, className: 'footnotes'}, [
         $ 'hr', {key: key+'-hr'}
         $ 'ol', {key: key+'-ol'}, items
       ]


Move mongoose connection to start method.

--- src/index.coffee
+++ src/index.coffee
@@ -16,8 +16,6 @@

 mongoose.Promise        = global.Promise
-
-mongoose.connect 'mongodb://localhost/test'

 process.on 'uncaughtException', (err) ->
   console.log 'uncaughtException', err
@@ -128,6 +126,7 @@

 Nodeswork.prototype.start = () ->
+  mongoose.connect 'mongodb://localhost/test'
   @dbConnection  = {}
   @server        = new koa()
   @server


Event names are lowercase.

Event names are lowercase.

--- Web/js/rohbot.coffee
+++ Web/js/rohbot.coffee
@@ -32,7 +32,7 @@

 		chatMgr.scrollToBottom()

-	rohbot.on 'chatHistory', (data) ->
+	rohbot.on 'chathistory', (data) ->
 		chatMgr.addChatHistory data.Lines, data.Requested

 		requestedHistory = false if data.Requested
@@ -54,7 +54,7 @@
 				notifications.doNotification roomName,
 					htmlDecode line.Sender + ': ' + line.Content

-	rohbot.on 'sysMessage', (line) ->
+	rohbot.on 'sysmessage', (line) ->
 		line.Type = 'state'
 		chatMgr.addLine line

@@ -72,7 +72,7 @@
 		user.Color = user.Playing ? "ingame" : ( user.Web ? "web" : "" )
 		return user

-	rohbot.on 'userList', (users) ->
+	rohbot.on 'userlist', (users) ->
 		chatMgr.statusMessage 'In this room: '
 		chatMgr.addHtml templates.users.render
 			Users: users.filter(userListFilter).map(userListMap)


one last fix

one last fix

--- src/modules/link-tooltip.coffee
+++ src/modules/link-tooltip.coffee
@@ -59,7 +59,7 @@
         anchor = this._findAnchor(@range)
         anchor.href = url if anchor?
       else
-        @quill.formatText(@range, 'link', url, 'user') if @range?
+        @quill.formatText(@range, 'link', url, 'user')
     this.setMode(url, false)

   setMode: (url, edit = false) ->


refac

refac

--- src/executor.coffee
+++ src/executor.coffee
@@ -13,18 +13,18 @@
     arr = []
     sheql = {}

-    sheql.getCollections = (ast, itemCollection, startDate, endDate, filterName)->
+    getCollections = (ast, itemCollection, startDate, endDate, filterName)->
         filteredCollection = []
         _cb = collectionBuilder[filterName]
         if ast[filterName]
             if itemCollection.length > 0
                 _.each itemCollection, (item)=>
                     tmpCollection = _cb.getCollection item.startDate, item.endDate
-                    arr.push.apply filteredCollection, @filterCollection tmpCollection, ast[filterName]
+                    arr.push.apply filteredCollection,  sheql.filterCollection tmpCollection, ast[filterName]
+
             else
                 tmpCollection = _cb.getCollection startDate, endDate
-                filteredCollection = @filterCollection tmpCollection, ast[filterName]
-
+                filteredCollection = sheql.filterCollection tmpCollection, ast[filterName]
             filteredCollection
         else

@@ -53,16 +53,16 @@
         ast = lexer.parser str

         itemCollection = []
-        itemCollection = @getCollections ast, itemCollection, startDate, endDate, 'y'
+        itemCollection = getCollections ast, itemCollection, startDate, endDate, 'y'

         # console.log itemCollection
-        itemCollection = @getCollections ast, itemCollection, startDate, endDate, 'm'
+        itemCollection = getCollections ast, itemCollection, startDate, endDate, 'm'

         # console.log itemCollection
-        itemCollection = @getCollections ast, itemCollection, startDate, endDate, 'w'
+        itemCollection = getCollections ast, itemCollection, startDate, endDate, 'w'

         # console.log itemCollection
-        itemCollection = @getCollections ast, itemCollection, startDate, endDate, 'd'
+        itemCollection = getCollections ast, itemCollection, startDate, endDate, 'd'

         _.map itemCollection, (i) -> i.value


[fix] queue cleaning from OptimalBits/bull#83

--- test/index.coffee
+++ test/index.coffee
@@ -51,6 +51,20 @@
       expect(bond.called).to.be.true

+queuename = "test"
+
+## https://github.com/OptimalBits/bull/issues/83
+qCleaner  = (queue) ->
+  clean = queue.clean.bind queue, 0
+  queue.pause()
+       .then clean 'completed'
+       .then clean 'active'
+       .then clean 'delayed'
+       .then clean 'failed'
+       .then -> queue.empty()
+       # .then -> queue.close()
+
+
 describe "BullModel", ->
   client   = null
   instance = null
@@ -77,24 +91,22 @@
   describe "##createJobInQueue", ->
     it "should create a new bull queue if none exists", (done) ->
       ideally   = errify done
-      queuename = "test"
       data      = {name: "testjob"}

       await instance.createJobInQueue queuename, data, ideally defer job
       queue = instance.queues[queuename]
       expect(queue).to.exist
-      queue.empty().then(queue.close()).asCallback done
+      qCleaner(queue).asCallback done

     it "should add a job to a bull queue", (done) ->
       ideally   = errify done
-      queuename = "test"
       data      = {name: "testjob"}

       await instance.createJobInQueue queuename, data, ideally defer job
       queue = instance.queues[queuename]
       await queue.count().asCallback ideally defer count
       expect(count).to.equal 1
-      queue.empty().then(queue.close()).asCallback done
+      qCleaner(queue).asCallback done

 describe "RedisModel", ->


Rename `beforeWrite` to `minify`.

Rename `beforeWrite` to `minify`.

--- src/fs_utils.coffee
+++ src/fs_utils.coffee
@@ -330,16 +330,14 @@
   ###

   write: (fileList) =>
-    beforeWrite = @plugins
-      .filter (plugin) ->
-        plugin.beforeWrite
-      .map (plugin) ->
-        (files, callback) -> plugin.beforeWrite files, callback
+    minifiers = @plugins
+      .filter((plugin) -> plugin.minify)
+      .map((plugin) -> plugin.minify)
     getFiles = (callback) => callback null, @getFiles fileList
     write = (file, callback) -> file.write callback

-    async.waterfall [getFiles, beforeWrite...], (error, files) =>
-      return helpers.logError "plugin error. #{error}" if error?
+    async.waterfall [getFiles, minifiers...], (error, files) =>
+      return helpers.logError "minify error. #{error}" if error?
       async.forEach files, write, (error, results) =>
         return helpers.logError "write error. #{error}" if error?
         @emit 'write', results


saner

saner

--- tests-coffee/unit/even-array-test.coffee
+++ tests-coffee/unit/even-array-test.coffee
@@ -5,12 +5,15 @@
 nums = null
 even = null

-module 'Integration - Pagination',
+module 'Integration - FilteredArray',
   setup: ->
     observer = MyObserver.create()
     nums = Ember.A([1,2,3,4,5])
     even = EvenArray.create(all: nums)
+
+    console.debug "adding observer"
     even.addArrayObserver(observer)
+    console.debug "Added observer"

   tearDown: ->
     observer = null
@@ -20,33 +23,37 @@

 FilteredObserver = Ember.Object.extend
   arrayWillChange: (observedObj, start, removeCount, addCount) ->
-    @parent.triggerObservers('arrayWillChange',observedObj, start, removeCount, addCount)
+    # do nothing

   arrayDidChange: (observedObj, start, removeCount, addCount) ->
     for i in [start...(start+addCount)]
       obj = observedObj[i]
-      if @parent.filterFunc(obj,i)
-        @parent.triggerObservers('arrayDidChange',observedObj, i, 0, 1)
+      if @get('parent').filterFunc(obj,i)
+        @get('parent').pushObject(obj)

-FilteredArray = Ember.Object.extend
-  observers: []
+FilteredArray = Ember.Object.extend Ember.MutableArray,
+  init: (ops) ->
+    @get('all').addArrayObserver(FilteredObserver.create(parent: this))

-  init: ->
-    @all.addArrayObserver(FilteredObserver.create(parent: this))
+  "[]": (->
+    c = []
+    i = 0
+    for num in @get('all')
+      if @filterFunc(num,i)
+        c.push(num)
+      i += 1
+    Ember.A(c)).property()

-  forEach: (f) ->
-    i = 0
-    for num in @all
-      if @filterFunc(num,i)
-        f(num)
-      i += 1
+  replace: (i,thing,objects) ->
+    for obj in objects
+      @get('[]').pushObject(obj)
+      @arrayContentDidChange(@get('[].length')-1,0,1)

-  addArrayObserver: (target) ->
-    @observers.push(target)
+  objectAt: (i) ->
+    @get('[]').objectAt(i)

-  triggerObservers: (method, observedObj, start, removeCount, addCount) ->
-    @observers.forEach (o) -> o[method](observedObj, start, removeCount, addCount)
+  lengthBinding: "[].length"

 EvenArray = FilteredArray.extend
   filterFunc: (num) -> num%2 == 0
@@ -80,60 +87,62 @@
   equalArray even,[2,4]

 test 'forEach up to date when all changes', ->
-  nums.pushObject(8)
+  Ember.run -> nums.pushObject(8)
   equalArray even,[2,4,8]

 test 'observer of EvenArray is updated', ->
-  nums.pushObject(8)
-  equal observer.get('arrayDidChangeCount'),1
+  Ember.run -> nums.pushObject(8)
+  Ember.run -> equal observer.get('arrayDidChangeCount'),1

 test 'observer of EvenArray is not updated on odd', ->
-  nums.pushObject(9)
+  Ember.run -> nums.pushObject(9)
   equal observer.get('arrayDidChangeCount'),0

 test 'filtered array with max size', ->
-  observer = MyObserver.create()
-  nums = Ember.A([1,2,3,4,5])
-  even = FilteredArray.create(all: nums, filterFunc: (num,i) -> i <= 3)
-  even.addArrayObserver(observer)
+  Ember.run ->
+    observer = MyObserver.create()
+    nums = Ember.A([1,2,3,4,5])
+    even = FilteredArray.create(all: nums, filterFunc: (num,i) -> i <= 3)
+    even.addArrayObserver(observer)

   equalArray even,[1,2,3,4]

-  nums.pushObject(9)
+  Ember.run -> nums.pushObject(9)
   equalArray even,[1,2,3,4]

 test 'filtered array with max size 2', ->
-  observer = MyObserver.create()
-  nums = Ember.A([1,2,3,4,5])
-  even = FilteredArray.create(all: nums, filterFunc: (num,i) -> i <= 5)
-  even.addArrayObserver(observer)
+  Ember.run ->
+    observer = MyObserver.create()
+    nums = Ember.A([1,2,3,4,5])
+    even = FilteredArray.create(all: nums, filterFunc: (num,i) -> i <= 5)
+    even.addArrayObserver(observer)

   equalArray even,[1,2,3,4,5]

-  nums.pushObject(6)
+  Ember.run -> nums.pushObject(6)
   equal observer.get('arrayDidChangeCount'),1

-  nums.pushObject(7)
+  Ember.run -> nums.pushObject(7)
   equal observer.get('arrayDidChangeCount'),1

 test 'observer updates when multiple pushed at once', ->
-  nums.pushObjects([8,10])
+  Ember.run -> nums.pushObjects([8,10])
   equal observer.get('arrayDidChangeCount'),2

 test 'make FilteredArray on the fly', ->
-  observer = MyObserver.create()
-  nums = Ember.A([1,2,3,4,5])
-  even = FilteredArray.create(all: nums, filterFunc: (num) -> num >= 3)
-
-  even.addArrayObserver(observer)
+  Ember.run ->
+    observer = MyObserver.create()
+    nums = Ember.A([1,2,3,4,5])
+    even = FilteredArray.create(all: nums, filterFunc: (num) -> num >= 3)
+    even.addArrayObserver(observer)

   equalArray even,[3,4,5]

-  nums.pushObject(-4)
+  Ember.run -> nums.pushObject(-4)
   equal observer.get('arrayDidChangeCount'),0

-  nums.pushObject(8)
+  Ember.run -> nums.pushObject(8)
   equal observer.get('arrayDidChangeCount'),1
   equalArray even,[3,4,5,8]


Made named function calls easier to see

Made named function calls easier to see

--- editor-plugins/atom/grammars/dyon.cson
+++ editor-plugins/atom/grammars/dyon.cson
@@ -174,6 +174,13 @@
       '1': { 'name': 'entity.name.function.dyon' }
     }
   }
+  {
+    'comment': 'Named argument'
+    'match': '\\b([a-zA-Z_][a-zA-Z0-9_]*)\\:'
+    'captures': {
+      '1': { 'name': 'entity.name.function.dyon' }
+    }
+  }
   # Function definition
   {
     'comment': 'Function definition'


Start test for .write

Start test for .write

--- test/utils.coffee
+++ test/utils.coffee
@@ -148,7 +148,7 @@
     And -> console.log @cb.getCall(0).args
     Then -> expect(@cb).to.have.been.calledWith null, 'some words we found in xanadu'

-
+  describe '.write', ->


Using 'literal' instead of 'lit'.

Using 'literal' instead of 'lit'.

--- lib/formats/jsonschema-v4.coffee
+++ lib/formats/jsonschema-v4.coffee
@@ -5,18 +5,18 @@

 # Takes literal and MSON type and provides JSON Schema value in corresponding type.
-coerceLiteral = (lit, typeName, cb) ->
+coerceLiteral = (literal, typeName, cb) ->
   switch typeName
     when 'string'
-      return cb null, lit
+      return cb null, literal
     when 'number'
-      return cb new Error "Literal '#{lit}' is not a number." if isNaN lit
-      return cb null, parseFloat lit
+      return cb new Error "Literal '#{literal}' is not a number." if isNaN literal
+      return cb null, parseFloat literal
     when 'boolean'
-      return cb new Error "Literal '#{lit}' is not 'true' or 'false'." if lit not in ['true', 'false']
-      return cb null, lit is 'true'
+      return cb new Error "Literal '#{literal}' is not 'true' or 'false'." if literal not in ['true', 'false']
+      return cb null, literal is 'true'
     else
-      return cb new Error "Literal '#{lit}' can't have type '#{typeName}'."
+      return cb new Error "Literal '#{literal}' can't have type '#{typeName}'."

 # Turns multiple member nodes into 'resolved members', i.e. objects


minor improvement

minor improvement

--- library/semantic/formular.coffee
+++ library/semantic/formular.coffee
@@ -89,12 +89,13 @@
     # of the fields have warning metadata attached to it. If so, a
     # warning is added to the list of messages and the field marked
     # with an error tag, which makes its validity visually distinct.
-    messages: (heading) ->
+    messages: (heading, force) ->
         assert @container.removeClass "warning error"
         @errors.detach(); @warnings.prependTo @container
         @warnings.empty(); list = $ "<ul>", class: "list"
         h = $("<div>", class: "header").appendTo @warnings
         h.text heading.toString(); list.appendTo @warnings
+        return this.container.addClass "warning" if force
         assert fields = @container.find(".field") or []
         sieve = (seq) -> _.filter seq, (value) -> value
         sieve _.map fields, (value, index, iteratee) =>


upgrade standard formular to use @subwidget

--- library/semantic/standard.coffee
+++ library/semantic/standard.coffee
@@ -66,7 +66,8 @@
     # while it is being typed in. The field has the asterisk to it
     # and can optionally attach an icon to the field (recommended).
     # In other ways, it is structurally equal to `starred` field.
-    hidden: (identity, synopsis, icon) ->
+    # Please refer to `Widget` class for reference on subwidgets.
+    @subwidget hidden: (identity, synopsis, icon) ->
         assert _.isString(identity), "invalid field identity"
         assert _.isString(synopsis), "invalid field synopsis"
         assert _.isObject label = $ "<label>", class: "label"
@@ -90,7 +91,8 @@
     # either required or has some remarks to it or simply indicates
     # an elevated attention to the field. Oterwise, it is a simple
     # textual field that can optionally be tagged with a left icon.
-    starred: (identity, synopsis, icon) ->
+    # Please refer to `Widget` class for reference on subwidgets.
+    @subwidget starred: (identity, synopsis, icon) ->
         assert _.isString(identity), "invalid field identity"
         assert _.isString(synopsis), "invalid field synopsis"
         assert _.isObject input = $ "<input>", type: "text"
@@ -114,7 +116,8 @@
     # It is usually a good idea for indicating options selection
     # or agreement to some legal terms and conditions. The field
     # that it creates is rendered as inline (see semantic man).
-    checkbox: (identity, synopsis, onpos, onneg) ->
+    # Please refer to `Widget` class for reference on subwidgets.
+    @subwidget checkbox: (identity, synopsis, onpos, onneg) ->
         assert _.isString(identity), "invalid field identity"
         assert _.isString(synopsis), "invalid field synopsis"
         assert _.isString what = "ui checkbox" # wrapping sel
@@ -135,7 +138,8 @@
     # It is usually a good idea for indicating options selection
     # or agreement to some legal terms and conditions. The field
     # that it creates is rendered as inline (see semantic man).
-    sliding: (identity, synopsis, onpos, onneg) ->
+    # Please refer to `Widget` class for reference on subwidgets.
+    @subwidget sliding: (identity, synopsis, onpos, onneg) ->
         assert _.isString(identity), "invalid field identity"
         assert _.isString(synopsis), "invalid field synopsis"
         assert _.isString what = "ui checkbox slider" # wrap sel
@@ -156,7 +160,8 @@
     # It is usually a good idea for indicating options selection
     # or agreement to some legal terms and conditions. The field
     # that it creates is rendered as inline (see semantic man).
-    toggling: (identity, synopsis, onpos, onneg) ->
+    # Please refer to `Widget` class for reference on subwidgets.
+    @subwidget toggling: (identity, synopsis, onpos, onneg) ->
         assert _.isString(identity), "invalid field identity"
         assert _.isString(synopsis), "invalid field synopsis"
         assert _.isString what = "ui checkbox toggle" # wrap sel
@@ -177,7 +182,8 @@
     # can be tagged by an icon on the left side of the field. It is
     # a good idea to use such a field for inputting sorts data that
     # is not strictly required, but is usually optional, as example.
-    regular: (identity, synopsis, icon) ->
+    # Please refer to `Widget` class for reference on subwidgets.
+    @subwidget regular: (identity, synopsis, icon) ->
         assert _.isString(identity), "invalid field identity"
         assert _.isString(synopsis), "invalid field synopsis"
         assert _.isObject input = $ "<input>", type: "text"


fix btn disable

fix btn disable

--- views/tagsInputContainer.cjsx
+++ views/tagsInputContainer.cjsx
@@ -21,6 +21,7 @@
     @props.handleTagAddClick tagInput
     @setState
       tagInput: ''
+      tagDisable: true
   render: ->
     <div className='tags-input-container'>
       <Input style={margin: 10}


Fix a step about hierarchy.

Fix a step about hierarchy.

--- features/step_definitions/steps.coffee
+++ features/step_definitions/steps.coffee
@@ -138,10 +138,10 @@
     try
       s    = system.fetch(source)
       t    = system.fetch(target)
-      neg  = ((neg == undefined) ? false : true)
+      neg  = (neg? ? true : false)
       isIt = s.isSuperTypeOf(t)
       unless isIt == neg
-        callback.fail("Expected #{source} #{(if neg then 'not' else '')} to be a super type of #{target}")
+        callback.fail("Expected #{source}#{(if neg then ' not' else '')} to be a super type of #{target}")
     catch e
       error = e
       callback.fail(e)


Fix snapping to currentPage

Fix snapping to currentPage

--- framer/Components/PageComponent.coffee
+++ framer/Components/PageComponent.coffee
@@ -62,11 +62,12 @@
 		return _.first(layers)

 	snapToPage: (page, animate=true, animationOptions=null) ->
-		return unless @currentPage isnt page
 		@scrollToLayer(page, @originX, @originY, animate, animationOptions)
-		@_previousPages.push(page)
-		@emit("change:previousPage", @previousPage)
-		@emit("change:currentPage", @currentPage)
+
+		if @currentPage isnt page
+			@_previousPages.push(page)
+			@emit("change:previousPage", @previousPage)
+			@emit("change:currentPage", @currentPage)

 	snapToNextPage: (direction="right", animate=true, animationOptions=null) ->
 		animationOptions ?= @animationOptions


protocol: Give better error if graph is not defined

--- src/protocol.coffee
+++ src/protocol.coffee
@@ -5,6 +5,7 @@

 exports.sendGraph = (runtime, graph , callback) ->
   main = false # this is a component?
+  return callback new Error "Graph not defined" if not graph

   graphId = graph.name or graph.properties.id
   graphId = "fixture.#{common.randomString(10)}" if not graphId


Fix bug where empty files where created for content plugins that did not render anything. (render callback returned null instead of a readStream)

--- src/renderer.coffee
+++ src/renderer.coffee
@@ -30,16 +30,18 @@

   renderPlugin = (content, callback) ->
     destination = path.join location, content.filename
-    writeStream = fs.createWriteStream destination
     logger.verbose "writing content #{ content.url } to #{ destination }"
     content.render locals, contents, templates, (error, result) ->
       if error
         callback error
-      else if result instanceof fs.ReadStream
-        util.pump result, writeStream, callback
-      else if result instanceof Buffer
-        writeStream.write result
-        writeStream.end()
+      else if result instanceof fs.ReadStream or result instanceof Buffer
+        # TODO: use in-memory readstreams instead of buffers if possible
+        writeStream = fs.createWriteStream destination
+        if result instanceof fs.ReadStream
+          util.pump result, writeStream, callback
+        else
+          writeStream.write result
+          writeStream.end()
         callback()
       else
         logger.verbose "skipping #{ content.url }"


add back fix present in last reverted commit

--- src/rewriter.coffee
+++ src/rewriter.coffee
@@ -470,7 +470,7 @@
 EXPRESSION_CLOSE = ['CATCH', 'THEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END

 # Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
-IMPLICIT_FUNC    = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', '@@', 'THIS']
+IMPLICIT_FUNC    = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']

 # If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
 IMPLICIT_CALL    = [


fix bug caused from failing to bind(this)

--- src/sailthru.coffee
+++ src/sailthru.coffee
@@ -65,7 +65,7 @@

         @log2 method + ' Request'

-        req = http_protocol.request options, (res) ->
+        req = http_protocol.request options, ((res) ->
             body = ''
             res.setEncoding 'utf8'
             statusCode = res.statusCode
@@ -90,6 +90,7 @@
                         error: 0,
                         errormsg: error.message
                     callback json_err, error.message
+        ).bind(this)
         req.on 'error', (err) ->
             callback err, err.message
         req.write url.format({query: options.query}).replace('?', ''), 'utf8' if method is 'POST'


better grouping

better grouping

--- src/steroids.coffee
+++ src/steroids.coffee
@@ -1,19 +1,11 @@
 Help = require "./steroids/Help"
-
-
 Grunt = require "./steroids/Grunt"
-
+paths = require "./steroids/paths"
+
+argv = require('optimist').argv
 util = require "util"
-
-paths = require "./steroids/paths"
-
-argv = require('optimist').argv
 open = require "open"
-
 fs = require("fs")
-
-
-
 chalk = require "chalk"

 class Steroids


Fix invalid tag test

Fix invalid tag test

--- test/response-cache-test.coffee
+++ test/response-cache-test.coffee
@@ -37,7 +37,7 @@
   expected = { noMatch: ['*'], match: undefined, modifiedSince: undefined, unmodifiedSince: undefined }
   assert.eql expected, responseCache.getRequestCacheInfo({ 'IF-nonE-match': '*' }), 'if-none-match star'

-  assert.eql expected, responseCache.getRequestCacheInfo({ 'IF-nonE-match': dateStr }), 'if-none-match invalid'
+  assert.eql undefined, responseCache.getRequestCacheInfo({ 'IF-nonE-match': dateStr }), 'if-none-match invalid'

 #
 # getResponseCacheInfo


Clear Webhook before polling the Telegram API

--- src/telegram.coffee
+++ src/telegram.coffee
@@ -231,6 +231,11 @@
                 res.send 'OK'

         else
+	    # Clear Webhook
+            @api.invoke 'setWebHook', { url: null }, (err, result) ->
+                if (err)
+                    self.emit 'error', err
+
             setInterval ->

                 self.api.invoke 'getUpdates', { offset: self.getLastOffset(), limit: 10 }, (err, result) ->


Improved descriptions (English) [redux]

Improved descriptions (English) [redux]

RAML file names now referenced via variables. (DRY)
Updates make descriptions more consistent. Minor wordsmithing.

--- test/unit/add-tests-test.coffee
+++ test/unit/add-tests-test.coffee
@@ -12,6 +12,10 @@
   'mocha': mochaStub
 }

+FIXTURE_DIR = "#{__dirname}/../fixtures"
+RAML_DIR = "#{FIXTURE_DIR}"
+
+
 describe '#addTests', ->

   describe '#run', ->
@@ -23,20 +27,21 @@
       callback = ''

       before (done) ->
-        ramlParser.loadFile("#{__dirname}/../fixtures/single-get.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added 1 test', ->
+        ramlFile = "#{RAML_DIR}/single-get.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 1 test', ->
         assert.lengthOf tests, 1

       it 'should set test.name', ->
@@ -71,20 +76,21 @@

       before (done) ->

-        ramlParser.loadFile("#{__dirname}/../fixtures/1-get-1-post.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added 2 test', ->
+        ramlFile = "#{RAML_DIR}/1-get-1-post.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 2 tests', ->
         assert.lengthOf tests, 2

       it 'should setup test.request of POST', ->
@@ -118,20 +124,21 @@

       before (done) ->

-        ramlParser.loadFile("#{__dirname}/../fixtures/ref_other_schemas.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added 1 test', ->
+        ramlFile = "#{RAML_DIR}/ref_other_schemas.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 1 test', ->
         assert.lengthOf tests, 1

       it 'should set test.name', ->
@@ -162,20 +169,21 @@

       before (done) ->

-        ramlParser.loadFile("#{__dirname}/../fixtures/inline_and_included_schemas.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added 1 test', ->
+        ramlFile = "#{RAML_DIR}/inline_and_included_schemas.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 1 test', ->
         assert.lengthOf tests, 1

       it 'should set test.name', ->
@@ -206,21 +214,22 @@

       before (done) ->

-        ramlParser.loadFile("#{__dirname}/../fixtures/three-levels.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added 3 test', ->
+        ramlFile = "#{RAML_DIR}/three-levels.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 3 tests', ->
         assert.lengthOf tests, 3

       it 'should set test.name', ->
@@ -246,21 +255,22 @@

       before (done) ->

-        ramlParser.loadFile("#{__dirname}/../fixtures/no-method.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added 1 test', ->
+        ramlFile = "#{RAML_DIR}/no-method.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 1 test', ->
         assert.lengthOf tests, 1

       it 'should set test.name', ->
@@ -312,26 +322,27 @@
         assert.lengthOf tests, 1
         assert.equal tests[0].name, 'POST /machines -> 204'

-    describe 'when raml contains vendor specifc JSON content-types', ->
-      tests = []
-      testFactory = new TestFactory()
-      callback = ''
-
-      before (done) ->
-        ramlParser.loadFile("#{__dirname}/../fixtures/vendor-content-type.raml")
-        .then (data) ->
-          callback = sinon.stub()
-          callback.returns(done())
-
-          addTests data, tests, hooks, callback, testFactory
-        , done
-      after ->
-        tests = []
-
-      it 'should run callback', ->
-        assert.ok callback.called
-
-      it 'should added a test', ->
+    describe 'when RAML media type uses a JSON-suffixed vendor tree subtype', ->
+      tests = []
+      testFactory = new TestFactory()
+      callback = ''
+
+      before (done) ->
+        ramlFile = "#{RAML_DIR}/vendor-content-type.raml"
+        ramlParser.loadFile(ramlFile)
+        .then (data) ->
+          callback = sinon.stub()
+          callback.returns(done())
+
+          addTests data, tests, hooks, callback, testFactory
+        , done
+      after ->
+        tests = []
+
+      it 'should run callback', ->
+        assert.ok callback.called
+
+      it 'should add 1 test', ->
         assert.lengthOf tests, 1

       it 'should setup test.request of PATCH', ->
@@ -355,3 +366,4 @@
         schema = res.schema
         assert.equal schema.properties.title.type, 'string'
         assert.equal schema.properties.artist.type, 'string'
+


add tests for @b-if

add tests for @b-if

--- test/index-test.coffee
+++ test/index-test.coffee
@@ -195,3 +195,37 @@
         ]
         template = bHtml source
         assert.deepEqual template(context), expected
+
+  context '@b-if', ->
+    context 'simple', ->
+      it 'works', ->
+        source = '''
+          <p
+            @b-if isShow
+        '''
+        context =
+          isShow: false
+        expected = []
+        template = bHtml source
+        assert.deepEqual template(context), expected
+
+    context 'complex', ->
+      it 'works', ->
+        source = '''
+          <p
+            @b-if parent
+            <span
+              @b-if child
+              hide
+            show
+        '''
+        context =
+          parent: true
+          child: false
+        expected = [
+          tag: 'p'
+          attrs: {}
+          children: ['show']
+        ]
+        template = bHtml source
+        assert.deepEqual template(context), expected


Cleanup.

Cleanup.

--- test/jnoid_spec.coffee
+++ test/jnoid_spec.coffee
@@ -46,7 +46,7 @@

 describe 'map', ->
   it 'transforms values', (done)->
-    stream= Jnoid.fromList([1, 2, 3])
+    stream = Jnoid.fromList([1, 2, 3])
     expectEvents [2, 4, 6],
       stream.map((x)-> x * 2),
       done
@@ -55,7 +55,7 @@
   events = []
   stream.onValue (event) ->
     if event.isEnd()
-      assert.deepEqual(expectedEvents, events)
+      assert.deepEqual(events, expectedEvents)
       done()
     else
       events.push(event.value)


more tests

more tests

--- test/model.test.coffee
+++ test/model.test.coffee
@@ -58,7 +58,7 @@
           post.userId.should.equal user.id
           done()

-      it 'should load hasMany relation', (done) ->
+      it 'should load hasMany relation - style #1', (done) ->
         user.addPost getFakePost()
         user.addPost getFakePost()
         user.save (err) ->
@@ -72,4 +72,11 @@
             u.posts.should.be.an('array').with.lengthOf 3
             # console.log 2, u.posts.length, typeOf u.posts
             should.not.exist err
-            done()+            done()
+
+      it 'should load hasMany relation - style #2 (the shortest)', (done) ->
+        User.get(user.id).with 'posts', (err, u) ->
+          u.posts.should.be.an('array').with.lengthOf 3
+          # console.log 2, u.posts.length, typeOf u.posts
+          should.not.exist err
+          done()


Fixed name tests after switching to SHA1 hashing

--- test/names_test.coffee
+++ test/names_test.coffee
@@ -60,21 +60,21 @@

   describe "from ID", ->
     it "should return given name and first letter of family name", ->
-      assert.equal name("85bb3cfe1"), "Lester G."
+      assert.equal name("85bb3cfe1"), "Willie I."

     it "should return female names", ->
-      assert.equal name("1ff4efbdf"), "Dawn Y."
+      assert.equal name("1ff4efbdf"), "Dawn A."

     it "should return male names", ->
-      assert.equal name("7864c456f"), "Bobby Y."
+      assert.equal name("7864c456f"), "James A."

     it "should return same name consistently for same ID", ->
       ids = ["07F9F5E2F3", "07F9F5E2F3", "07F9F5E2F3", "07F9F5E2F3", "07F9F5E2F3", "07F9F5E2F3"]
       names = ids.map((id)-> name(id)).sort()
-      assert.deepEqual unique(names), ["Christina S."]
+      assert.deepEqual unique(names), ["Lester S."]

     it "should return different name for different ID", ->
       ids = ["07F9F5E2F3", "31F509B60E", "CDE02B9F4B", "D624D97240", "6913D09DA8", "8E44C8C990"]
       names = ids.map((id)-> name(id)).sort()
-      assert.deepEqual unique(names), ["Alonso M.","Christina S.","Eric Q.","Janet I.","Nancy U.","Trista A."]
+      assert.deepEqual unique(names), ["Alfonso O.", "Alicia Q.", "Christopher I.", "Goldie I.", "Lester S."]


avoid gratuitous names

avoid gratuitous names

--- games/tutorial.coffee
+++ games/tutorial.coffee
@@ -8,7 +8,7 @@
 exports.game = {
   name: 'The Hour of Node'
   assume: 'baseline'
-  comment: "The world's first NodeScript program"
+  comment: "The world's first Hour of Node program"
   author: {name: 'David Huffman', url: 'mailto:david%40theswanfactory.com'}
   license: {
     name: 'Creative Commons Attribution 4.0 International'
@@ -56,7 +56,7 @@
       sprites: [
         { kind: 'wall', position: [5,0] }
         { kind: 'gate', actions: {interrupt: ['_victory']}, position: [4,4] }
-        {
+        {
           kind: 'turtle'
           actions: { run: ['forward'], interrupt: ['right'] }
           editable: false
@@ -112,7 +112,7 @@
       bricks: 1
       sprites: [
         { kind: 'gate', actions: {interrupt: ['_victory']}, position: [4,4] }
-        {
+        {
           kind: 'turtle'
           actions: { run: ['forward'], interrupt: ['right'] }
           editable: false


Add a test for modifying messages

Add a test for modifying messages

--- test/robot_test.coffee
+++ test/robot_test.coffee
@@ -725,3 +725,24 @@
             'doneA'
           ])
           testDone()
+
+      it 'allows editing the message portion of the given response', (testDone) ->
+        execution = []
+
+        testMiddlewareA = (context, next, done) ->
+          context.response.message.text = "foobar"
+          next()
+
+        testMiddlewareB = (context, next, done) ->
+          expect(context.response.message.text).to.equal("foobar")
+          next()
+
+        @robot.receiveMiddleware testMiddlewareA
+        @robot.receiveMiddleware testMiddlewareB
+
+        @robot.hear /^foobar$/, () ->
+          # We'll never get to this if testMiddlewareA has not modified the message.
+          testDone()
+
+        testMessage = new TextMessage @user, 'message123'
+        @robot.receive testMessage


fixed missing apply

fixed missing apply

--- addon/models/history.coffee
+++ addon/models/history.coffee
@@ -2,7 +2,7 @@
 `import {RelateableMixin, virtual} from 'autox'`
 `import Timestamps from 'autox/mixins/timestamps'`
 `import Ember from 'ember'`
-{RSVP} = Ember
+{RSVP, computed} = Ember
 History = DS.Model.extend RelateableMixin, Timestamps,
   recordableId: DS.attr "string",
     description: "The polymorphic id of an object that supports histories"
@@ -32,7 +32,8 @@
     label: "Event Summary"
     description: "Just the quick gist of this history event"
     display: ["index"]
-    apply "message", "scheduledAt", (message, scheduledAt) ->
+    computed "message", "scheduledAt", ->
+      {message, scheduledAt} = @getProperties("message", "scheduledAt")
       "#{scheduledAt.format('lll')} - #{message}"

   mentionedModel: ->


Re-enabled CSRF tokens.

Re-enabled CSRF tokens.

--- picoCTF-web/web/coffee/dependencies.coffee
+++ picoCTF-web/web/coffee/dependencies.coffee
@@ -1,4 +1,8 @@
 @apiCall = (type, url, data) ->
+
+  if type == "POST":
+    data.token = $.cookie("token")
+
   $.ajax {url: url, type: type, data: data, cache: false}
   .fail (jqXHR, text) ->
     $.notify "API is offline. :(", "error"


Make node more generic

Make node more generic

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -2,26 +2,30 @@
 {format, get, set, preventDefault} = require './helpers'

 class Node
-  constructor: (@ast, @model, @controller) ->
-    @element = Serenade.document.createElement(@ast.name)
-
-    @element.setAttribute('id', @ast.id) if @ast.id
-    @element.setAttribute('class', @ast.classes.join(' ')) if @ast.classes?.length
-
-    for property in @ast.properties
+  @element: (ast, model, controller) ->
+    element = Serenade.document.createElement(ast.name)
+    node = new Node(ast, element, model, controller)
+
+    element.setAttribute('id', ast.id) if ast.id
+    element.setAttribute('class', ast.classes.join(' ')) if ast.classes?.length
+
+    for property in ast.properties
       switch property.scope
         when "attribute"
           if property.name is "binding"
-            new TwoWayBinding(property, this, @model, @controller)
+            new TwoWayBinding(property, node, model, controller)
           else
-            new Attribute(property, this, @model, @controller)
-        when "style" then new Style(property, this, @model, @controller)
-        when "event" then new Event(property, this, @model, @controller)
-        when "binding" then new TwoWayBinding(property, this, @model, @controller)
+            new Attribute(property, node, model, controller)
+        when "style" then new Style(property, node, model, controller)
+        when "event" then new Event(property, node, model, controller)
+        when "binding" then new TwoWayBinding(property, node, model, controller)
         else throw SyntaxError "#{property.scope} is not a valid scope"

-    for child in @ast.children
-      Nodes.compile(child, @model, @controller).append(@element)
+    for child in ast.children
+      Nodes.compile(child, model, controller).append(element)
+    node
+
+  constructor: (@ast, @element, @model, @controller) ->

   append: (inside) ->
     inside.appendChild(@element)
@@ -318,7 +322,7 @@
 Nodes =
   compile: (ast, model, controller) ->
     switch ast.type
-      when 'element' then new Node(ast, model, controller)
+      when 'element' then Node.element(ast, model, controller)
       when 'text' then new TextNode(ast, model, controller)
       when 'instruction'
         switch ast.command


prefetch: fetching all main pages in sequence

--- app/_src/main.coffee
+++ app/_src/main.coffee
@@ -29,10 +29,14 @@

 FOURTEEN.onWindowLoad = ->
-  # prefetch work page - must have same path + querystring as pjax request will have
-  # This will only work when using Cloudflare configured to cache HTML
+  # prefetch main pages - must have same path + querystring as pjax request will have
+  # This will only work when sending far future headers for HTML
   if location.pathname is "/"
-    $.get('work/?_pjax=.js-pjax-container')
+    $.get('work/?_pjax=.js-pjax-container', ->
+      $.get('about/?_pjax=.js-pjax-container', ->
+        $.get('contact/?_pjax=.js-pjax-container')
+      )
+    )


Remove unique user IDs in Atom config

Remove unique user IDs in Atom config

--- roles/fedora_laptop/files/atom/config.cson
+++ roles/fedora_laptop/files/atom/config.cson
@@ -11,16 +11,14 @@
     useSnippets: "required"
   core:
     disabledPackages: [
+      "exception-reporting"
       "markdown-preview"
     ]
     telemetryConsent: "limited"
   editor:
     showIndentGuide: true
-  "exception-reporting":
-    userId: "a2c07b84-577e-2e1f-6364-19a81188bf7f"
   "git-plus":
-    general:
-      _analyticsUserId: "7c7df9ea-c0e9-44e9-8f76-384e0f077622"
+    general: {}
   linter: {}
   welcome:
     showOnStartup: false