stubs

stubs

--- src/stubs.coffee
+++ src/stubs.coffee
@@ -1,7 +1,5 @@
 ###*
 Non-standard
-
-

 @name toSource
 @methodOf Boolean#
@@ -46,8 +44,6 @@
 ###*
 number.toLocaleString();

-
-
 @name toLocaleString
 @methodOf Number#
 ###
@@ -61,8 +57,6 @@
 ###
 ###*
 Non-standard
-
-

 @name toSource
 @methodOf Number#
@@ -80,8 +74,6 @@
 ###*
 Returns the primitive value of a Number object.

-
-
 @name valueOf
 @methodOf Number#
 ###
@@ -89,7 +81,7 @@
 Returns the specified character from a string.

 string.charAt(index)
-@param index  An integer between 0 and 1 less than the length of the string.
+@param index  An integer between 0 and 1 less than the length of the string.
 @name charAt
 @methodOf String#
 ###
@@ -98,7 +90,7 @@
 for unicode codepoints > 0x10000).

-@param index  An integer greater than 0 and less than the length of the string;
+@param index  An integer greater than 0 and less than the length of the string;
 if it is not a number, it defaults to 0.
 @name charCodeAt
 @methodOf String#
@@ -107,7 +99,7 @@
 Combines the text of two or more strings and returns a new string.

 string.concat(string2, string3[, ..., stringN])
-@param string2...stringN  Strings to concatenate to this string.
+@param string2...stringN  Strings to concatenate to this string.
 @name concat
 @methodOf String#
 ###
@@ -117,8 +109,8 @@
 returns -1 if the value is not found.

 string.indexOf(searchValue[, fromIndex]
-@param searchValue  A string representing the value to search for.
-@param fromIndex  The location within the calling string to start the search
+@param searchValue  A string representing the value to search for.
+@param fromIndex  The location within the calling string to start the search
 from. It can be any integer between 0 and the length of the string. The default
 value is 0.
 @name indexOf
@@ -130,8 +122,8 @@
 starting at fromIndex.

 string.lastIndexOf(searchValue[, fromIndex])
-@param searchValue  A string representing the value to search for.
-@param fromIndex  The location within the calling string to start the search
+@param searchValue  A string representing the value to search for.
+@param fromIndex  The location within the calling string to start the search
 from, indexed from left to right. It can be any integer between 0 and the length
 of the string. The default value is the length of the string.
 @name lastIndexOf
@@ -166,21 +158,21 @@
 ###
 ###*
 Returns a new string with some or all matches of a pattern replaced by a
-replacement.  The pattern can be a string or a RegExp, and the replacement can
+replacement.  The pattern can be a string or a RegExp, and the replacement can
 be a string or a function to be called for each match.

 str.replace(regexp|substr, newSubStr|function[, flags]);
-@param regexp  A RegExp object. The match is replaced by the return value of
+@param regexp  A RegExp object. The match is replaced by the return value of
 parameter #2.
-@param substr  A String that is to be replaced by newSubStr.
-@param newSubStr  The String that replaces the substring received from parameter
+@param substr  A String that is to be replaced by newSubStr.
+@param newSubStr  The String that replaces the substring received from parameter
 #1. A number of special replacement patterns are supported; see the "Specifying
 a string as a parameter" section below.
-@param function  A function to be invoked to create the new substring (to put in
+@param function  A function to be invoked to create the new substring (to put in
 place of the substring received from parameter #1). The arguments supplied to
 this function are described in the "Specifying a function as a parameter"
 section below.
-@param flags gimy
+@param flags gimy

 Non-standardThe use of the flags parameter in the String.replace method is
 non-standard. For cross-browser compatibility, use a RegExp object with
@@ -195,7 +187,7 @@
 object.

 string.search(regexp)
-@param regexp  A  regular expression object. If a non-RegExp object obj is
+@param regexp  A  regular expression object. If a non-RegExp object obj is
 passed, it is implicitly converted to a RegExp by using new RegExp(obj).
 @name search
 @methodOf String#
@@ -204,8 +196,8 @@
 Extracts a section of a string and returns a new string.

 string.slice(beginslice[, endSlice])
-@param beginSlice  The zero-based index at which to begin extraction.
-@param endSlice  The zero-based index at which to end extraction. If omitted,
+@param beginSlice  The zero-based index at which to begin extraction.
+@param endSlice  The zero-based index at which to end extraction. If omitted,
 slice extracts to the end of the string.
 @name slice
 @methodOf String#
@@ -215,11 +207,11 @@
 substrings.

 string.split([separator][, limit])
-@param separator  Specifies the character to use for separating the string. The
+@param separator  Specifies the character to use for separating the string. The
 separator is treated as a string or a regular expression. If separator is
 omitted, the array returned contains one element consisting of the entire
 string.
-@param limit  Integer specifying a limit on the number of splits to be found.
+@param limit  Integer specifying a limit on the number of splits to be found.
 @name split
 @methodOf String#
 ###
@@ -228,8 +220,8 @@
 the specified number of characters.

 string.substr(start[, length])
-@param start  Location at which to begin extracting characters.
-@param length  The number of characters to extract.
+@param start  Location at which to begin extracting characters.
+@param length  The number of characters to extract.
 @name substr
 @methodOf String#
 ###
@@ -238,8 +230,8 @@
 of the string.

 string.substring(indexA[, indexB])
-@param indexA  An integer between 0 and one less than the length of the string.
-@param indexB  (optional) An integer between 0 and the length of the string.
+@param indexA  An integer between 0 and one less than the length of the string.
+@param indexB  (optional) An integer between 0 and the length of the string.
 @name substring
 @methodOf String#
 ###
@@ -449,7 +441,7 @@
 @methodOf Array#
 ###
 ###*
-Reverses an array in place.  The first array element becomes the last and the
+Reverses an array in place.  The first array element becomes the last and the
 last becomes the first.

 array.reverse()
@@ -470,7 +462,7 @@
 Sorts the elements of an array in place.

 array.sort([compareFunction])
-@param compareFunction  Specifies a function that defines the sort order. If
+@param compareFunction  Specifies a function that defines the sort order. If
 omitted, the array is sorted lexicographically (in dictionary order) according
 to the string conversion of each element.
 @name sort
@@ -481,14 +473,14 @@
 elements.

 array.splice(index, howMany[, element1[, ...[, elementN]]])
-@param index  Index at which to start changing the array. If negative, will
+@param index  Index at which to start changing the array. If negative, will
 begin that many elements from the end.
-@param howMany  An integer indicating the number of old array elements to
+@param howMany  An integer indicating the number of old array elements to
 remove. If howMany is 0, no elements are removed. In this case, you should
 specify at least one new element. If no howMany parameter is specified (second
 syntax above, which is a SpiderMonkey extension), all elements after index are
 removed.
-@param element1, ..., elementN  The elements to add to the array. If you don't
+@param element1, ..., elementN  The elements to add to the array. If you don't
 specify any elements, splice simply removes elements from the array.
 @name splice
 @methodOf Array#
@@ -507,7 +499,7 @@
 value(s).

 array.concat(value1, value2, ..., valueN)
-@param valueN  Arrays and/or values to concatenate to the resulting array.
+@param valueN  Arrays and/or values to concatenate to the resulting array.
 @name concat
 @methodOf Array#
 ###
@@ -515,7 +507,7 @@
 Joins all elements of an array into a string.

 array.join(separator)
-@param separator  Specifies a string to separate each element of the array. The
+@param separator  Specifies a string to separate each element of the array. The
 separator is converted to a string if necessary. If omitted, the array elements
 are separated with a comma.
 @name join
@@ -525,10 +517,10 @@
 Returns a one-level deep copy of a portion of an array.

 array.slice(begin[, end])
-@param begin  Zero-based index at which to begin extraction.As a negative index,
+@param begin  Zero-based index at which to begin extraction.As a negative index,
 start indicates an offset from the end of the sequence. slice(-2) extracts the
 second-to-last element and the last element in the sequence.
-@param end  Zero-based index at which to end extraction. slice extracts up to
+@param end  Zero-based index at which to end extraction. slice extracts up to
 but not including end.slice(1,4) extracts the second element through the fourth
 element (elements indexed 1, 2, and 3).As a negative index, end indicates an
 offset from the end of the sequence. slice(2,-1) extracts the third element
@@ -558,7 +550,7 @@
 -1 if it is not present.

 array.indexOf(searchElement[, fromIndex])
-@param searchElement fromIndex  Element to locate in the array.The index at
+@param searchElement fromIndex  Element to locate in the array.The index at
 which to begin the search. Defaults to 0, i.e. the whole array will be searched.
 If the index is greater than or equal to the length of the array, -1 is
 returned, i.e. the array will not be searched. If negative, it is taken as the
@@ -573,7 +565,7 @@
 if it is not present. The array is searched backwards, starting at fromIndex.

 array.lastIndexOf(searchElement[, fromIndex])
-@param searchElement fromIndex  Element to locate in the array.The index at
+@param searchElement fromIndex  Element to locate in the array.The index at
 which to start searching backwards. Defaults to the array's length, i.e. the
 whole array will be searched. If the index is greater than or equal to the
 length of the array, the whole array will be searched. If negative, it is taken
@@ -588,7 +580,7 @@
 provided function.

 array.filter(callback[, thisObject])
-@param callback thisObject  Function to test each element of the array.Object to
+@param callback thisObject  Function to test each element of the array.Object to
 use as this when executing callback.
 @name filter
 @methodOf Array#
@@ -597,7 +589,7 @@
 Executes a provided function once per array element.

 array.forEach(callback[, thisObject])
-@param callback thisObject  Function to execute for each element.Object to use
+@param callback thisObject  Function to execute for each element.Object to use
 as this when executing callback.
 @name forEach
 @methodOf Array#
@@ -628,7 +620,7 @@
 provided function.

 array.some(callback[, thisObject])
-@param callback thisObject  Function to test for each element.Object to use as
+@param callback thisObject  Function to test for each element.Object to use as
 this when executing callback.
 @name some
 @methodOf Array#
@@ -648,7 +640,7 @@
 right-to-left) as to reduce it to a single value.

 array.reduceRight(callback[, initialValue])
-@param callback initialValue  Function to execute on each value in the
+@param callback initialValue  Function to execute on each value in the
 array.Object to use as the first argument to the first call of the callback.
 @name reduceRight
 @methodOf Array#
@@ -665,13 +657,13 @@
 Calls a function with a given this value and arguments provided as an array.

 fun.apply(thisArg[, argsArray])
-@param thisArg  Determines the value of this inside fun. If thisArg is null or
+@param thisArg  Determines the value of this inside fun. If thisArg is null or
 undefined, this will be the global object. Otherwise, this will be equal to
 Object(thisArg) (which is thisArg if thisArg is already an object, or a String,
 Boolean, or Number if thisArg is a primitive value of the corresponding type).
 Therefore, it is always true that typeof this == "object" when the function
 executes.
-@param argsArray  An argument array for the object, specifying the arguments
+@param argsArray  An argument array for the object, specifying the arguments
 with which fun should be called, or null or undefined if no arguments should be
 provided to the function.
 @name apply
@@ -684,7 +676,7 @@

 fun.bind(thisArg[, arg1[, arg2[, ...]]])
 @param thisValuearg1, arg2, ... The value to be passed as the this parameter to
-the target function when the bound function is called.  The value is ignored if
+the target function when the bound function is called.  The value is ignored if
 the bound function is constructed using the new operator.Arguments to prepend to
 arguments provided to the bound function when invoking the target function.
 @name bind
@@ -694,13 +686,13 @@
 Calls a function with a given this value and arguments provided individually.

 fun.call(thisArg[, arg1[, arg2[, ...]]])
-@param thisArg  Determines the value of this inside fun. If thisArg is null or
+@param thisArg  Determines the value of this inside fun. If thisArg is null or
 undefined, this will be the global object. Otherwise, this will be equal to
 Object(thisArg) (which is thisArg if thisArg is already an object, or a String,
 Boolean, or Number if thisArg is a primitive value of the corresponding type).
 Therefore, it is always true that typeof this == "object" when the function
 executes.
-@param arg1, arg2, ...  Arguments for the object.
+@param arg1, arg2, ...  Arguments for the object.
 @name call
 @methodOf Function#
 ###
@@ -727,9 +719,9 @@
 null.

-@param regexp  The name of the regular expression. It can be a variable name or
+@param regexp  The name of the regular expression. It can be a variable name or
 a literal.
-@param str  The string against which to match the regular expression.
+@param str  The string against which to match the regular expression.
 @name exec
 @methodOf RegExp#
 ###
@@ -738,9 +730,9 @@
 string. Returns true or false.

  regexp.test([str])
-@param regexp  The name of the regular expression. It can be a variable name or
+@param regexp  The name of the regular expression. It can be a variable name or
 a literal.
-@param str  The string against which to match the regular expression.
+@param str  The string against which to match the regular expression.
 @name test
 @methodOf RegExp#
 ###
@@ -960,7 +952,7 @@
 Sets the day of the month for a specified date according to local time.

  setDate(dayValue)
-@param dayValue  An integer from 1 to 31, representing the day of the month.
+@param dayValue  An integer from 1 to 31, representing the day of the month.
 @name setDate
 @methodOf Date#
 ###
@@ -970,11 +962,11 @@

 setFullYear(yearValue[, monthValue[, dayValue]])

-@param  yearValue   An integer specifying the numeric value of the year, for
+@param  yearValue   An integer specifying the numeric value of the year, for
 example, 1995.
-@param  monthValue   An integer between 0 and 11 representing the months January
+@param  monthValue   An integer between 0 and 11 representing the months January
 through December.
-@param  dayValue   An integer between 1 and 31 representing the day of the
+@param  dayValue   An integer between 1 and 31 representing the day of the
 month. If you specify the dayValue parameter, you must also specify the
 monthValue.
 @name setFullYear
@@ -986,11 +978,11 @@

 setHours(hoursValue[, minutesValue[, secondsValue[, msValue]]])

-@param  hoursValue   An integer between 0 and 23, representing the hour.
-@param  minutesValue   An integer between 0 and 59, representing the minutes.
-@param  secondsValue   An integer between 0 and 59, representing the seconds. If
+@param  hoursValue   An integer between 0 and 23, representing the hour.
+@param  minutesValue   An integer between 0 and 59, representing the minutes.
+@param  secondsValue   An integer between 0 and 59, representing the seconds. If
 you specify the secondsValue parameter, you must also specify the minutesValue.
-@param  msValue   A number between 0 and 999, representing the milliseconds. If
+@param  msValue   A number between 0 and 999, representing the milliseconds. If
 you specify the msValue parameter, you must also specify the minutesValue and
 secondsValue.
 @name setHours
@@ -1002,7 +994,7 @@

 setMilliseconds(millisecondsValue)

-@param  millisecondsValue   A number between 0 and 999, representing the
+@param  millisecondsValue   A number between 0 and 999, representing the
 milliseconds.
 @name setMilliseconds
 @methodOf Date#
@@ -1013,10 +1005,10 @@

 setMinutes(minutesValue[, secondsValue[, msValue]])

-@param  minutesValue   An integer between 0 and 59, representing the minutes.
-@param  secondsValue   An integer between 0 and 59, representing the seconds. If
+@param  minutesValue   An integer between 0 and 59, representing the minutes.
+@param  secondsValue   An integer between 0 and 59, representing the seconds. If
 you specify the secondsValue parameter, you must also specify the minutesValue.
-@param  msValue   A number between 0 and 999, representing the milliseconds. If
+@param  msValue   A number between 0 and 999, representing the milliseconds. If
 you specify the msValue parameter, you must also specify the minutesValue and
 secondsValue.
 @name setMinutes
@@ -1028,9 +1020,9 @@

 setMonth(monthValue[, dayValue])

-@param  monthValue   An integer between 0 and 11 (representing the months
+@param  monthValue   An integer between 0 and 11 (representing the months
 January through December).
-@param  dayValue   An integer from 1 to 31, representing the day of the month.
+@param  dayValue   An integer from 1 to 31, representing the day of the month.
 @name setMonth
 @methodOf Date#
 ###
@@ -1040,8 +1032,8 @@

 setSeconds(secondsValue[, msValue])

-@param  secondsValue   An integer between 0 and 59.
-@param  msValue   A number between 0 and 999, representing the milliseconds.
+@param  secondsValue   An integer between 0 and 59.
+@param  msValue   A number between 0 and 999, representing the milliseconds.
 @name setSeconds
 @methodOf Date#
 ###
@@ -1052,7 +1044,7 @@

 setTime(timeValue)

-@param  timeValue   An integer representing the number of milliseconds since 1
+@param  timeValue   An integer representing the number of milliseconds since 1
 January 1970, 00:00:00 UTC.
 @name setTime
 @methodOf Date#
@@ -1063,7 +1055,7 @@

 setUTCDate(dayValue)

-@param  dayValue   An integer from 1 to 31, representing the day of the month.
+@param  dayValue   An integer from 1 to 31, representing the day of the month.
 @name setUTCDate
 @methodOf Date#
 ###
@@ -1073,11 +1065,11 @@

 setUTCFullYear(yearValue[, monthValue[, dayValue]])

-@param  yearValue   An integer specifying the numeric value of the year, for
+@param  yearValue   An integer specifying the numeric value of the year, for
 example, 1995.
-@param  monthValue   An integer between 0 and 11 representing the months January
+@param  monthValue   An integer between 0 and 11 representing the months January
 through December.
-@param  dayValue   An integer between 1 and 31 representing the day of the
+@param  dayValue   An integer between 1 and 31 representing the day of the
 month. If you specify the dayValue parameter, you must also specify the
 monthValue.
 @name setUTCFullYear
@@ -1089,11 +1081,11 @@

 setUTCHours(hoursValue[, minutesValue[, secondsValue[, msValue]]])

-@param  hoursValue   An integer between 0 and 23, representing the hour.
-@param  minutesValue   An integer between 0 and 59, representing the minutes.
-@param  secondsValue   An integer between 0 and 59, representing the seconds. If
+@param  hoursValue   An integer between 0 and 23, representing the hour.
+@param  minutesValue   An integer between 0 and 59, representing the minutes.
+@param  secondsValue   An integer between 0 and 59, representing the seconds. If
 you specify the secondsValue parameter, you must also specify the minutesValue.
-@param  msValue   A number between 0 and 999, representing the milliseconds. If
+@param  msValue   A number between 0 and 999, representing the milliseconds. If
 you specify the msValue parameter, you must also specify the minutesValue and
 secondsValue.
 @name setUTCHours
@@ -1105,7 +1097,7 @@

 setUTCMilliseconds(millisecondsValue)

-@param  millisecondsValue   A number between 0 and 999, representing the
+@param  millisecondsValue   A number between 0 and 999, representing the
 milliseconds.
 @name setUTCMilliseconds
 @methodOf Date#
@@ -1116,10 +1108,10 @@

 setUTCMinutes(minutesValue[, secondsValue[, msValue]])

-@param  minutesValue   An integer between 0 and 59, representing the minutes.
-@param  secondsValue   An integer between 0 and 59, representing the seconds. If
+@param  minutesValue   An integer between 0 and 59, representing the minutes.
+@param  secondsValue   An integer between 0 and 59, representing the seconds. If
 you specify the secondsValue parameter, you must also specify the minutesValue.
-@param  msValue   A number between 0 and 999, representing the milliseconds. If
+@param  msValue   A number between 0 and 999, representing the milliseconds. If
 you specify the msValue parameter, you must also specify the minutesValue and
 secondsValue.
 @name setUTCMinutes
@@ -1131,9 +1123,9 @@

 setUTCMonth(monthValue[, dayValue])

-@param  monthValue   An integer between 0 and 11, representing the months
+@param  monthValue   An integer between 0 and 11, representing the months
 January through December.
-@param  dayValue   An integer from 1 to 31, representing the day of the month.
+@param  dayValue   An integer from 1 to 31, representing the day of the month.
 @name setUTCMonth
 @methodOf Date#
 ###
@@ -1143,8 +1135,8 @@

 setUTCSeconds(secondsValue[, msValue])

-@param  secondsValue   An integer between 0 and 59.
-@param  msValue   A number between 0 and 999, representing the milliseconds.
+@param  secondsValue   An integer between 0 and 59.
+@param  msValue   A number between 0 and 999, representing the milliseconds.
 @name setUTCSeconds
 @methodOf Date#
 ###


added new events; cleanup

added new events; cleanup

--- manager/lib/assets/javascripts/stark/stark.js.coffee
+++ manager/lib/assets/javascripts/stark/stark.js.coffee
@@ -60,6 +60,7 @@
   #
   transition: (state_name, state_data) ->
     @log "transition", state_name, state_data
+    @trigger "before:transition", state_name, state_data
     target_state = @states[state_name]

     if ! target_state?
@@ -110,13 +111,14 @@
     @log "render_views "

     if @current_state?
+      @trigger("state:deactivate", state)
       @current_state.deactivate()
       @current_state.dispose(state)
-      @trigger("state:deactivate", state)

     # create views
-    _.each state.views, (v) ->
+    _.eachR @, state.views, (v) ->
+
       if @current_state? && _.include(@current_state.views, v) && v.prototype.redraw == false
         @log "not going to redraw #{v.name}"
         return
@@ -129,7 +131,6 @@
       view.bind_app_events()
       view.render()
       state._views.push view
-    , @ # context for _.each

     if @current_state? && state.url? && (!state.params? || state.params.changeURL == true)
       # there was a previous state, update browser url


Don't use directly hidden properties but use _get instead

--- lib/characters.coffee
+++ lib/characters.coffee
@@ -135,15 +135,15 @@
       arentNull = (el) ->
         el != null
       if _.all delta.attributes, arentNull
-        operation = @_selections.select
+        operation = (@get "selections").select
       else
-        operation = @_selections.unselect
+        operation = (@get "selections").unselect

       if delta.insert?
         @insert position, delta.insert
         from = @val position
         to = @val (position + delta.insert.length)
-        operation from, to, delta.attributes
+        operation.call (@get "selections"), from, to, delta.attributes
         return position + delta.insert.length

       else if delta.delete?


Add gc signal

Add gc signal

--- lib/Site.coffee
+++ lib/Site.coffee
@@ -29,6 +29,15 @@
 RESERVED_RANK = 9

 _USER_RANK_COOKIE_NAME = 'weedproxite_urc'
+
+
+process.on  'SIGUSR2',
+            () ->
+              if global.gc
+                console.log("Doing GC...")
+                global.gc()
+              else
+                console.log("GC is not exposed.")

 encrypt = (text,password) ->


Disabled cloning of editable contents for proper plugin modification. Blacklist plugin works now as expected.

--- src/hallo.coffee
+++ src/hallo.coffee
@@ -238,13 +238,11 @@

     # Get contents of an editable as HTML string
     getContents: ->
-      # clone
-      contentClone = @element.clone()
       for plugin of @options.plugins
         cleanup = jQuery(@element).data('IKS-'+plugin).cleanupContentClone
         continue unless jQuery.isFunction cleanup
-        jQuery(@element)[plugin] 'cleanupContentClone', contentClone
-      contentClone.html()
+        jQuery(@element)[plugin] 'cleanupContentClone', @element
+      @element.html()

     # Set the contents of an editable
     setContents: (contents) ->


Added rudimentary tweening, wut!

Added rudimentary tweening, wut!

--- src/tween.coffee
+++ src/tween.coffee
@@ -23,8 +23,7 @@
         I[property] = f(t)

   ###*
-  A convenient way to set the flicker instance variables on a sprite. You can modify the
-  instance variables by hand but the suggested way to do it is through this method.
+  Mod

   player = GameObject()


Fix require path for buffer_ieee754

Fix require path for buffer_ieee754

--- src/hoard.coffee
+++ src/hoard.coffee
@@ -42,7 +42,7 @@
         # Using 'buffer_ieee754' from node 0.5.x
         # as no libraries had a working IEEE754 encoder
         buffer = new Buffer(4)
-        require('buffer_ieee754').writeIEEE754(buffer, 0.5, 0, 'big', 23, 4);
+        require('./buffer_ieee754').writeIEEE754(buffer, 0.5, 0, 'big', 23, 4);
         buffer

     buffer = Put()


Update radbus.coffee

Update radbus.coffee

fix typo

--- src/radbus.coffee
+++ src/radbus.coffee
@@ -175,7 +175,7 @@
                  "2. Use the 'bus token {your-token}' to tell me what your token is."

       else
-        msg.send "Hey @#{userName}, give me a moment to look up those bus depatures..."
+        msg.send "Hey @#{userName}, give me a moment to look up those bus departures..."

         chain = ensureAuthToken(robot, msg, userData, logPrefix).then ->
           console.log chalk.blue("#{logPrefix} Getting user's departures...")


viewSpec: test static method classNameExtend

--- coffee/test/views/view.spec.coffee
+++ coffee/test/views/view.spec.coffee
@@ -92,3 +92,21 @@
     view2.softRender()
     expect(renderSpy1.callCount).toBe 2
     expect(renderSpy2.callCount).toBe 1
+
+  it 'should have static method classNameExtend, which extends classNames', ->
+    class Firetruck extends View
+      className: @classNameExtend 'firetruck'
+    class RedFiretruck extends Firetruck
+      className: @classNameExtend 'red'
+    class BigRedFiretruck extends RedFiretruck
+      className: @classNameExtend 'big'
+
+    view = new View()
+    firetruck = new Firetruck()
+    redFiretruck = new RedFiretruck()
+    bigRedFiretruck = new BigRedFiretruck()
+
+    expect(view.className).toBe ''
+    expect(firetruck.className).toBe 'firetruck'
+    expect(redFiretruck.className).toBe 'firetruck red'
+    expect(bigRedFiretruck.className).toBe 'firetruck red big'


Removing log

Removing log

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

 # All routes return layout.  (Chaplin loads views dynamically)
 app.get ['/', '/about'], (req, resp) ->
-  console.log req.session, resp.session
   resp.render 'index'

 # Define Port


Update index.coffee

Update index.coffee

--- src/index.coffee
+++ src/index.coffee
@@ -1,6 +1,5 @@
 https = require('https')
 crypto = require('crypto')
-Promise = require('bluebird')
 pem = require('pem')

 TlsaBuilder = (_domain, _port = 443, _usage = 3, _selector = 0,


sentiment of to/be and nt is better expressed as a switch statement

--- src/index.coffee
+++ src/index.coffee
@@ -67,18 +67,20 @@
   [Object(y) instanceof x, "expected #{str y} to be an instance of #{x.name}"]

 be = to = (x) ->
-  if x is empty then return is_empty
-  if x is ok then return is_ok
-  if x is exist then return does_exist
-  if x is error then return should_throw
-  x
+  return switch x
+    when empty then is_empty
+    when ok then is_ok
+    when exist then does_exist
+    when error then should_throw
+    else x

 nt = (f) ->
-  if f is empty then return negate is_empty
-  if f is ok then return negate is_ok
-  if f is exist then return negate does_exist
-  if f is error then return negate should_throw
-  negate f
+  return switch f
+    when empty then negate is_empty
+    when ok then negate is_ok
+    when exist then negate does_exist
+    when error then negate should_throw
+    else negate f

 sentence = module.exports = {exist, empty, ok, error, a, an, have, match, length, contain, include, negate, nt, to, be, than, less, lt, less_than, less_or_equal, lte, greater, gt, greater_than, greater_or_equal, gte, expect, equal, not_equal, deep_equal, eql}


Throw error if bucket is undefined

Throw error if bucket is undefined

--- src/index.coffee
+++ src/index.coffee
@@ -7,6 +7,8 @@
 rand = require('crypto').pseudoRandomBytes

 Upload = module.exports = (awsBucketName, opts) ->
+  throw new Error 'Bucket name can not be undefined' if not awsBucketName
+
   @s3 = new S3 params: Bucket: awsBucketName

   @versions = opts?.versions or []


Change default body text + bump base font-size

--- src/index.coffee
+++ src/index.coffee
@@ -6,14 +6,14 @@

 module.exports = (options) ->
   defaults =
-    baseFontSize: '16px'
-    baseLineHeight: '24px'
+    baseFontSize: '18px'
+    baseLineHeight: '28.5px'
     modularScales: [
       'diminished fourth'
     ]
     googleFonts: []
     headerFontFamily: '"Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif'
-    bodyFontFamily: '"Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif'
+    bodyFontFamily: 'georgia, serif'
     headerGray: 20
     headerGrayHue: 0
     bodyGray: 20


* [bug] the assign of attributes does not return proper value

--- src/index.coffee
+++ src/index.coffee
@@ -29,7 +29,10 @@
       type: 'Object'
       assigned: '$_attributes' # this should define the non-enumerable `$_attributes` property.
       assign: (value, dest, src, key)->
-         dest.attributes.assign(value) if (dest instanceof ObjectType) and dest.attributes?
+        if (dest instanceof ObjectType) and dest.attributes?
+          dest.attributes.assign(value)
+        else
+          value
     $_attributes:
       value: new ObjectAttributes
     strict:


core/utils: log :arrow_right: console.log

--- lib/core/utils.coffee
+++ lib/core/utils.coffee
@@ -355,7 +355,7 @@
     kallback

   logTimer:(timerName, timerNumber, startTime)->
-    log "logTimer name:#{timerName}"
+    console.log "logTimer name:#{timerName}"

     @timers[timerName] ||= {}
     @timers[timerName][timerNumber] =
@@ -375,7 +375,7 @@

     @timers[timerName][timerNumber] = timer

-    log "updateLogTimer name:#{timerName}, status:#{status} elapsed:#{elapsed}"
+    console.log "updateLogTimer name:#{timerName}, status:#{status} elapsed:#{elapsed}"

   timers: {}


runner: Accept a fbp-client.Transport in addition to runtime definition

--- src/runner.coffee
+++ src/runner.coffee
@@ -9,9 +9,11 @@
 debug = common.debug

 class Runner
-  constructor: (@rt) ->
-    Transport = fbpClient.getTransport @rt.protocol
-    @client = new Transport @rt
+  constructor: (@client) ->
+    if @client.protocol? and @client.id?
+      # is a runtime definition
+      Transport = fbpClient.getTransport @client.protocol
+      @client = new Transport @client
     @currentGraphId = null

   # TODO: check the runtime capabilities before continuing


include_module_loader is working.

include_module_loader is working.

--- src/watch.coffee
+++ src/watch.coffee
@@ -45,7 +45,9 @@
 jsShimMap = {}
 if config?
   paths = config.clientSettings.paths
-  for name, value of config.clientSettings.shim
+  shim = config.clientSettings.shim
+  buildConfig = {paths, shim}
+  for name, value of shim
     path = paths[name] ? name
     deps = ((paths[dep] ? dep) for dep in value.deps)
     jsShimMap[path] = {deps}
@@ -56,6 +58,15 @@
     "?_#{(new Date()).getTime()}"
   else
     ''
+
+# Module loader source
+moduleLoaderSrc = fs.readFileSync(sysPath.join(__dirname, 'module_loader.coffee')).toString()
+moduleLoaderSrc = _.template(moduleLoaderSrc, {settings})
+moduleLoaderSrc = CoffeeScript.compile(moduleLoaderSrc)
+
+liveReloadSrc = fs.readFileSync(sysPath.join(__dirname, 'live_reload.coffee')).toString()
+liveReloadSrc = _.template(liveReloadSrc, {settings})
+liveReloadSrc = CoffeeScript.compile(liveReloadSrc)

 htmlHelpers =
   link_tag: (link, attrs={}) ->
@@ -67,43 +78,11 @@
   image_tag: (src, attrs={}) ->
     ""
   include_module_loader: ->
-    loaderSrc = fs.readFileSync(sysPath.join(__dirname, 'module_loader.coffee')).toString()
-    loaderJS = CoffeeScript.compile(loaderSrc)
-    buildConfig =
-      paths: config.clientSettings.paths
-      shim: config.clientSettings.shim
     """
-
-
+
+
+
     """
-
-jadeHelpers =
-  link_tag: (link, attrs={}) ->
-    "link(href='#{settings.assetHost}#{link}#{cacheBuster(attrs.forceCacheBuster)}', #{("#{k}='#{v}'" for k, v of attrs).join(',')})"
-  stylesheet_link_tag: (link, attrs={}) ->
-    "link(rel='stylesheet', type='text/css', href='#{settings.assetHost}#{link}#{cacheBuster(attrs.forceCacheBuster)}', #{("#{k}='#{v}'" for k, v of attrs).join(',')})"
-  script_tag: (src, attrs={}) ->
-    "script(src='#{settings.assetHost}#{src}#{cacheBuster(attrs.forceCacheBuster)}', #{("#{k}='#{v}'" for k, v of attrs).join(',')})"
-  image_tag: (src, attrs={}) ->
-    "img(src='#{settings.assetHost}#{src}#{cacheBuster(attrs.forceCacheBuster)}', #{("#{k}='#{v}'" for k, v of attrs).join(',')})"
-  include_module_loader: ->
-    loaderSrc = fs.readFileSync(sysPath.join(__dirname, 'module_loader.coffee')).toString()
-    loaderJS = CoffeeScript.compile(loaderSrc)
-    buildConfig =
-      paths: config.clientSettings.paths
-      shim: config.clientSettings.shim
-    """
-    script #{loaderJS}
-    script require.config(JSON.parse(#{JSON.stringify(buildConfig)}))
-    """
-
-injectLiveReloadJS = (data) ->
-  # Inject livereload.js
-  if settings.liveReload
-    i = data.indexOf('')
-    if i isnt -1
-      data = data[0...i] + "\n" + data[i..]
-  return data

 # Files to ignore
 ignored = (file) ->
@@ -198,6 +177,7 @@
     _compile()

   _compile = ->
+    logging.info "processing #{source}"
     try
       switch sysPath.extname(source)
         when '.coffee'
@@ -216,14 +196,15 @@
           reload(path)

         when '.jade'
-          # Run the source file through template engine
-          sourceData = _.template(fs.readFileSync(source).toString(), _.extend({}, {settings}, jadeHelpers))
+          # Compile Jade into html
+          sourceData = fs.readFileSync(source).toString()
           filename = sysPath.basename(source, sysPath.extname(source)) + '.html'
           path = sysPath.join destDir, filename
-
-          fn = jade.compile sourceData, { filename: source, compileDebug: false, pretty: true }
+          fn = jade.compile sourceData, {filename: source, compileDebug: false, pretty: true}
           html = fn()
-          html = injectLiveReloadJS(html)
+
+          # Run through the template engine and write to the output file
+          html = _.template(html, _.extend({}, {settings}, htmlHelpers))
           fs.writeFileSync path, html
           logging.info "compiled #{source}"
           reload(path)
@@ -242,7 +223,6 @@
         when '.html', '.htm', '.css'
           # Run the source file through template engine
           sourceData = _.template(fs.readFileSync(source).toString(), _.extend({}, {settings}, htmlHelpers))
-          sourceData = injectLiveReloadJS(sourceData)
           filename = sysPath.basename(source)
           path = sysPath.join destDir, filename
           fs.writeFileSync path, sourceData


response status was never set

response status was never set

--- src/server.coffee
+++ src/server.coffee
@@ -29,9 +29,9 @@
 		Object.getOwnPropertyNames(err).map (p) ->
 			flatErr[p] = err[p]
 		err = flatErr
-	log.error StringifySafe err
+	log.error "ERROR", StringifySafe err
 	delete err.arguments
-	res.status = 400
+	res.status 400
 	if Accepts(req).types().length > 0 and Accepts(req).types()[0] is 'text/html'
 		return res.render 'error', { err }
 	else
@@ -108,6 +108,7 @@
 				'swagger'
 				'json-import'
 				'syntax-highlight'
+				'play'
 			]
 			do (controller) =>
 				log.info "Setting up route #{controller}"


Change resolution to 30ms

Change resolution to 30ms

--- src/server.coffee
+++ src/server.coffee
@@ -49,7 +49,7 @@

   #
   # write buffer directly to the kernel via /dev/ttyO1 pipe
-  # if buffer has content, at 15ms resolution. recursively call this function on success
+  # if buffer has content, at 30ms resolution. recursively call this function on success
   #
   _write_pipe: ->
     setTimeout (=>
@@ -62,7 +62,7 @@
           buffer = ''
           @_write_pipe()
         )
-    ), 15
+    ), 30

   #
   # convert halo rgba string to a UART instruction


Our argument-passing is old-style, use proper Socket.IO 1.x format.

Reading through the documentation, Server#listen === Server#Attach which takes different arguments, so this must have been working because of some compatibility mode.

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -99,7 +99,7 @@
   io = null
   if options.io isnt false
     socketio = options.socketio ? require 'socket.io'
-    io = context.io = socketio.listen context.server, options.io ? {}
+    io = context.io = socketio context.server, options.io ? {}

   # Reference to the zappa client, the value will be set later.
   client = null


Made zappa `.coffee` handler actually use CoffeeCup.

Need tests, opened zappajs/zappajs#5

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -115,7 +115,7 @@

   # Zappa's default settings.
   app.set 'view engine', 'coffee'
-  app.register '.coffee', zappa.adapter require('coffeekup').adapters.express,
+  app.register '.coffee', zappa.adapter require('coffeecup').adapters.express,
     blacklist: ['format', 'autoescape', 'locals', 'hardcode', 'cache']

   # Sets default view dir to @root (`path.dirname(module.parent.filename)`).


Added Packet.headerSize getter (may require some testing)

--- src/wrathnet/net/packet.coffee
+++ src/wrathnet/net/packet.coffee
@@ -25,6 +25,10 @@
     # Seek past opcode to reserve space for it when finalizing
     @index = @headerSize

+  # Header size in bytes for both incoming and outgoing packets
+  @getter 'headerSize', ->
+    return @constructor.HEADER_SIZE
+
   # Finalizes this packet
   finalize: ->
     return @


Handle GET and POST differently in HttpServer

--- lib/httpServer.coffee
+++ lib/httpServer.coffee
@@ -4,27 +4,39 @@

 helpers = require './helpers'

-class httpServer
+class HttpServer
     constructor: (@device) ->
         @server = http.createServer(@listener)

     listener: (req, res) =>
         helpers.debug "#{req.url} served to #{req.client.remoteAddress}"
-
-        @handler req.url, (err, data) ->
-            if err?
-                res.writeHead data, 'Content-Type': 'text/plain'
-                res.write "#{data} - #{err.message}"
-            else
-                res.writeHead 200,
-                    'Content-Type': 'text/xml'
-                    'Content-Length': Buffer.byteLength(data)
-                res.write data
-            res.end()
+        if req.method is 'GET'
+            @handler req.url, (err, data) ->
+                if err?
+                    res.writeHead data, 'Content-Type': 'text/plain'
+                    res.write "#{data} - #{err.message}"
+                else
+                    res.writeHead 200,
+                        'Content-Type': 'text/xml'
+                        'Content-Length': Buffer.byteLength(data)
+                    res.write data
+                res.end()
+        else if req.method is 'POST'
+            data = ''
+            req.on 'data', (chunk) ->
+                data += chunk
+            req.on 'end', =>
+                if req.headers.soapaction
+                    [foo, serviceType, action] = ///
+                        (\w+) # serviceType
+                        :\d#
+                        (\w+) # action
+                        "$
+                    ///.exec(req.headers.soapaction)
+                    @device.services[serviceType].action(action, data)

     handler: (path, callback) ->
         [foo, category, action, type] = path.split('/')
-        console.log path
         switch category
             when 'device'
                 if action isnt 'description'
@@ -40,14 +52,6 @@
                         fs.readFile @_makeServicePath(type), 'utf8', (err, file) ->
                             return callback err, 500 if err
                             callback null, file
-                    when 'control'
-                        if req.headers.soapaction? and req.method == 'POST'
-                            data = ''
-                            req.on 'data', (chunk) ->
-                                data += chunk
-                            req.on 'end', ->
-
-                                console.log /#(\w+)/.exec(req.headers.soapaction)[1] # service action
             else
                 callback new Error('File not found'), 404

@@ -64,4 +68,4 @@
     _makeServicePath: (serviceType) ->
         __dirname + '/services/' + serviceType + '.xml'

-exports.createServer = (device) -> new httpServer(device)
+exports.createServer = (device) -> new HttpServer(device)


Hide currently unused options

Hide currently unused options

--- lib/latextools.coffee
+++ lib/latextools.coffee
@@ -25,10 +25,10 @@
       type: 'boolean'
       default: false
       order: 3
-    fillAutoTrigger:
-      type: 'boolean'
-      default: true
-      order: 4
+    # fillAutoTrigger:
+    #   type: 'boolean'
+    #   default: true
+    #   order: 4
     keepFocus:
       type: 'boolean'
       default: true
@@ -38,17 +38,17 @@
       default: true
       order: 6

-    commandCompletion:
-      type: 'string'
-      default: 'prefixed'
-      enum: ['always', 'prefixed', 'never']
-      order: 7
-
-    hideBuildPanel:
-      type: 'string'
-      default: 'never'
-      enum: ['always', 'no_errors', 'no_warnings', 'never']
-      order: 8
+    # commandCompletion:
+    #   type: 'string'
+    #   default: 'prefixed'
+    #   enum: ['always', 'prefixed', 'never']
+    #   order: 7
+
+    # hideBuildPanel:
+    #   type: 'string'
+    #   default: 'never'
+    #   enum: ['always', 'no_errors', 'no_warnings', 'never']
+    #   order: 8

     texFileExtensions:
       type: 'array'
@@ -57,27 +57,27 @@
         type: 'string'
       order: 9

-    latextoolsSetSyntax:
-      type: 'boolean'
-      default: true
-      order: 10
-
-    temporaryFileExtensions:
-      type: 'array'
-      default: [
-		          ".blg",".bbl",".aux",".log",".brf",".nlo",".out",".dvi",".ps",
-		          ".lof",".toc",".fls",".fdb_latexmk",".pdfsync",".synctex.gz",
-              ".ind",".ilg",".idx"
-	             ]
-      items:
-        type: 'string'
-      order: 11
-    temporaryFilesIgnoredFolders:
-      type: 'array'
-      default: [".git", ".svn", ".hg"]
-      items:
-        type: 'string'
-      order: 12
+    # latextoolsSetSyntax:
+    #   type: 'boolean'
+    #   default: true
+    #   order: 10
+
+    # temporaryFileExtensions:
+    #   type: 'array'
+    #   default: [
+		#           ".blg",".bbl",".aux",".log",".brf",".nlo",".out",".dvi",".ps",
+		#           ".lof",".toc",".fls",".fdb_latexmk",".pdfsync",".synctex.gz",
+    #           ".ind",".ilg",".idx"
+	  #            ]
+    #   items:
+    #     type: 'string'
+    #   order: 11
+    # temporaryFilesIgnoredFolders:
+    #   type: 'array'
+    #   default: [".git", ".svn", ".hg"]
+    #   items:
+    #     type: 'string'
+    #   order: 12

     darwin:
       type: 'object'
@@ -103,9 +103,9 @@
         atomExecutable:
           type: 'string'
           default: ""
-        keepFocusDelay:
-          type: 'number'
-          default: 0.5
+        # keepFocusDelay:
+        #   type: 'number'
+        #   default: 0.5
       order:14

     linux:
@@ -114,18 +114,18 @@
         texpath:
           type: 'string'
           default: "$PATH:/usr/texbin"
-        python2:
+        # python2:
+        #   type: 'string'
+        #   default: ""
+        atomExecutable:
           type: 'string'
           default: ""
-        atomExecutable:
-          type: 'string'
-          default: ""
-        syncWait:
-          type: 'number'
-          default: 1.5
-        keepFocusDelay:
-          type: 'number'
-          default: 0.5
+        # syncWait:
+        #   type: 'number'
+        #   default: 1.5
+        # keepFocusDelay:
+        #   type: 'number'
+        #   default: 0.5
       order: 15

     builder:


formatting

formatting

--- src/pan_zoom/pan_zoom.coffee
+++ src/pan_zoom/pan_zoom.coffee
@@ -26,7 +26,7 @@
       ) ->
          @panning = false

-         @minZoom = 1 / 4 - 0.01
+         @minZoom = 1/4 - 0.01
          @zoom = 1
          @maxZoom = 1

@@ -87,7 +87,7 @@

       move: (x, y) ->
          if @panning
-            @_lastMoveX = x;
+            @_lastMoveX = x
             @_lastMoveY = y

       minX: ->
@@ -112,16 +112,15 @@
          @_lastTouchY = @_lastMoveY

-   _document = angular.element(document)
+   _document = angular.element document
    class PanZoomElement
       constructor: (panZoom, element) ->
          @panZoom = panZoom
          @element = element
-         @boundOnMove = @onMove.bind(this)
-
-         @element.on 'mousedown', @onTouch.bind(this)
-         @element.on 'mouseup', @onUntouch.bind(this)
-         @element.on 'wheel', @onScroll.bind(this)
+         @boundOnMove = @onMove.bind this
+         @element.on 'mousedown', @onTouch.bind this
+         @element.on 'mouseup', @onUntouch.bind this
+         @element.on 'wheel', @onScroll.bind this
          @setPan()
          @setZoom()

@@ -158,8 +157,8 @@
       setPan: ->
          scrollTo -@panZoom.panX(), -@panZoom.panY()

-   zoomInFactor = Math.sqrt(2)
-   zoomOutFactor = 1 / Math.sqrt(2)
+   zoomInFactor = Math.sqrt 2
+   zoomOutFactor = 1 / Math.sqrt 2
    zoomFactor = (scrollDelta) ->
       if scrollDelta < 0 then zoomInFactor else zoomOutFactor

@@ -167,11 +166,12 @@

    return (
       PanZoom: PanZoom
-      bindElement: (el, initX = 0, initY = 0) ->
+      bindElement: (el, initX=0, initY=0) ->
          new PanZoomElement(
             new PanZoom(
                initX, initY
                el[0].offsetWidth, el[0].offsetHeight,
                _viewport[0].offsetWidth, _viewport[0].offsetHeight
-            ), el)
+            ), el
+         )
    )


syntax errors

syntax errors

--- src/lobby.coffee
+++ src/lobby.coffee
@@ -113,7 +113,7 @@

 exports.filterMaps = (desired, mapList) ->

-  mapList.filter (map) -> map.indexOf(desired) isnt -1
+  mapList.filter((map) -> map.indexOf(desired) isnt -1)

 exports.newLobby = (map, principal, server) ->
   {
@@ -126,11 +126,11 @@
   }

 exports.finalising = (robot, msg) ->
-  lobby = robot.brain.get 'lobby'
+  lobby = robot.brain.get('lobby')
   server = servers[lobby.server]

   if lobby?
-    players = Object.keys lobby.participants
+    players = Object.keys(lobby.participants)

     if players.length is 12

@@ -142,35 +142,35 @@
         ctx.close()
       )

-      today = robot.brain.get 'today'
+      today = robot.brain.get('today')

       today = { players: {}, maps: {} } unless today?

       for player in players
-        if today.players.hasOwnProperty player
+        if today.players.hasOwnProperty(player)
           today.players[player]++
         else
           today.players[player] = 1

-      if today.maps.hasOwnProperty lobby.map
+      if today.maps.hasOwnProperty(lobby.map)
         today.maps[lobby.map]++
       else
         today.maps[lobby.map] = 1

-      robot.brain.set 'today', today
-
-      robot.brain.set 'lobby', null
-      robot.brain.set 'previous', lobby
-      msg.send "be a darling and click the link: steam://connect/#{server.host}:#{server.port}/#{server.password}"
-      msg.send "no guarantee can be made that your place will still be available if you're late."
-      return msg.send "also, if you're late often, a suitable punishment will be awarded."
+      robot.brain.set('today', today)
+
+      robot.brain.set('lobby', null)
+      robot.brain.set('previous', lobby)
+      msg.send("be a darling and click the link: steam://connect/#{server.host}:#{server.port}/#{server.password}")
+      msg.send("no guarantee can be made that your place will still be available if you're late.")
+      return msg.send("also, if you're late often, a suitable punishment will be awarded.")

     lobby.finalising = false
-    robot.brain.set 'lobby', lobby
-    return msg.send "#{msg.random(responses.mistake)}  it looks like we didn't find enough players in time. but never fear! tfbot is here to comfort you while you cry yourself to sleep."
+    robot.brain.set('lobby', lobby)
+    return msg.send("#{msg.random(responses.mistake)}  it looks like we didn't find enough players in time. but never fear! tfbot is here to comfort you while you cry yourself to sleep.")

 exports.onLeave = (robot, msg) ->
-  lobby = robot.brain.get 'lobby'
+  lobby = robot.brain.get('lobby')
   return unless lobby?

   user = msg.message.user.id
@@ -178,8 +178,8 @@

   if user in players
     delete lobby.participants[user]
-    robot.brain.set 'lobby', lobby
-    return msg.send "|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||"
+    robot.brain.set('lobby', lobby)
+    return msg.send("|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||")

 exports.rconSay = (robot, msg) ->
   user = msg.message.user.id
@@ -189,32 +189,36 @@
   if robot.auth.hasRole(msg.envelope.user, 'rcon')

     if server?.rcon
-      return new Rcon server, (ctx) ->
-        ctx.exec "sm_say #{msg.match[2]}", (res) ->
+      return new Rcon(server, (ctx) ->
+        ctx.exec("sm_say #{msg.match[2]}", (res) ->
           ctx.close()
-          msg.reply "#{msg.random(responses.affirmative)} your message was delivered..."
-
-    return msg.reply "#{msg.random(responses.mistake)} that's not a valid server..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't to do that..."
+          msg.reply("#{msg.random(responses.affirmative)} your message was delivered...")
+        )
+      )
+
+    return msg.reply("#{msg.random(responses.mistake)} that's not a valid server...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't to do that...")

 exports.rconRoster = (robot, msg) ->
   user = msg.message.user.id

   if robot.auth.hasRole(msg.envelope.user, 'rcon')

-    previous = robot.brain.get 'previous'
+    previous = robot.brain.get('previous')
     server = servers[previous.server]

     if previous? and server?.rcon
-      return new Rcon server, (ctx) ->
-        ctx.exec "sm_say [ #tfbot ] #{Object.keys(previous.participants).join(', ')}", (res) ->
+      return new Rcon(server, (ctx) ->
+        ctx.exec("sm_say [ #tfbot ] #{Object.keys(previous.participants).join(', ')}", (res) ->
           ctx.close()
-          msg.reply "#{msg.random(responses.affirmative)} player roster was delivered..."
-
-    return msg.reply "#{msg.random(responses.mistake)} there's no previous game data. creepy..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't to do that..."
+          msg.reply("#{msg.random(responses.affirmative)} player roster was delivered...")
+        )
+      )
+
+    return msg.reply("#{msg.random(responses.mistake)} there's no previous game data. creepy...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't to do that...")

 exports.rconMap = (robot, msg) ->
   user = msg.message.user.id
@@ -223,24 +227,115 @@

   if robot.auth.hasRole(msg.envelope.user, 'rcon')

-    if server?.rcon and (map in maps or filterMaps(map, maps).length is 1)
-      return new Rcon server, (ctx) ->
-        ctx.exec "changelevel #{map}", (res) ->
+    if server?.rcon
+
+      return new Rcon(server, (ctx) ->
+        ctx.exec("changelevel #{if map in maps then map else filtered[0]}", (res) ->
           ctx.close()
-          msg.reply "#{msg.random(responses.affirmative)} changing map as we speak..."
-
-    return msg.reply "#{msg.random(responses.mistake)} i don't know that map..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't to do that..."
+          msg.reply("#{msg.random(responses.affirmative)} changing map as we speak...")
+        )
+      )
+
+    return msg.reply("#{msg.random(responses.mistake)} i don't know that map...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't to do that...")

 exports.sg = (robot, msg) ->
   user = msg.message.user.id

   if robot.auth.hasRole(msg.envelope.user, 'officer')
     lobby = robot.brain.get('lobby')
-    return msg.reply "#{msg.random(responses.mistake)} it seems a pickup is already filling..." if lobby?
-
-    msg.send "#{msg.random(responses.affirmative)} starting a new pickup..."
+    return msg.reply("#{msg.random(responses.mistake)} it seems a pickup is already filling...") if lobby?
+
+    msg.send("#{msg.random(responses.affirmative)} starting a new pickup...")
+
+    validMap = msg.match[2] in maps
+    filtered = filterMaps(msg.match[2], maps)
+
+    if validMap
+      map = msg.match[2]
+    else if filtered.length is 1
+      map = filtered[0]
+    else
+      map = msg.random(maps)
+
+    created = newLobby(map, user, msg.random(serverList[0..3]))
+    robot.brain.set('lobby', created)
+    return msg.send("|| #{created.map} | #{Object.keys(created.participants).length}/12 | [  ] ||")
+
+  return msg.send("#{msg.random(responses.mistake)} you can't to do that...")
+
+exports.cg = (robot, msg) ->
+  user = msg.message.user.id
+
+  if robot.auth.hasRole(msg.envelope.user, 'officer')
+    lobby = robot.brain.get('lobby')
+    return msg.reply("#{msg.random(responses.mistake)} there\'s no pickup filling...") unless lobby?
+
+    robot.brain.set('lobby', null)
+
+    return msg.send("#{msg.random(responses.negative)}, pickup cancelled...")
+
+  return msg.send("#{msg.random(responses.negative)}, you can't to do that...")
+
+exports.add = (robot, msg) ->
+  user = msg.message.user.id
+  lobby = robot.brain.get('lobby')
+  target = if msg.match[1] is 'me' then user else msg.match[1].trim()
+
+  if target is 'me' or (target isnt 'me' and robot.auth.hasRole(msg.envelope.user, 'officer'))
+
+    if not lobby?
+      lobby = newLobby(msg.random(maps), user, msg.random(serverList[0..2]))
+      robot.brain.set('lobby', lobby)
+
+    players = Object.keys(lobby.participants)
+
+    if players.length < 12
+
+      if target not in players
+        lobby.participants[target] = target
+        robot.brain.set('lobby', lobby)
+        players = Object.keys(lobby.participants)
+        msg.send("|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||")
+        return unless players.length is 12 and not lobby.finalising
+
+        return setTimeout(finalising, 60000, robot, msg)
+
+      return msg.reply("#{if msg.match[1] is 'me' then 'you are' else target + ' is'} already added...")
+
+    return msg.reply("#{msg.random(responses.mistake)} the pickup is already full...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't to do that...")
+
+exports.rem = (robot, msg) ->
+  user = msg.message.user.id
+  target = if msg.match[1] is 'me' then user else msg.match[1]
+
+  if target is 'me' or (target isnt 'me' and robot.auth.hasRole(msg.envelope.user, 'officer'))
+    lobby = robot.brain.get('lobby')
+    return msg.reply("#{msg.random(responses.mistake)} there\'s no pickup filling...") if not lobby?
+
+    players = Object.keys(lobby.participants)
+
+    if target in players
+      delete lobby.participants[target]
+      players = Object.keys(lobby.participants)
+      robot.brain.set('lobby', lobby)
+      return msg.send("|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||")
+
+    return msg.reply("#{if msg.match[1] is 'me' then 'you\'re not' else target + '\'s not'} added to the pickup...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't do that...")
+
+exports.map = (robot, msg) ->
+  user = msg.message.user.id
+
+  if robot.auth.hasRole(msg.envelope.user, 'officer')
+
+    lobby = robot.brain.get('lobby')
+
+    return msg.reply("#{msg.random(responses.mistake)} there\'s no pickup filling...") unless lobby?

     validMap = msg.match[2] in maps
     filtered = filterMaps(msg.match[2], maps)
@@ -252,142 +347,54 @@
     else
       map = msg.random maps

-    created = newLobby(map, user, msg.random(serverList[0..3]))
-    robot.brain.set('lobby', created)
-    return msg.send "|| #{created.map} | #{Object.keys(created.participants).length}/12 | [  ] ||"
-
-  return msg.send "#{msg.random(responses.mistake)} you can't to do that..."
-
-exports.cg = (robot, msg) ->
+    lobby.map = map
+    robot.brain.set('lobby', lobby)
+    return msg.reply("#{msg.random(responses.affirmative)} changing map to #{map}...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't do that...")
+
+exports.server = (robot, msg) ->
   user = msg.message.user.id

   if robot.auth.hasRole(msg.envelope.user, 'officer')
-    lobby = robot.brain.get 'lobby'
-    return msg.reply "#{msg.random(responses.mistake)} there\'s no pickup filling..." unless lobby?
-
-    robot.brain.set 'lobby', null
-
-    return msg.send "#{msg.random(responses.negative)}, pickup cancelled..."
-
-  return msg.send "#{msg.random(responses.negative)}, you can't to do that..."
-
-exports.add = (robot, msg) ->
-  user = msg.message.user.id
-  lobby = robot.brain.get('lobby')
-  target = if msg.match[1] is 'me' then user else msg.match[1].trim()
-
-  if target is 'me' or (target isnt 'me' and robot.auth.hasRole msg.envelope.user, 'officer')
-
-    if not lobby?
-      lobby = newLobby msg.random(maps), user, msg.random(serverList[0..2])
-      robot.brain.set 'lobby', lobby
-
-    players = Object.keys lobby.participants
-
-    if players.length < 12
-
-      if target not in players
-        lobby.participants[target] = target
-        robot.brain.set 'lobby', lobby
-        players = Object.keys lobby.participants
-        msg.send "|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||"
-        return unless players.length is 12 and not lobby.finalising
-
-        return setTimeout finalising, 60000, robot, msg
-
-      return msg.reply "#{if msg.match[1] is 'me' then 'you are' else target + ' is'} already added..."
-
-    return msg.reply "#{msg.random(responses.mistake)} the pickup is already full..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't to do that..."
-
-exports.rem = (robot, msg) ->
-  user = msg.message.user.id
-  target = if msg.match[1] is 'me' then user else msg.match[1]
-
-  if target is 'me' or (target isnt 'me' and robot.auth.hasRole msg.envelope.user, 'officer')
-    lobby = robot.brain.get 'lobby'
-    return msg.reply "#{msg.random(responses.mistake)} there\'s no pickup filling..." if not lobby?
-
-    players = Object.keys lobby.participants
-
-    if target in players
-      delete lobby.participants[target]
-      players = Object.keys lobby.participants
-      robot.brain.set 'lobby', lobby
-      return msg.send "|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||"
-
-    return msg.reply "#{if msg.match[1] is 'me' then 'you\'re not' else target + '\'s not'} added to the pickup..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't do that..."
-
-exports.map = (robot, msg) ->
-  user = msg.message.user.id
-
-  if robot.auth.hasRole msg.envelope.user, 'officer'
-
-    lobby = robot.brain.get 'lobby'
-
-    return msg.reply "#{msg.random(responses.mistake)} there\'s no pickup filling..." unless lobby?
-
-    validMap = msg.match[2] in maps
-    filtered = filterMaps msg.match[2], maps
-
-    if validMap
-      map = msg.match[2]
-    else if filtered.length is 1
-      map = filtered[0]
-    else
-      map = msg.random maps
-
-    lobby.map = map
-    robot.brain.set 'lobby', lobby
-    return msg.reply "#{msg.random(responses.affirmative)} changing map to #{map}..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't do that..."
-
-exports.server = (robot, msg) ->
-  user = msg.message.user.id
-
-  if robot.auth.hasRole(msg.envelope.user, 'officer')

     lobby = robot.brain.get('lobby')

-    return msg.reply "#{msg.random(responses.mistake)} there\'s no pickup filling..." unless lobby?
+    return msg.reply("#{msg.random(responses.mistake)} there\'s no pickup filling...") unless lobby?

     if msg.match[1] in serverList
       lobby.server = msg.match[1]
-      robot.brain.set 'lobby', lobby
-      return msg.reply "#{msg.random(responses.affirmative)} changing the server to #{msg.match[1]}..."
-
-    return msg.reply "#{msg.random(responses.mistake)} #{msg.match[1]} isn't a valid server..."
-
-  return msg.reply "#{msg.random(responses.mistake)} you can't do that..."
+      robot.brain.set('lobby', lobby)
+      return msg.reply("#{msg.random(responses.affirmative)} changing the server to #{msg.match[1]}...")
+
+    return msg.reply("#{msg.random(responses.mistake)} #{msg.match[1]} isn't a valid server...")
+
+  return msg.reply("#{msg.random(responses.mistake)} you can't do that...")

 exports.status = (robot, msg) ->
   lobby = robot.brain.get('lobby')

-  return msg.reply "#{msg.random(responses.mistake)} there\'s currently no pickup..." unless lobby?
+  return msg.reply("#{msg.random(responses.mistake)} there\'s currently no pickup...") unless lobby?

   players = Object.keys(lobby.participants)
-  return msg.send "|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||"
+  return msg.send("|| #{lobby.server} | #{lobby.map} | #{players.length}/12 | [ #{players.join(', ')} ] ||")

 exports.previous = (robot, msg) ->
-  previous = robot.brain.get 'previous'
-  return msg.send "#{msg.random(responses.negative)}, no previous match data..." unless previous?
-  return msg.send "|| #{previous.principal} | #{previous.server} | #{previous.map} | [ #{Object.keys(previous.participants).join(', ')} ] | #{new Date(previous.createdAt).toString()} ||"
+  previous = robot.brain.get('previous')
+  return msg.send("#{msg.random(responses.negative)}, no previous match data...") unless previous?
+  return msg.send("|| #{previous.principal} | #{previous.server} | #{previous.map} | [ #{Object.keys(previous.participants).join(', ')} ] | #{new Date(previous.createdAt).toString()} ||")

 exports.top = (robot, msg) ->
-  today = robot.brain.get 'today'
-
-  return msg.send "#{msg.random(responses.negative)}, i haven't captured any daily data yet..." unless today?
+  today = robot.brain.get('today')
+
+  return msg.send("#{msg.random(responses.negative)}, i haven't captured any daily data yet...") unless today?

   response = '||'

   if msg.match[1] is 'maps'

     if not Object.keys(today.maps).length
-      return msg.send "#{msg.random(responses.negative)}, i haven't captured any daily map data yet..."
+      return msg.send("#{msg.random(responses.negative)}, i haven't captured any daily map data yet...")

     for map, played of today.maps
       response += " #{map}: #{played} |"
@@ -395,9 +402,9 @@
   else

     if not Object.keys(today.players).length
-      return msg.send "#{msg.random(responses.negative)}, i haven't captured any daily player data yet..."
+      return msg.send("#{msg.random(responses.negative)}, i haven't captured any daily player data yet...")

     for player, played of today.players
       response += " #{player}: #{played} |"

-  return msg.send "#{response}|"
+  return msg.send("#{response}|")


Ignore canceled errors and just terminate

--- src/login.coffee
+++ src/login.coffee
@@ -32,7 +32,12 @@
       .then(@getTwoFactorCode)
       .then(@createToken)
       .then(@saveToken)
-      .catch(callback)
+      .catch (error) ->
+        if error.message is 'canceled'
+          console.log()
+          callback()
+        else
+          callback(error)

   prompt: (options) ->
     readPromise = Q.denodeify(read)


Don't subscribe to the executable path config

--- lib/init.coffee
+++ lib/init.coffee
@@ -6,14 +6,6 @@
       title: 'The elm-make executable path.'
       type: 'string'
       default: 'elm-make'
-
-  activate: ->
-    @subscriptions = new CompositeDisposable
-    @subscriptions.add atom.config.observe 'linter-elm-make.elmMakeExecutablePath',
-      (executablePath) => @executablePath = executablePath
-
-  deactivate: ->
-    @subscriptions.dispose()

   provideLinter: ->
     proc = process
@@ -25,11 +17,12 @@
         return new Promise (resolve, reject) =>
           filePath = textEditor.getPath()
           lines = []
+          executablePath = atom.config.get 'linter-elm-make.elmMakeExecutablePath'
           options =
             cwd: atom.project.getPaths()[0]
             env: proc.env
           process = new BufferedProcess
-            command: @executablePath
+            command: executablePath
             args: [filePath, '--warn', '--report=json']
             options: options
             stdout: (data) ->
@@ -37,6 +30,7 @@
             exit: (code) =>
               text = lines[0]
               json = try JSON.parse(text.slice(0, text.indexOf("\n")))
+              console.log json if atom.inDevMode()
               return resolve [] unless json?
               resolve json.map (error) ->
                 type: error.type
@@ -48,7 +42,7 @@
                 ]

           process.onWillThrowError ({error,handle}) ->
-            atom.notifications.addError "Failed to run #{@executablePath}",
+            atom.notifications.addError "Failed to run #{executablePath}",
               detail: "#{error.message}"
               dismissable: true
             handle()


Update verbiage

Update verbiage

--- lib/main.coffee
+++ lib/main.coffee
@@ -19,7 +19,7 @@
       order: 2
     maxVisibleSuggestions:
       title: 'Maximum Visible Suggestions'
-      description: 'The autocomplete popup will only show this many suggestions.'
+      description: 'The suggestion list will only show this many suggestions.'
       type: 'integer'
       default: 10
       minimum: 1


improve apply timing

improve apply timing

--- lib/main.coffee
+++ lib/main.coffee
@@ -15,9 +15,10 @@
     # ContextMenu
     that.updateContextMenu(defC.Context)

-    # Settings
+    # Settings (on init and open)
+    that.updateSettings()
     atom.commands.add 'atom-workspace', 'settings-view:open', ->
-      that.updateSettings()
+      that.updateSettings(true)

   updateMenu: (menuList, def) ->
     return if not def
@@ -39,18 +40,31 @@
         label = set[item.command]
         item.label = label if label?

-  updateSettings: () ->
-    setTimeout(@delaySettings, 0, this)
+  updateSettings: (onOpen = false) ->
+    tab = document.querySelector('.tab-bar .active[data-type="SettingsView"]')
+    if tab != null || onOpen
+      setTimeout(@delaySettings, 0, this)
+    else

   delaySettings: (that) ->
-    panel = document.querySelector('.settings-view .panels-menu')
-    data = [
-      {label: "Settings", value: "設定"}
-      {label: "Keybindings", value: "キーバインド"}
-      {label: "Packages", value: "パッケージ"}
-      {label: "Themes", value: "テーマ"}
-      {label: "Updates", value: "パッケージの更新"}
-      {label: "Install", value: "パッケージのインストール"}
-    ]
-    for d in data
-      panel.querySelector("[name='#{d.label}']>a").text = d.value
+    try
+      panel = document.querySelector('.settings-view .panels-menu')
+      data = [
+        {label: "Settings", value: "設定"}
+        {label: "Keybindings", value: "キーバインド"}
+        {label: "Packages", value: "パッケージ"}
+        {label: "Themes", value: "テーマ"}
+        {label: "Updates", value: "アップデート"}
+        {label: "Install", value: "インストール"}
+      ]
+      for d in data
+        el = panel.querySelector("[name='#{d.label}']>a")
+        el.text = d.value
+        el.setAttribute('title', d.label)
+
+      ext = document.querySelector('.settings-view .icon-link-external')
+      before = ext['textContent']
+      ext['textContent'] = "設定フォルダを開く"
+      ext.setAttribute('title', before)
+    catch e
+      console.error "日本語化に失敗しました。", e


:fire: Remove legacy versionMatch method

--- lib/main.coffee
+++ lib/main.coffee
@@ -23,9 +23,6 @@
   PluginManagement.includeInto(this)

   ### Public ###
-
-  # The minimap package version
-  version: require('../package.json').version

   # The default minimap settings
   config:
@@ -128,18 +125,6 @@
     @editorsMinimaps = undefined
     @toggled = false
     @active = false
-
-  # Verifies that the passed-in version expression is satisfied by
-  # the current minimap version.
-  #
-  # expectedVersion - A [semver](https://github.com/npm/node-semver)
-  #                   compatible expression to match agains the minimap
-  #                   version.
-  #
-  # Returns a {Boolean}.
-  versionMatch: (expectedVersion) ->
-    semver ?= require 'semver'
-    semver.satisfies(@version, expectedVersion)

   # Toggles the minimap display.
   toggle: ->


remove config property temporarily

remove config property temporarily

--- lib/main.coffee
+++ lib/main.coffee
@@ -10,8 +10,8 @@
   # serialize: ->
   # getProvider: -> [jsProvider]
   getClickProvider: -> clickProvider.getProvider()
-  config:
-    openSourceInSplitWindow:
-      type: 'boolean'
-      default: false
-      title: 'Open source in split window'
+  # config:
+  #   openSourceInSplitWindow:
+  #     type: 'boolean'
+  #     default: false
+  #     title: 'Open source in split window'


s/edit/editable/ for clarity

s/edit/editable/ for clarity

--- lib/main.coffee
+++ lib/main.coffee
@@ -49,7 +49,7 @@
     $el.find('button.reset').click =>
       $el.find('button.reset').hide()
       @annotations.reset()
-      @map.edit = true
+      @map.editable = true

   update: (state) =>
     open = state.open
@@ -68,7 +68,7 @@
     @path = new PathFinder @map, neighborStrategy

   run: (@callback) =>
-    @map.edit = false
+    @map.editable = false
     @annotations.reset()
     setTimeout @tick, @delay

@@ -208,7 +208,7 @@
     @updatePoint start, 'start' if start
     @updatePoint goal, 'goal' if goal

-    @edit = interactive
+    @editable = interactive
     @drag = null # what's being dragged, if anything

     $('body').on 'mouseup', @mouseup
@@ -262,14 +262,14 @@
     squares.attr('class', (d, i) -> d[2])

   mousedown: (d, i) =>
-    return unless @edit
+    return unless @editable
     square = d3.select(d3.event.target)
     @drag = square.attr 'class'
     @mouseover d, i
     d3.event.preventDefault()

   mouseup: =>
-    return unless @edit
+    return unless @editable
     switch @drag
       when 'start'
         start = @grid.mapSelection.selectAll('rect.start')
@@ -280,7 +280,7 @@
     @drag = null

   mouseover: (d, i) =>
-    return unless @edit and @drag
+    return unless @editable and @drag

     touches = d3.event.changedTouches
     coords = if touches?


:bug: Handle Invalid Linters in main.coffee

--- lib/main.coffee
+++ lib/main.coffee
@@ -25,7 +25,11 @@
         @consumeLinter(linter)

   consumeLinter: (linter) ->
-    @instance.linters.push linter
+    if linter.grammarScopes instanceof Array and typeof linter.lint is 'function'
+      @instance.linters.push linter
+    else
+      err = new Error("Invalid Linter Provided")
+      atom.notifications.addError err.message, {detail: err.stack}

   consumeStatusBar: (statusBar) ->
     @instance.views.attachBottom(statusBar)


:art: cleanup

:art: cleanup

--- lib/main.coffee
+++ lib/main.coffee
@@ -127,14 +127,15 @@
       editorSubs.add editor.onDidStopChanging =>
         return unless getEditor() is editor
         URI = editor.getURI()
-        @refreshEditor(e) for e in getVisibleEditors() when (e.getURI() is URI)
+        for e in getVisibleEditors() when (e.getURI() is URI)
+          @refreshEditor(e)

       editorElement = getView(editor)
       editorSubs.add(editorElement.onDidChangeScrollTop => @refreshEditor(editor))

       # [FIXME]
-      # @refreshEditor depend on editorElement.getVisibleRowRange() but it return
-      # [undefined, undefined] when it called on editorElement not attached yet.
+      # @refreshEditor depends on editorElement.getVisibleRowRange() but it return
+      # [undefined, undefined] when it called on editorElement which is not attached yet.
       # So we separately need to cover this case from Atom v1.1.0
       editorSubs.add(editorElement.onDidAttach => @refreshEditor(editor))

@@ -219,14 +220,17 @@
     editor = getEditor()
     selection = editor.getLastSelection()
     {cursor} = selection
-    point = cursor.getBufferPosition()
+
     if selection.isEmpty()
-      @withLock -> selection.selectWord()
-
-    word = selection.getText()
-    unless cursor.getBufferPosition().isEqual(point)
-      @withLock -> cursor.setBufferPosition(point)
-    word
+      text = null
+      point = cursor.getBufferPosition()
+      @withLock ->
+        selection.selectWord()
+        text = selection.getText()
+        cursor.setBufferPosition(point)
+      text
+    else
+      selection.getText()

   toggle: (keyword) ->
     keyword ?= @getKeywordUnderCursor()
@@ -250,7 +254,7 @@
     decorationStyle = getConfig('decorate')
     @keywords.each (keyword, color) =>
       color = "#{decorationStyle}-#{color}"
-      decorations = decorations.concat @highlightKeyword(editor, scanRange, keyword, color)
+      decorations = decorations.concat(@highlightKeyword(editor, scanRange, keyword, color))
     @decorationsByEditor.set(editor, decorations)

   highlightKeyword: (editor, scanRange, keyword, color) ->


reuse converter

reuse converter

--- lib/main.coffee
+++ lib/main.coffee
@@ -402,24 +402,26 @@
             console.log 'inspect result:', result
             found = result['found']
             if found is true
+                if not @convert?
+                    @convert = new convertAnsi()
                 data = result['data']
                 lines = data['text/plain'].split('\n')
-                convert = new convertAnsi()
-                firstline = convert.toHtml(lines[0])
+                firstline = @convert.toHtml(lines[0])
                 lines.splice(0,1)
-                message = convert.toHtml(lines.join('\n'))
+                message = @convert.toHtml(lines.join('\n'))
+
                 if not @inspector?
                     console.log "Opening Inspector"
                     @inspector = new MessagePanelView
                         title: 'Hydrogen Inspector'
                 else
                     @inspector.clear()
+
                 @inspector.attach()
                 @inspector.add new PlainMessageView
                     message: firstline
                     className: 'inspect-message'
                     raw: true
-
                 @inspector.add new PlainMessageView
                     message: message
                     className: 'inspect-message'


rename

rename

--- lib/main.coffee
+++ lib/main.coffee
@@ -99,16 +99,16 @@
   #  - Event capture phase: Cursor position is not yet changed.
   #  - Event bubbling phase: Cursor position updated to clicked position.
   observeMouse: ->
-    stack = []
+    locationStack = []
     handleCapture = ({target}) ->
       model = target.getModel?()
-      return unless model?.getURI?()
-      stack.push(new Location('mousedown', model))
+      if model?.getURI?()
+        locationStack.push(new Location('mousedown', model))

     handleBubble = ({target}) =>
       return unless target.getModel?()?.getURI?()?
       setTimeout =>
-        @checkLocationChange(location) if location = stack.pop()
+        @checkLocationChange(location) if location = locationStack.pop()
       , 100

     workspaceElement = atom.views.getView(atom.workspace)


Fix module export

Fix module export

--- lib.coffee
+++ lib.coffee
@@ -5,7 +5,7 @@

 formatRegex = /([QeEAaXx]|M{1,4}o?|D{1,4}o?|d{1,4}o?|w{1,2}o?|W{1,2}o?|Y{2,4}|g{2,4}|G{2,4}|H{1,2}|h{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,2}|Z{1,2})/

-PickerMixin = @PickerMixin =
+PickerMixin =
   getDefaultProps: ->
     format = defaultFormat
     defaultValue = (do moment).format format
@@ -44,7 +44,7 @@
     delta *= n
     @changeValue -> @add delta, p

-YearPicker = @YearPicker = createClass
+YearPicker = createClass
   mixins: [
     PickerMixin
   ]
@@ -116,7 +116,7 @@
                     onClick: @pickYear year
                     year

-MonthPicker = @MonthPicker = createClass
+MonthPicker = createClass
   mixins: [
     PickerMixin
   ]
@@ -146,7 +146,7 @@
                   onClick: @pickMon month
                   (moment month + 1, "M").format "MMMM"

-DatePicker = @DatePicker = createClass
+DatePicker = createClass
   mixins: [
     PickerMixin
   ]
@@ -243,7 +243,7 @@
                     onClick: @pickDate date
                     date

-TimePicker = @TimePicker = createClass
+TimePicker = createClass
   mixins: [
     PickerMixin
   ]
@@ -345,7 +345,7 @@
                     createElement Glyphicon,
                       glyph: "chevron-down"

-@DateTime = createClass
+DateTime = createClass
   propTypes: ->
     label: PropTypes.string
     help: PropTypes.string
@@ -458,3 +458,12 @@
                   display: timePart
                   onChange: @handleTime
                   value: value
+
+module.exports = {
+  PickerMixin
+  YearPicker
+  MonthPicker
+  DatePicker
+  TimePicker
+  DateTime
+}


Build: modules defined where they are necessary

to be able to use the framework as a submodule

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -6,18 +6,14 @@
 rename     = require 'gulp-rename'
 uglify     = require 'gulp-uglify'
 stylus     = require 'gulp-stylus'
-livereload = require 'gulp-livereload'
 concat     = require 'gulp-concat'
 minifyCSS  = require 'gulp-minify-css'
-karma      = require 'gulp-karma'
 rimraf     = require 'gulp-rimraf'
-markdox    = require 'gulp-markdox'
 fs         = require 'fs'
 http       = require 'http'
 argv       = require('minimist') process.argv
 source     = require 'vinyl-source-stream'
 gulpBuffer = require 'gulp-buffer'
-express    = require 'express'
 Promise    = require 'bluebird'
 exec       = Promise.promisify (require 'child_process').exec

@@ -42,6 +38,7 @@
   b.bundle()

 watchLogger = (color, watcher) ->
+  livereload = require 'gulp-livereload'
   server = livereload()  if useLiveReload
   watcher.on 'change', (event) ->
     log color, "file #{event.path} was #{event.type}"
@@ -120,6 +117,7 @@

 gulp.task 'play-html', ->

+  livereload = require 'gulp-livereload'
   gulp.src './playground/index.html'
     .pipe gulpif useLiveReload, livereload()

@@ -160,6 +158,7 @@

 gulp.task 'docs-html', ->

+  livereload = require 'gulp-livereload'
   gulp.src './docs/index.html'
     .pipe gulpif useLiveReload, livereload()

@@ -227,10 +226,13 @@

 gulp.task 'karma', ['coffee-test'], ->

+  karma = require 'gulp-karma'
+
   gulp.src testFiles
     .pipe karma
       configFile : 'karma.conf.js'
       action     : karmaAction
+

 gulp.task 'sauce', ->
   gulp.src testFiles
@@ -328,6 +330,9 @@

 # Use markdox to output markdown files for the API Documentation.
 gulp.task 'markdox', ->
+
+  markdox = require 'gulp-markdox'
+
   gulp.src [
       'src/**/core/**/*.coffee'
       'src/**/components/**/*.coffee'


Add clean

Add clean

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -13,6 +13,8 @@
 gulp.task 'clean-build', ->
   gulp.src './lib/*'
     .pipe clean { force: true }
+
+gulp.task 'clean', ['clean-build']

 gulp.task 'lint', ->
   gulp.src srcFiles.concat ['./*.coffee', './spec/**/*.coffee']


deleted unnecessary code

deleted unnecessary code

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -23,10 +23,7 @@
     jsurl : 'components/jsurl/url.min.js'

   test:
-    src   : ['test/source/test.url.coffee'
-             'test/source/test.ajax.coffee'
-             'test/source/test.store.coffee'
-             'test/source/test.notification.coffee']
+    src   : 'test/source/test.url.coffee'
     dist  : 'test/dist'
     index : 'test/index.html'


Concat, then Uglify

Concat, then Uglify

Not the other way around.

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -46,8 +46,8 @@
   gulp.src COFFEE_PATH
     .pipe sourcemaps.init()
     .pipe coffee()
+    .pipe concat 'app.js'
     .pipe uglify mangle: false
-    .pipe concat 'app.js'
     .pipe sourcemaps.write()
     .pipe gulp.dest "#{DEST}/scripts"


Support Windows

Support Windows

Support the softlink for javascript folder in Windows

--- gulpfile.coffee
+++ gulpfile.coffee
@@ -69,10 +69,6 @@
 gulp.task 'default', ->
   console.log """

-*************************************
-*** Currently, for Linux/Mac only ***
-*************************************
-
 1. gulp compile --version x.y.z.ddmm
 2. gulp dev

@@ -118,7 +114,7 @@
   # for js only (no compile, just soft link)
   js_dest_path = path.join(dev_path, lang.js.dest)
   rmdirp js_dest_path
-  fs.symlinkSync path.join('..', lang.js.source), js_dest_path
+  fs.symlink path.join('..', lang.js.source), js_dest_path, 'dir'

   compileManifest dev_path, (manifest_json) ->
     manifest_json.name += '(dev)'


moved super to top of some constructors

moved super to top of some constructors

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -1161,9 +1161,12 @@
       members.unshift new Assign(new Value(new Literal("constructor")), ctor, 'object')

     # bind members
-    for bvar in boundFuncs
-      lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
-      ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
+    if boundFuncs.length > 0
+      hopefullySuper = ctor.body.expressions.shift()
+      for bvar in boundFuncs
+        lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
+        ctor.body.expressions.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
+      ctor.body.expressions.unshift hopefullySuper if hopefullySuper

     members