templates : register partials with full template name

--- src/client/templates.coffee
+++ src/client/templates.coffee
@@ -1,8 +1,8 @@
 define ['lib/hullbase', 'handlebars'], (Hull, Handlebars)->
   init: (env)->
-    setupTemplate = (tplSrc, name) ->
+    setupTemplate = (tplSrc, tplName) ->
       compiled = env.core.template.hbs(tplSrc)
-      Handlebars.registerPartial(name, compiled)
+      Handlebars.registerPartial(tplName, compiled)
       compiled

     env.core.template.load = (names, ref, format="hbs")->
@@ -18,18 +18,18 @@
         # if require.defined(path)
         #   ret[tpl] = require(path)
         # else
-        tplName = [widgetName, name].join("/")
+        tplName = [widgetName, name.replace(/^_/, '')].join("/")
         localTpl = env.core.dom.find("script[data-hull-template='#{tplName}']")
         if localTpl.length
-          parsed = setupTemplate(localTpl.text(), name)
+          parsed = setupTemplate(localTpl.text(), tplName)
           ret[name] = parsed
           define path, parsed
         else if Hull.templates["#{tplName}"]
-          parsed = setupTemplate(Hull.templates["#{tplName}"], name)
+          parsed = setupTemplate(Hull.templates["#{tplName}"],  tplName)
           ret[name] = parsed
           define path, parsed
         else if Hull.templates._default?["#{tplName}"]
-          parsed = setupTemplate(Hull.templates._default["#{tplName}"], name)
+          parsed = setupTemplate(Hull.templates._default["#{tplName}"],  tplName)
           ret[name] = parsed
           define path, parsed
         else
@@ -40,7 +40,8 @@
           res = Array.prototype.slice.call(arguments)
           for t,i in res
             name = paths[i][0]
-            ret[name] = setupTemplate(t, name)
+            tplName = [widgetName, name].join("/")
+            ret[name] = setupTemplate(t, tplName)
           dfd.resolve(ret)
         , (err)->
           console.error("Error loading templates", paths, err)


Fix ordering logs in sidebar

Fix ordering logs in sidebar

--- admin/static/coffee/sidebar.coffee
+++ admin/static/coffee/sidebar.coffee
@@ -99,11 +99,11 @@
             need_render = false
             for machine_id, data of response
                 for new_log_entry in data
-                    for old_log_entry in @log_entries
-                        if new_log_entry.timestamp > old_log_entry.get('timestamp')
+                    for old_log_entry, i in @log_entries
+                        if parseFloat(new_log_entry.timestamp) > parseFloat(old_log_entry.get('timestamp'))
                             entry = new LogEntry new_log_entry
                             entry.set('machine_uuid', machine_id)
-                            @log_entries.unshift entry
+                            @log_entries.splice i, 0, entry
                             need_render = true
                             break


modified TODOs which will never be seen

modified TODOs which will never be seen

--- script/stairs.coffee
+++ script/stairs.coffee
@@ -118,5 +118,5 @@
   # renderer.setSize( window.innerWidth, window.innerHeight )
   # controls.handleResize()

-# TODO:spotlight & camera.setlens
-# TODO:shake camera
+# TODO:camera.setlens
+# TODO:shake camera,using THREE.PathControls


fixed manual color setting in apps (box and whisker)

--- src/core/fetch/color.coffee
+++ src/core/fetch/color.coffee
@@ -6,6 +6,9 @@

 # Finds an object's color and returns random if it cannot be found
 module.exports = (vars, id, level) ->
+
+  obj = validObject id
+  return id.d3plus.color if obj and "d3plus" of id and "color" of id.d3plus

   level = vars.id.value unless level
   level = vars.id.nesting[level] if typeof level is "number"
@@ -19,7 +22,7 @@

     while i >= 0
       colorLevel = vars.id.nesting[i]
-      if validObject(id)
+      if obj
         value = uniques id, vars.color.value, fetchValue, vars, colorLevel
         value = value[0] if value.length is 1
       else


relative requires...

relative requires...

--- test/test_compilation.coffee
+++ test/test_compilation.coffee
@@ -1,6 +1,6 @@
 # Ensure that carriage returns don't break compilation on Windows.
-CoffeeScript: require('coffee-script')
-Lexer: require('coffee-script/lexer')
+CoffeeScript: require('./../lib/coffee-script')
+Lexer: require('./../lib/lexer')

 js: CoffeeScript.compile("one\r\ntwo", {no_wrap: on})


style: add empty lines to config specs

style: add empty lines to config specs

--- test/unit/config.spec.coffee
+++ test/unit/config.spec.coffee
@@ -234,12 +234,14 @@
       expect(config.basePath).to.equal resolveWinPath('/some') # overriden by CLI
       expect(config.urlRoot).to.equal '/' # default value

+
     it 'should not read config file, when null but still resolve cli basePath', ->
       config = e.parseConfig null, {basePath: './some' }

       expect(logSpy).not.to.have.been.called
       expect(config.basePath).to.equal resolveWinPath('./some')
       expect(config.urlRoot).to.equal '/' # default value
+

   describe 'normalizeConfig', ->


More logging...yay

More logging...yay

--- src/adapters/campfire.coffee
+++ src/adapters/campfire.coffee
@@ -50,7 +50,7 @@
       unless bot.info.id == author.id
         self.receive new Robot.LeaveMessage(author)

-    bot.on "TimestampMessage",  ->
+    bot.on "TimestampMessage",  room ->
       author = bot.Me
       author.room = room
       console.log "Timestamp"


:lipstick: whitespace

:lipstick: whitespace

--- src/app/language-mode.coffee
+++ src/app/language-mode.coffee
@@ -25,7 +25,7 @@
     @subscribe syntax, 'grammar-added', (grammar) =>
       newScore = grammar.getScore(@buffer.getPath(), @buffer.getText())
       @setGrammar(grammar, newScore) if newScore > @currentGrammarScore
-
+
   # Internal:
   destroy: ->
     @unsubscribe()
@@ -159,7 +159,7 @@

   # Public: Given a buffer row, this returns a suggested indentation level.
   #
-  # The indentation level provided is based on the current {LanguageMode}.
+  # The indentation level provided is based on the current {LanguageMode}.
   #
   # bufferRow - A {Number} indicating the buffer row
   #


add tests

add tests

--- tests/mocha/unit/normalizer.coffee
+++ tests/mocha/unit/normalizer.coffee
@@ -198,6 +198,22 @@
       expected: [0]
     )

+    docTest.run('correct trailing newline',
+      initial:  [
+        '
Test
'
+        '

'
+      ]
+      expected: [0, 1]
+    )
+
+    docTest.run('correct multiline',
+      initial:  [
+        '
One
'
+        '
Two
'
+      ]
+      expected: [0, 1]
+    )
+
     docTest.run('handle nonstandard block tags',
       initial: [
         '


no need to create entire editor for test

--- tests/scripts/unit/document.coffee
+++ tests/scripts/unit/document.coffee
@@ -3,11 +3,11 @@
     it('should find correct offset in line', ->
       lines = ['

', '
12
', '
45
', '

', '

', '

78

', '

']
       $('#test-container').html(lines.join(''))
-      editor = new Scribe.Editor('test-container')
-      lines = editor.doc.lines.toArray()
+      doc = new Scribe.Document($('#test-container').get(0))
+      lines = doc.lines.toArray()
       _.each([[0], [1,2,3], [4,5,6], [7], [8], [9,10,11], [12]], (indexGroup, lineIndex) ->
         _.each(indexGroup, (index, indexIndex) ->
-          [line, offset] = editor.doc.findLineAtOffset(index)
+          [line, offset] = doc.findLineAtOffset(index)
           expect([line.id, offset]).to.deep.equal([lines[lineIndex].id, indexIndex])
         )
       )


tests: fixed missing browser.end() and async browser.end()s

--- tests/src/activity/postwith.coffee
+++ tests/src/activity/postwith.coffee
@@ -29,7 +29,7 @@
     # added 'hello world' bc it first thinks that you type http://placehold.it/
     # and renders it as a link, but if we continue typing it understands that
     # it is an image
-    image = 'http://placehold.it/200x100 hello world!'
+    image    = 'http://placehold.it/200x100 hello world!'
     selector = activitySelector + ' .activity-content-wrapper .embed-image-view img'

     browser
@@ -48,7 +48,7 @@

     helpers.beginTest(browser)

-    link = 'http://wikipedia.org/'
+    link         = 'http://wikipedia.org/'
     linkSelector = activitySelector + ' .activity-content-wrapper article a'

     helpers.doPostActivity(browser, link, yes, yes)
@@ -57,7 +57,7 @@
       href = result.value
       assert.equal(link, href)

-    browser.end()
+      browser.end()

   postCommentWithCode: (browser) ->
@@ -94,13 +94,15 @@
       href = result.value
       assert.equal(image, href)

+      browser.end()
+

   postCommentWithLink: (browser) ->

     helpers.beginTest(browser)

-    post     = helpers.getFakeText()
-    link = 'http://wikipedia.org/'
+    post         = helpers.getFakeText()
+    link         = 'http://wikipedia.org/'
     linkSelector = activitySelector + ' .comment-contents .comment-body-container .has-markdown a'

     helpers.doPostActivity(browser, post)
@@ -110,4 +112,4 @@
       href = result.value
       assert.equal(link, href)

-    browser.end()
+      browser.end()


Revert "remove unused code, tweak active node styling."

This reverts commit 3489924554b4023952251587178df9f858ad8038.

--- scripts/bungie-data-helper.coffee
+++ scripts/bungie-data-helper.coffee
@@ -1,6 +1,12 @@
 request = require('request')

 class DataHelper
+  'fetchDefs': ->
+    @fetchStatDefs (error, response, body) =>
+      @statDefs = JSON.parse(body)
+    @fetchVendorDefs (error, response, body) =>
+      @vendorDefs = JSON.parse(body)
+
   'serializeFromApi': (response) ->
     damageColor =
       Kinetic: '#d9d9d9'
@@ -26,6 +32,9 @@
     nodes: response.data.talentNodes
     nodeDefs: response.definitions.talentGrids[item.talentGridHash].nodes
     damageType: damageTypeName
+
+  'parseItemsForAttachment': (items) ->
+    items.map (item) => @parseItemAttachment(item)

   'parseItemAttachment': (item) ->
     name = "#{item.itemName}"
@@ -66,6 +75,18 @@
       column++
     return orderedNodes

+  # creates fields for perks and their descriptions
+  'buildFields': (nodes, nodeDefs) ->
+    displayNodes = nodes.map (node) ->
+      step = nodeDefs[node.nodeIndex].steps[node.stepIndex]
+      description = step.nodeStepDescription.replace(/(\r\n|\n|\r)/gm," ").replace("  "," ")
+
+      title: step.nodeStepName
+      value: description
+      short: true
+
+    displayNodes.filter (x) -> x
+
   'buildText': (nodes, nodeDefs) ->
     getName = (node) ->
       step = nodeDefs[node.nodeIndex].steps[node.stepIndex]
@@ -77,11 +98,27 @@
       column = nodeDefs[node.nodeIndex].column
       name = step.nodeStepName
       if node.isActivated
-        name = "*#{step.nodeStepName}*"
+        name = '_*' + step.nodeStepName + '*_'
       text[column] = "" unless text[column]
       text[column]+= name + " | "

     setText node for node in nodes
     return text

+  'fetchVendorDefs': (callback) ->
+    options =
+      method: 'GET'
+      url: 'http://destiny.plumbing/raw/mobileWorldContent/en/DestinyStatDefinition.json'
+      gzip: true
+
+    request(options, callback)
+
+  'fetchStatDefs': (callback) ->
+    options =
+      method: 'GET'
+      url: 'http://destiny.plumbing/raw/mobileWorldContent/en/DestinyStatDefinition.json'
+      gzip: true
+
+    request(options, callback)
+
 module.exports = DataHelper


Added news

Added news

--- server/materials/data/news.coffee
+++ server/materials/data/news.coffee
@@ -3,38 +3,26 @@

 export default allNews = () ->
     return news([
-        newsItem("Занятие 19 декабря в ВШЭ начнется в 14.15", String.raw"""
-            19 декабря занятие в ВШЭ начнется в 14.15.
+        newsItem("Алгопрог-Новый год: новости", String.raw"""
+            Алгопрог-Новый год состоится 6 января, приглашаются все ученики алгопрога, кто будет в Нижнем Новгороде.
+            Напишите мне, чтобы я вас добавил в секретный телеграм-чат :)
         """),
-        newsItem("Запись обсуждения районной олимпиады", String.raw"""
-            Выложена видеозапись занятия от 05.12.2021 про районную олимпиаду.
-            Также можете посмотреть видеозапись аналогичного занятия 2019 г., в частности,
-            там есть обсуждение более старых задач.
+        newsItem("26 декабря занятия во ВШЭ не будет", String.raw"""
+            26 декабря занятия во ВШЭ не будет, следующее занятие будет 9 января.
+        """),
+        newsItem("Занятия в праздники", String.raw"""
+            26 декабря и 2 января занятий во ВШЭ не будет, следующее занятие 9 января.

+            22 декабря занятие в лицее 40 будет, 29 декабря и 5 января занятий в лицее 40 не будет, первое занятие в новом году — 12 января.
         """),
         newsItem("Зимние алгопрог-сборы", String.raw"""
             С 3 по 9 января пройдут зимние алгопрог-сборы, основная цель — подготовка к региональному этапу ВсОШ. Участвовать могут все желающие.
             Подробная информация и анкета участника.
-        """),
-        newsItem("Алгопрог-Новый год", String.raw"""
-            В новогодние каникулы я хочу организовать празднование Нового года для нижегородских школьников Алгопрога
-            (ну и если будут желающие, то и не только нижегородских, и не только школьников, и не только Алгопрога).
-            Кто хочет участвовать, заполните, пожалуйста, форму.
         """),
         newsItem("Конкурс дизайна футболок и стикеров", String.raw"""
             В течение декабря-января принимаю предложения на дизайн «дополнительных» («платных») футболок и стикеров алгопрога.
             Тем, кто предложит наиболее понравившиеся мне дизайны — соответствующая футболка/стикеры бесплатно независимо от вашего уровня.
             Подробнее в конце текста про футболки.
         """),
-        newsItem("Футболки: новости!", String.raw"""
-            Доступны футболки с логотипом алгопрога за более высокие уровни (5В, 7В, 9В, 11В). Пишите.
-            Также доступны футболки для тех, кто занимался раньше.
-        """),
-        newsItem("Занятия для старших уровней", String.raw"""
-            С 21 ноября возобновляются занятия для старших уровней — по воскресеньям, параллельно с основным занятием во ВШЭ. Подробнее.
-        """),
-        newsItem("Районная олимпиада", String.raw"""
-            Районная олимпиада в Нижегородской области в этом году будет, предварительно, 16 декабря. На сайт добавлена подробная информация, также в архив районных олимпиад добавлены задачи прошлого года.
-        """),
         newsItem("Опрос про алгопрог", String.raw"""
             Ответьте, пожалуйста, на несколько вопросов. Тем, кто уже отвечал — я там добавил несколько вопросов, можете ответить еще раз.
         """),


specific handler for starting points

specific handler for starting points

--- src/coffee/directives.coffee
+++ src/coffee/directives.coffee
@@ -42,6 +42,10 @@

   Directives.directive 'startingPoint', ($window) ->
     restrict: 'E'
+    controller: ($scope) ->
+      $scope.reset = -> $scope.$broadcast 'reset'
+      $scope.act = -> $scope.$broadcast 'act'
+
     link: (scope, element, attrs) ->

       if scope.tool.expandable


Add TestCommand to FeedContext

Add TestCommand to FeedContext

--- src/context/feed/feed.coffee
+++ src/context/feed/feed.coffee
@@ -20,6 +20,10 @@
     @$emitDomainEvent "FeedCaptionChanged",
       caption: caption
   return
+
+
+feedContext.addCommandHandler "TestCommand", (params, done) ->
+  console.log "---------------- TestCommand ----------------"

 feedContext.addCommandHandler "CreateFeed", (params, done) ->


Update documentation

Update documentation

--- src/core/types/object.coffee
+++ src/core/types/object.coffee
@@ -59,11 +59,25 @@

 # Retuns `true` if the specified values is contained in one of the object
 # enumerable properties.
+#
+#     object =
+#       foo: 10
+#       bar: 20
+#
+#     object.has 20 # true
+#     object.has 30 # false
 def Object, has: (value) -> value in @values()

 ##### Object::hasKey

 # Returns `true` if the specified key is defined on this object.
+#
+#     object =
+#       foo: 10
+#       bar: 20
+#
+#     object.hasKey 'foo' # true
+#     object.hasKey 'baz' # false
 def Object, hasKey: (key) -> @[key]?

 ##### Object::keys
@@ -72,6 +86,12 @@
 #
 # The keys are returned as the `for..in` construct iterates on them.
 # Use `sortedKeys` to retreive the keys sorted alphabetically.
+#
+#     object =
+#       foo: 10
+#       bar: 20
+#
+#     object.keys() # ['foo', 'bar']
 def Object, keys: -> k for k of this

 ##### Object::length
@@ -132,6 +152,12 @@
 ##### Object::sortedKeys

 # Returns the enumerable keys sorted alphabetically.
+#
+#     object =
+#       foo: 10
+#       bar: 20
+#
+#     object.sortedKeys() # ['bar', 'foo']
 def Object, sortedKeys: -> @keys().sort()

 ##### Object::sortedValues
@@ -139,6 +165,12 @@
 # Returns the values of the enumerable properties of this object.
 # The values are ordered such as each key in `sortedKeys` correspond
 # to the value at the same index in `sortedValues`.
+#
+#     object =
+#       foo: 10
+#       bar: 20
+#
+#     object.sortedValues() # [20, 10]
 def Object, sortedValues: -> @[k] for k in @sortedKeys()

 ##### Object::type
@@ -159,6 +191,12 @@
 # The values are returned as the `for..in` construct iterates on this object.
 # Use `sortedValues` to retreive the values based on the alphabetically
 # sorted keys.
+#
+#     object =
+#       foo: 10
+#       bar: 20
+#
+#     object.values() # [10, 20]
 def Object, values: -> @[k] for k in @keys()

 #### Duck Typing


fixed commit tab page shows commit log twice

--- app/assets/javascripts/commits.js.coffee
+++ app/assets/javascripts/commits.js.coffee
@@ -42,6 +42,7 @@
       @disable = true

   @initLoadMore: ->
+    $(document).unbind('scroll')
     $(document).endlessScroll
       bottomPixels: 400
       fireDelay: 1000


Initialize and set focus on rename_column form

--- app/assets/javascripts/erd/erd.js.coffee
+++ app/assets/javascripts/erd/erd.js.coffee
@@ -259,6 +259,7 @@
       .show()
       .find('a.cancel')
       .show()
+      .end()
       .find('input[name=to]')
       .val(text)
       .focus()


use parseFloat

use parseFloat

--- app/assets/javascripts/erd/erd.js.coffee
+++ app/assets/javascripts/erd/erd.js.coffee
@@ -25,7 +25,7 @@
     $('#changes').show()

   positions: (div) ->
-    [left, width, top, height] = [parseInt(div.css('left')), parseInt(div.css('width')), parseInt(div.css('top')), parseInt(div.css('height'))]
+    [left, width, top, height] = [parseFloat(div.css('left')), parseFloat(div.css('width')), parseFloat(div.css('top')), parseFloat(div.css('height'))]
     {left: left, right: left + width, top: top, bottom: top + height, center: {x: (left + left + width) / 2, y: (top + top + height) / 2}, vertex: {}}

   connect_arrows: ->


Fix regression:  Enable "submit" click button again.

--- app/assets/javascripts/prediction.coffee
+++ app/assets/javascripts/prediction.coffee
@@ -17,6 +17,10 @@
     $(document).on "no_answer_for", (e,opts) =>
       if opts.source == @$form.attr('id')
         @disable_submit_button()
+    @$button.click (e) =>
+      if @submit_enabled
+        @record_answer()
+        @disable_form()

   enable_submit_button: ->
     console.log "enabled button"


Added support for custom commands in presets.

--- app/assets/javascripts/presets.js.coffee
+++ app/assets/javascripts/presets.js.coffee
@@ -16,6 +16,35 @@
   html = """

       Refresh
       <input type="text" _name="name" value="#{name}" />
+      every
+      <input type="text" _name="age" value="#{age}" />
+      seconds
+       x
+
"""
+
+  el = $(html)
+  $(container).append(el)
+  el.hide().fadeIn(300) if fade
+
+
+window.addCustomCommandValueConfiguration = (container, command = '', value = '', fade = true) ->
+  html = """

+      Command
+      <input type="text" _name="command" value="#{command}" />
+      Assert value
+      <input type="text" _name="value" value="#{value}" />
+       x
+
"""
+
+  el = $(html)
+  $(container).append(el)
+  el.hide().fadeIn(300) if fade
+
+
+window.addCustomCommandAgeConfiguration = (container, command = '', age = '', fade = true) ->
+  html = """

+      Execute
+      <input type="text" _name="command" value="#{command}" />
       every
       <input type="text" _name="age" value="#{age}" />
       seconds
@@ -99,6 +128,10 @@
         addAddObjectConfiguration(container_selector, c['name'], c['object'], false)
       when 'delete_object'
         addRemoveObjectConfiguration(container_selector, c['name'], c['object'], false)
+      when 'custom_command_value'
+        addCustomCommandValueConfiguration(container_selector, c['command'], c['value'])
+      when 'custom_command_age'
+        addCustomCommandAgeConfiguration(container_selector, c['command'], c['age'])

   popup = """
      +
@@ -109,6 +142,8 @@
       Remove tag

       Add object

       Remove object

+      Command value

+      Command age

   """
   f.children('.configurations_selection').html(popup)
@@ -128,6 +163,14 @@
         name = $(this).children('input[_name="name"]').val()
         age = $(this).children('input[_name="age"]').val()
         configurations.push({type: 'age', name: name, age: age})
+      when 'custom_parameter_value'
+        command = $(this).children('input[_name="command"]').val().trim()
+        value = $(this).children('input[_name="value"]').val().trim()
+        configurations.push({type: 'custom_parameter_value', command: command, value: value})
+      when 'custom_parameter_age'
+        command = $(this).children('input[_name="command"]').val()
+        age = $(this).children('input[_name="age"]').val()
+        configurations.push({type: 'custom_command_age', command: command, age: age})
       when 'add_tag'
         tag = $(this).children('input[_name="tag"]').val()
         configurations.push({type: 'add_tag', tag: tag})
@@ -142,5 +185,13 @@
         name = $(this).children('input[_name="name"]').val()
         object = $(this).children('input[_name="object"]').val()
         configurations.push({type: 'delete_object', name: name, object: object})
+      when 'custom_command_value'
+        command = $(this).children('input[_name="command"]').val().trim()
+        value = $(this).children('input[_name="value"]').val().trim()
+        configurations.push({type: 'custom_command_value', command: command, value: value})
+      when 'custom_command_age'
+        command = $(this).children('input[_name="command"]').val()
+        age = $(this).children('input[_name="age"]').val()
+        configurations.push({type: 'custom_command_age', command: command, age: age})
   )
   $("##{id} > input[name=configurations]").attr('value', JSON.stringify(configurations))


Reverted to openshift port

Reverted to openshift port

--- server/server.coffee
+++ server/server.coffee
@@ -70,6 +70,6 @@

 app.use renderOnServer

-port = 80 # (process.env.OPENSHIFT_NODEJS_PORT || 3000)
+port = (process.env.OPENSHIFT_NODEJS_PORT || 3000)
 app.listen port, () ->
   logger.info 'Example app listening on port ', port


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animated.coffee
+++ test/animated.coffee
@@ -417,7 +417,7 @@
     data: animationData
     includedModules: ["Animated"]

-  (animation.I.activeAnimation.frames.length).times ->
+  animation.I.activeAnimation.frames.length.times ->
     animation.update()

   equals animation.I.currentFrameIndex, 0, "Frame position should be 0 after reaching the end of an animation state"
@@ -428,7 +428,7 @@
     includedModules: ["Animated"]

   # Bite cannot be interrupted. Hack to get to idle state
-  (animation.I.activeAnimation.frames.length).times -> animation.update()
+  animation.I.activeAnimation.frames.length.times -> animation.update()

   equals animation.I.activeAnimation.name, "Idle1", "Animation should be in idle1 state after bite finishes"


toggle trip options. fixes #21

toggle trip options. fixes #21

--- app/assets/transit/lib/views/plan.coffee
+++ app/assets/transit/lib/views/plan.coffee
@@ -27,7 +27,7 @@
     @model.trigger 'fetch'

   display_trip_options: =>
-    @$('.trip-options').slideDown()
+    @$('.trip-options').slideToggle()

   change_trip_options: (event) =>
     event.preventDefault()


sending the uuid not nested now

sending the uuid not nested now

--- app/controllers/device-controller.coffee
+++ app/controllers/device-controller.coffee
@@ -14,8 +14,8 @@
     {device, pin} = request.body
     device ?= {}
     device.ipAddress ?= @ipAddress(request)
-    @pinController.createDevice pin, device, (error, uuid) =>
-      return response.status(500).send error: error.message if error?
-      response.status(201).send uuid: uuid
+    @pinController.createDevice pin, device, (error, response) =>
+      return response.status(500).send error.message if error?
+      response.status(201).send response

 module.exports = DeviceController


Plants - Fix regression.

Plants - Fix regression.

--- app/controllers/interfaces/plants.coffee
+++ app/controllers/interfaces/plants.coffee
@@ -1,4 +1,5 @@
 Archive = require 'models/Archive'
+Classification = require 'models/Classification'

 Interfaces = require 'controllers/interfaces'

@@ -12,6 +13,8 @@

   nextSubject: =>
     @archive.nextSubject (@currentSubject) =>
+      @classification = Classification.create({subject_id: @currentSubject.id, workflow_id: @currentSubject.workflow_ids[0]})
+
       callback = =>
         $(".photos img").animate({ marginLeft: "0" }, 500)
         @transcriber.spinner.hide()


Fix typo

Fix typo

--- scripts/prime-number.coffee
+++ scripts/prime-number.coffee
@@ -24,7 +24,7 @@
     i = Math.floor(Math.random() * primeNumbers.length)
     if i >= primeNumbers.length then i = primeNumbers - 1
     pn = primeNumbers[i]
-    m = "好きなの素数は" + pn + "です．修論ダメです"
+    m = "好きな素数は" + pn + "です．修論ダメです"

     msg.send m


Automatically open the first task if there is one

--- app/scripts/controllers/documents.coffee
+++ app/scripts/controllers/documents.coffee
@@ -75,6 +75,8 @@
           $scope.tasks = response.data
           $scope.files = ([] for i in [0..$scope.tasks.length])
           $scope.loading = false
+          if $scope.tasks and $scope.tasks.length > 0
+            $scope.expandTask $scope.tasks[0]
         (error) ->
           $scope.$parent.alert("An error occured while fetching the tasks.", "danger")
           $scope.loading = false


Support events on nest temp and humidity

--- lib/adapters/nest/NestThermostatNode.coffee
+++ lib/adapters/nest/NestThermostatNode.coffee
@@ -3,8 +3,12 @@

 module.exports = class NestThermostatNode extends NestNode
   aspects:
-    "temperature-sensor": {}
-    "humidity-sensor": {}
+    "temperature-sensor":
+      events:
+        changed: (prev, cur) -> prev.value != cur.value
+    "humidity-sensor":
+      events:
+        changed: (prev, cur) -> prev.value != cur.value
     "temperature-set-point":
       commands:
         "set-target": (node, temp) -> node.adapter.setTemperature(node.id, temp)


moved link check to afterClick

moved link check to afterClick

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -105,13 +105,13 @@

 handleClick = (event) ->
   unless event.defaultPrevented
-    link = extractLink event
-    if link.nodeName is 'A' and !ignoreClick(event, link)
-      document.removeEventListener 'click', handleAfterClick
-      document.addEventListener 'click', handleAfterClick
+    document.removeEventListener 'click', handleAfterClick
+    document.addEventListener 'click', handleAfterClick

 handleAfterClick = (event) ->
   unless event.defaultPrevented
+    link = extractLink event
+    if link.nodeName is 'A' and !ignoreClick(event, link)
       link = extractLink event
       visit link.href
       event.preventDefault()


updated twitter example

updated twitter example

--- examples/twitter/demo1.coffee
+++ examples/twitter/demo1.coffee
@@ -1,14 +1,14 @@
 #!/usr/bin/env coffee

 Hydrant = require '../../lib/hydrant'
-
+{inspect} = require 'util'
 hydrant = new Hydrant
   defaults:
     encoding: no # yaml, json, none
     compress: no # deflateRaw, deflate, gzip, or none

   twitter:
-    module:               'lib/input/twitter'
+    module:               '../../lib/input/twitter'

     consumer_key:         'CONSUMER_KEY'
     consumer_secret:      'CONSUMER_SECRET'
@@ -22,5 +22,7 @@
       "data.text.length < 40"   # if you are using json/yml, you can use plain text
       (-> Math.random() > 0.05) # or if you are in a JS/Coffee context, use some real code!
     ]
+hydrant.on 'input', (msg) ->
+  console.log " >> INPUT #{inspect msg}"

 hydrant.start()


Removing todo's

Removing todo's

--- src/extenders/convert.coffee
+++ src/extenders/convert.coffee
@@ -1,6 +1,4 @@
   ko.extenders.convert = (target, options) ->
-    # ToDo: .type becomes optional as the type restriction list, .TypeName options are used as overrides during the specific conversions. Need only to skip expanding .types and to fix the untyped conversion to check for overrides. *Might* refactor some common code
-    # ToDo: should we do the same for .type in the type restricted version for symmetry? Yes!
     if options == false
       return target


Support VALUE

Support VALUE

--- src/formula_evaluator.coffee
+++ src/formula_evaluator.coffee
@@ -1040,6 +1040,11 @@
     str = @expectString(args[0])
     str.toUpperCase()

+  VALUE: (args)->
+    @checkArgumentSize(args, 1)
+    @expectString(args[0])
+
+
   WEEKDAY: (args)->
     @checkArgumentSize(args, 1, 2)
     dt = @expectMoment(args[0])


trying to get CI to pass

trying to get CI to pass

--- test/javascripts/controllers/task_controller_test.js.coffee
+++ test/javascripts/controllers/task_controller_test.js.coffee
@@ -18,17 +18,23 @@
       @subject().set('model', @task)

+
 test '#isEditable: true when the task is not a metadata task', ->
-  equal @subject().get('isEditable'), true
+  Ember.run =>
+    @task.set('isMetadataTask', false)
+    equal @subject().get('isEditable'), true

 test '#isEditable: always true when the user is an admin', ->
-  ETahi.currentUser.user.admin = true
-  equal @subject().get('isEditable'), true
+  Ember.run =>
+    ETahi.currentUser.user.admin = true
+    @task.set('isMetadataTask', true)
+    @litePaper.set('submitted', true)
+    equal @subject().get('isEditable'), true

 test '#isEditable: true when paper is not submitted and task is a metadata task', ->
-  @litePaper.set('submitted', false)
-
-  equal @subject().get('isEditable'), true
+  Ember.run =>
+    @litePaper.set('submitted', false)
+    equal @subject().get('isEditable'), true

 test '#isEditable: false when the paper is submitted and the task is a metadata task', ->
   Ember.run =>


Fix stupid typo

Fix stupid typo

--- src/jquery.turbolinks.coffee
+++ src/jquery.turbolinks.coffee
@@ -34,7 +34,7 @@
   #     registering callbacks under a new event called `turbo:ready`.
   #
   register: ->
-    $(@onload) #[1]
+    $(@onLoad) #[1]
     $.fn.ready = @addCallback #[2]

 # Use with Turbolinks.


Run callback after adding to waintg list if $.isReady (closes #6)

--- src/jquery.turbolinks.coffee
+++ src/jquery.turbolinks.coffee
@@ -23,6 +23,7 @@
 # Store callbacks in list on `$` and `$.ready`
 $.fn.ready = (callback) ->
   callbacks.push(callback)
+  callback($) if $.isReady

 # Bind ready to passed event
 $.setReadyEvent = (event) ->


Fix: revision /0 not shown

Fix: revision /0 not shown

--- app/assets/javascripts/main.coffee
+++ app/assets/javascripts/main.coffee
@@ -13,8 +13,8 @@
   )

 xmleditor = ace.edit "xmleditor"
-xmleditor.setTheme  "ace/theme/monokai"
-xmleditor.getSession().setMode  "ace/mode/xml"
+xmleditor.setTheme "ace/theme/monokai"
+xmleditor.getSession().setMode "ace/mode/xml"
 xmleditor.getSession().setValue $("xml").val()
 xmleditor.getSession().on(
   'change'
@@ -26,11 +26,11 @@
         transform
         doneTypingInterval
       )
-  )
+)

 xsleditor = ace.edit "xsleditor"
-xsleditor.setTheme  "ace/theme/monokai"
-xsleditor.getSession().setMode  "ace/mode/xml"
+xsleditor.setTheme "ace/theme/monokai"
+xsleditor.getSession().setMode "ace/mode/xml"
 xsleditor.getSession().setValue $("xsl").val()
 xsleditor.getSession().on(
   'change'
@@ -45,8 +45,8 @@
 )

 resulteditor = ace.edit "resulteditor"
-resulteditor.setTheme  "ace/theme/monokai"
-resulteditor.getSession().setMode  "ace/mode/xml"
+resulteditor.setTheme "ace/theme/monokai"
+resulteditor.getSession().setMode "ace/mode/xml"

 $("#autotransform").click ->
   autotransform = !autotransform;
@@ -64,9 +64,12 @@
   jsRoutes.controllers.Application.save().ajax(
     data: $("#files").serialize()
     success: (data) ->
-     window.history.pushState("", "XSL Transform", "/"+data[0]+"/"+data[1]);
-     $("#id_slug").val(data[0]);
-     $("#save").find("span").html("Update");
+      if data[1] == 0
+        window.history.pushState("", "XSL Transform", "/" + data[0]);
+      else
+        window.history.pushState("", "XSL Transform", "/" + data[0] + "/" + data[1]);
+      $("#id_slug").val(data[0]);
+      $("#save").find("span").html("Update");
     error: (err) ->
       console.log err
       $("#alert").find("h4").html("Save oeps");
@@ -106,13 +109,13 @@
   if id != ""
     $("#save").find("span").html("Update");

-    jsRoutes.controllers.Application.xml(id,revision).ajax(
+    jsRoutes.controllers.Application.xml(id, revision).ajax(
       dataType: 'text'
       success: (data) ->
         xmleditor.getSession().setValue data
         $("#xml").val(data)
     );
-    jsRoutes.controllers.Application.xsl(id,revision).ajax(
+    jsRoutes.controllers.Application.xsl(id, revision).ajax(
       dataType: 'text'
       success: (data) ->
         xsleditor.getSession().setValue data
@@ -122,13 +125,12 @@
     reset()

-
   clip = new ZeroClipboard($("#copyclipboard"), { moviePath: "/assets/flash/ZeroClipboard.swf" })
   clip.glue($("#copyclipboard"));

 $("#copyclipboard").on(
   'mouseover'
   (event) ->
-    $("#copyclipboard").attr("data-clipboard-text",""+window.location);
+    $("#copyclipboard").attr("data-clipboard-text", "" + window.location);

 )


Arrays: Fix findIndex Chain

Arrays: Fix findIndex Chain

--- snippets/arrays.cson
+++ snippets/arrays.cson
@@ -76,7 +76,7 @@
   "findIndex chain":
     prefix: ".findIndex"
     body: """
-    .find(${1:(${2:item}) => {
+    .findIndex(${1:(${2:item}) => {
     \t${0}
     \\}});
     """


Remove leftover console.log

Remove leftover console.log

--- app/assets/javascripts/admin/views/home/index.js.coffee
+++ app/assets/javascripts/admin/views/home/index.js.coffee
@@ -9,7 +9,6 @@
     'click .integration-toggle': 'toggleIntegration'

   render: ->
-    console.log "rendering"
     @env = _(Augury.connections).findWhere(id: Augury.env.id)

     # Filter integrations from the collection that don't have any mappings


Implement the new color scheme format in the tab.

--- src/main/webapp/coffeescripts-hidden/load.coffee
+++ src/main/webapp/coffeescripts-hidden/load.coffee
@@ -145,7 +145,7 @@
   # Pull out the various descriptors into useful information.
   font = tabJson.font
   displayDelay = tabJson.delay * 1000
-  colorScheme = tabJson.colorScheme.toLowerCase()
+  colorScheme = tabJson.colorScheme
   customMessage = tabJson.customText

   # Load the Anchor Tab stylesheet.
@@ -170,11 +170,19 @@
         .attr('href', "http://anchortab.com")
         .attr('target', '_blank')

+  # Build the color scheme CSS. :/
+  colorSchemeStyle = "background: #{colorScheme.baseColor}; "
+  colorSchemeStyle += "background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #{colorScheme.baseColor}), color-stop(100%, #{colorScheme.secondaryColor}));"
+  colorSchemeStyle += "background: -webkit-linear-gradient(#{colorScheme.baseColor}, #{colorScheme.secondaryColor}); "
+  colorSchemeStyle += "background: -moz-linear-gradient(#{colorScheme.baseColor}, #{colorScheme.secondaryColor});"
+  colorSchemeStyle += "background: -o-linear-gradient(#{colorScheme.baseColor}, #{colorScheme.secondaryColor});"
+  colorSchemeStyle += "background: linear-gradient(#{colorScheme.baseColor}, #{colorScheme.secondaryColor});"
+
   # Create the tab and append to the end of the body.
   anchorTab =
     $("<div />")
       .attr("id", "anchor-tab")
-      .addClass(colorScheme)
+      .attr("style", colorSchemeStyle)
       .append(anchorTabStamp)
       .append(
         $("<p />")


Use elipsis for truncation

Use elipsis for truncation

--- extras/Studio.framer/app.coffee
+++ extras/Studio.framer/app.coffee
@@ -279,7 +279,7 @@
 		if @shareInfo.description.length > @options.maxDescriptionLength

 			truncated = @shareInfo.description.substring(@options.maxDescriptionLength,length).trim()
-			@options.shortDescription = truncated + "..."
+			@options.shortDescription = truncated + "…"

 			descriptionTruncatedSize = Utils.textSize(
 				parseDescription(@options.shortDescription),


OX-139 jump to active node keyboard shortcut

--- app/assets/javascripts/controller.coffee
+++ app/assets/javascripts/controller.coffee
@@ -192,6 +192,7 @@
           @setActiveNode(id, true)
           @sceneController.skeleton.setBranchPoint(false)
         )
+      "h" : @centerActiveNode

       #Zoom in/out
       "i" : =>
@@ -328,10 +329,13 @@
   setActiveNode : (nodeId, centered) =>
     @model.Route.setActiveNode(nodeId)
     if centered
-      @flycam.setGlobalPos(@model.Route.getActiveNodePos())
+      @centerActiveNode()
     @flycam.hasChanged = true
     @gui.update()
     @sceneController.skeleton.setActiveNode()
+
+  centerActiveNode : =>
+    @flycam.setGlobalPos(@model.Route.getActiveNodePos())

   deleteActiveNode : =>
     @model.Route.deleteActiveNode()


Shortened code that calculates percent change in properties since last visit.

--- app/javascripts/controllers.coffee
+++ app/javascripts/controllers.coffee
@@ -114,34 +114,23 @@
       # Get the session data.
       sessionCounter = []
       sheetData = []
-      for sess, index in subject.sessions
-        sessionCounter.push index
+      delta_k_trans = []
+      for sess, i in subject.sessions
+        sessionCounter.push i
         # Calculate delta-Ktrans
-        delta_k_trans = sess.modeling.fxr_k_trans - sess.modeling.fxl_k_trans
+        delta_k_trans[i] = sess.modeling.fxr_k_trans - sess.modeling.fxl_k_trans
         # Unless this is the first visit,
-        # calculate percent change in Ktrans, FXL, FXR, V_e, and tau_i since last visit,
-        # otherwise set values to null.
-        if index == 0
-          delta_k_trans_change = null
-          fxl_change = null
-          fxr_change = null
-          v_e_change = null
-          tau_i_change = null
-        else
-          delta_k_trans_change = ((delta_k_trans - prev_delta_k_trans)/prev_delta_k_trans * 100).toFixed(dpPct)
-          fxl_change = ((sess.modeling.fxl_k_trans - prev_fxl_k_trans)/prev_fxl_k_trans * 100).toFixed(dpPct)
-          fxr_change = ((sess.modeling.fxr_k_trans - prev_fxr_k_trans)/prev_fxr_k_trans * 100).toFixed(dpPct)
-          v_e_change = ((sess.modeling.v_e - prev_v_e)/prev_v_e * 100).toFixed(dpPct)
-          tau_i_change = ((sess.modeling.tau_i - prev_tau_i)/prev_tau_i * 100).toFixed(dpPct)
-        prev_delta_k_trans = delta_k_trans
-        prev_fxl_k_trans = sess.modeling.fxl_k_trans
-        prev_fxr_k_trans = sess.modeling.fxr_k_trans
-        prev_v_e = sess.modeling.v_e
-        prev_tau_i = sess.modeling.tau_i
+        # calculate percent change in each property since previous visit.
+        unless i == 0
+          delta_k_trans_change = ((delta_k_trans[i] - sheetData[i-1].deltaKtrans)/sheetData[i-1].deltaKtrans * 100).toFixed(dpPct)
+          fxl_change = ((sess.modeling.fxl_k_trans - sheetData[i-1].fxl)/sheetData[i-1].fxl * 100).toFixed(dpPct)
+          fxr_change = ((sess.modeling.fxr_k_trans - sheetData[i-1].fxr)/sheetData[i-1].fxr * 100).toFixed(dpPct)
+          v_e_change = ((sess.modeling.v_e - sheetData[i-1].ve)/sheetData[i-1].ve * 100).toFixed(dpPct)
+          tau_i_change = ((sess.modeling.tau_i - sheetData[i-1].taui)/sheetData[i-1].taui * 100).toFixed(dpPct)
         # Update the parameters for this session.
-        sheetData[index] =
+        sheetData[i] =
           visitDate: Helpers.dateFormat(sess.acquisition_date)
-          deltaKtrans: delta_k_trans.toFixed(dpVal)
+          deltaKtrans: delta_k_trans[i].toFixed(dpVal)
           deltaKtransChange: delta_k_trans_change
           fxl: sess.modeling.fxl_k_trans.toFixed(dpVal)
           fxlChange: fxl_change


Remove <br>

Remove <br>

--- app/js/controllers/favorite.coffee
+++ app/js/controllers/favorite.coffee
@@ -13,14 +13,14 @@

     $scope.isFavorite = (account)->
       account.private_data && account.private_data.gui_data.favorite
-
+
     $scope.toggleFavorite = (name) ->
         $modal.open
             templateUrl: "dialog-confirmation.html"
             controller: "DialogConfirmationController"
             resolve:
                 title: -> "Are you sure?"
-                message: -> "This will remove <b>" + name + "</b> from favorites"
+                message: -> "This will remove " + name + " from favorites"
                 action: -> -> yesToggleFavorite(name)

     yesToggleFavorite = (name)->


Removed apparently unnecessary preventDefault

--- app/js/initializers/create_button.coffee
+++ app/js/initializers/create_button.coffee
@@ -1,6 +1,5 @@
 Factlink.createButton = new Factlink.CreateButton
   mousedown: (e) -> e.preventDefault() # To prevent de-selecting text
   click: (e) ->
-    e.preventDefault()
     Factlink.createButton.startLoading()
     Factlink.createFactFromSelection()


Update assertion to allow for dynamic error names.

--- spec/compiler.coffee
+++ spec/compiler.coffee
@@ -24,7 +24,7 @@
       try
         exercise()
       catch error
-        expect(error.name).to.equal name
+        expect(error.name).to.contain name

 describe 'GSS compiler', ->


splat basics

splat basics


removed uneeded intrinsic tests

removed uneeded intrinsic tests


Tests: Remove console.log

Tests: Remove console.log

--- spec/governor.coffee
+++ spec/governor.coffee
@@ -108,7 +108,6 @@
         gov.once 'error', (err) ->
           chai.expect(err).to.exist
           chai.expect(err.message).to.contain cfg.wrongqueue.queue
-          console.log 'on err', err
           done()
         gov.once 'state', (state) ->
           newState = state


Add PairedSecureScreen#getByNameFromStore to get a paired secure screen with its name

--- app/src/m2fa/paired_secure_screen.coffee
+++ app/src/m2fa/paired_secure_screen.coffee
@@ -67,3 +67,12 @@

   @getMostRecentFromSyncedStore: (callback = _.noop) -> @getMostRecentFromStore(ledger.storage.sync, callback)

+  @getByNameFromStore: (store, name, callback = _.noop) ->
+    closure = new CompletionClosure(callback)
+    @getAllFromStore store, (result, error) ->
+      return closure.failure(error) if error?
+      closure.success(_(result).where(name: name)[0])
+    closure.readonly()
+
+  @getByNameFromSyncedStore: (name, callback = _.noop) -> @getByNameFromStore(ledger.storage.sync, name, callback)
+


Teamwork: Fixed calling setVmRoot before teamwork is ready.

--- client/Teamwork/Views/teamworkapp.coffee
+++ client/Teamwork/Views/teamworkapp.coffee
@@ -179,7 +179,8 @@
         @teamwork.destroy()
         @createTeamwork @mergePlaygroundOptions manifest, playground
         @teamwork.container.setClass playground
-        @setVMRoot root
+        @teamwork.once "WorkspaceSyncedWithRemote", =>
+          @setVMRoot root

   setUpImport: (manifest, playground) ->
     {version} = manifest


Stepped okSubmits date

Stepped okSubmits date

--- server/api/dashboard.coffee
+++ server/api/dashboard.coffee
@@ -9,7 +9,8 @@

 import awaitAll from '../../client/lib/awaitAll'

-export START_SUBMITS_DATE = new Date(2020, 0, 1)
+# note that months start from 0
+export START_SUBMITS_DATE = new Date(2020, 2, 20)

 expandResult = (result) ->
     res = result.toObject()


VideoLinkShell: better controls toggle

VideoLinkShell: better controls toggle

--- coffee/src/shells/videolink.shell.coffee
+++ coffee/src/shells/videolink.shell.coffee
@@ -112,6 +112,8 @@

     @listenTo @playerView, 'all', _.bind(@trigger, @)

+    @on 'Media:StateChange', @togglePlayPauseControls
+
     @initializeMediaEvents @options

@@ -120,22 +122,17 @@
     super
     @$el.empty()
     @$el.append @playerView.render().el
-    @controlsView.$('.control-view.pause').addClass 'hidden'
+    @togglePlayPauseControls()
     @

-  onMediaPlay: =>
-    @controlsView.$('.control-view.play').addClass 'hidden'
-    @controlsView.$('.control-view.pause').removeClass 'hidden'
-
-
-  onMediaPause: =>
-    @controlsView.$('.control-view.play').removeClass 'hidden'
-    @controlsView.$('.control-view.pause').addClass 'hidden'
-
-  onMediaEnd: =>
-    @controlsView.$('.control-view.play').removeClass 'hidden'
-    @controlsView.$('.control-view.pause').addClass 'hidden'
+  togglePlayPauseControls: =>
+    if @isPlaying()
+      @controlsView.$('.control-view.play').addClass 'hidden'
+      @controlsView.$('.control-view.pause').removeClass 'hidden'
+    else
+      @controlsView.$('.control-view.play').removeClass 'hidden'
+      @controlsView.$('.control-view.pause').addClass 'hidden'

   # forward state transitions


Much better naming

Much better naming

--- client/Framework/components/buttons/KDButtonView.coffee
+++ client/Framework/components/buttons/KDButtonView.coffee
@@ -21,7 +21,7 @@
     @setCallback options.callback
     @setTitle options.title
     @setIconClass options.iconClass if options.iconClass
-    @unhideIcon()                   if options.icon
+    @showIcon()                     if options.icon
     @setIconOnly options.iconOnly   if options.iconOnly
     @disable()                      if options.disabled

@@ -47,7 +47,7 @@

   getCallback:()-> @buttonCallback

-  unhideIcon:()->
+  showIcon:()->
     @setClass "with-icon"
     @$('span.icon').removeClass 'hidden'


fix typo

fix typo

--- app/pages/project/stats/index.cjsx
+++ app/pages/project/stats/index.cjsx
@@ -71,7 +71,7 @@
   render: ->

-        Project statistics are currently unavalible and we are working to fix the issue.
+        Project statistics are currently unavailable and we are working to fix the issue.


fix candidatures expried

fix candidatures expried

--- app/scripts/candidature/app.coffee
+++ app/scripts/candidature/app.coffee
@@ -5,13 +5,13 @@
             'ui.router',
 ])

-.run(['$rootScope' ,'$state', ($rootScope, $state) ->
+.run(['$rootScope', '$state', ($rootScope, $state) ->
   $rootScope.$on('tokenHasExpired', () ->
     console.log('Your session has expired!')
     if( $rootScope.logout == Function)
       $rootScope.logout()

-    if($state.$urlRouter!=undefined && $state.$urlRouter.location.indexOf("candidature/"))
+    if($state.$urlRouter!=undefined && $state.$urlRouter.location.indexOf("candidature/")!=-1)
       setTimeout(() ->
         $state.go('candidature.account.login')
       , 200)


Remove sinon and chai require

Remove sinon and chai require

Not needed since karma has them as plugins.  Sinon causes webpack errors
when required twice.

--- test/components/helpers/component-testing.coffee
+++ test/components/helpers/component-testing.coffee
@@ -1,6 +1,4 @@
 _ = require 'underscore'
-chai  = require 'chai'
-sinon = require 'sinon'
 expect = chai.expect
 React = require 'react'
 ReactAddons    = require('react/addons')


format copy output depending on datatype

--- lib/copy-providers/values-copy-provider.coffee
+++ lib/copy-providers/values-copy-provider.coffee
@@ -21,7 +21,7 @@
                 if row.x == parseInt(col)
                     if not rows[row.y]?
                         rows[row.y] = []
-                    rows[row.y].push(["'", row.value, "'"].join(''))
+                    rows[row.y].push(@formatCell(columns[col].type, row.value))
         for col in Object.keys(rows)
             arr.push(rows[col])
         z = arr.join("""),\n           (""")
@@ -30,8 +30,15 @@
 FROM (
     VALUES (#{z})
 ) X (#{y})"""
-        console.log 'result', result
         return result
-
+

     getName: () -> 'Values'
+
+    formatCell: (columnType, cellValue) ->
+        if cellValue == null
+            return 'NULL'
+        if columnType not in ['integer', 'bigint', 'numeric', 'real']
+            return "'" + cellValue + "'"
+        else
+            return cellValue


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -74,7 +74,7 @@
   Math.round(this)

 Number::circularPoints = (n, block) ->
-  n.times
+  n.times (i)

 ###*
 Returns a number whose value is limited to the given range.


fix spec

fix spec

--- spec/operator-general-spec.coffee
+++ spec/operator-general-spec.coffee
@@ -163,17 +163,15 @@
           cursor: [0, 2]

     describe "undo behavior", ->
-      originalText = null
-
-      beforeEach ->
-        set
-          textC: """
+      [originalText, initialTextC] = []
+      beforeEach ->
+        initialTextC = """
           12345
           a|bcde
           ABCDE
           QWERT
           """
-
+        set textC: initialTextC
         originalText = editor.getText()

       it "undoes both lines", ->
@@ -183,12 +181,7 @@
           |QWERT
           """
         ensure 'u',
-          textC: """
-          12345
-          |abcde
-          ABCDE
-          QWERT
-          """
+          textC: initialTextC
           selectedText: ""

       describe "with multiple cursors", ->
@@ -257,14 +250,16 @@
               selectedText: ''

         describe "setCursorToStartOfChangeOnUndoRedo is false", ->
-          initialTextC = """
-            |12345
-            a|bcde
-            ABCDE
-            QWERT
-            """
+          initialTextC = null

           beforeEach ->
+            initialTextC = """
+              |12345
+              a|bcde
+              ABCDE
+              QWERT
+              """
+
             settings.set('setCursorToStartOfChangeOnUndoRedo', false)
             set textC: initialTextC
             ensure 'd l',


Ignore requests to other hosts.

Ignore requests to other hosts.

--- atom/browser/lib/chrome-extension.coffee
+++ atom/browser/lib/chrome-extension.coffee
@@ -8,7 +8,7 @@
 hostPathMapNextKey = 0

 getHostForPath = (path) ->
-  key = "extension-#{hostPathMapNextKey}"
+  key = "extension-#{++hostPathMapNextKey}"
   hostPathMap[key] = path
   key

@@ -22,6 +22,8 @@
   protocol.registerProtocol 'chrome-extension', (request) ->
     parsed = url.parse request.url
     return unless parsed.hostname and parsed.path?
+
+    return unless /extension-\d+/.test parsed.hostname

     directory = getPathForHost parsed.hostname
     return new protocol.RequestFileJob(path.join(directory, parsed.path))


Remove pulsar hunters slug

Remove pulsar hunters slug

--- app/classifier/index.cjsx
+++ app/classifier/index.cjsx
@@ -17,8 +17,6 @@
 WorldWideTelescope = require './world_wide_telescope'
 MiniCourseButton = require './mini-course-button'
 GridTool = require './drawing-tools/grid'
-
-PULSAR_HUNTERS_SLUG = 'zooniverse/pulsar-hunters'

 Classifier = React.createClass
   displayName: 'Classifier'


Improved error handling and encapsulated in separate method

--- app/client/helpers.coffee
+++ app/client/helpers.coffee
@@ -1,26 +1,45 @@
-# app/client/helpers.coffee
+# app/client/helpers.coffee#

+# methods
+
+# helper method for failing gracefully when required value is null
+failIfNull = (value=null, msg) ->
+  # if given value is null, route to home screen and throw error
+  unless value?
+    Meteor.Router.to '/'
+    throw new Error msg
+  # else, return the value
+  else
+    value
+
+
+# helpers
+
+# show popup dialog with text and options
 @notify = ({title, content, cancel, confirm}) ->
+  # set text
   $('#popup-title').text title
   $('#popup-content').text content
-  unless cancel
-    $('#popup-cancel').hide()
-  else
-    $('#popup-cancel').text cancel
   $('#popup-confirm').text confirm
+
+  # hide cancel button if not set
+  if cancel then $('#popup-cancel').text cancel else $('#popup-cancel').hide()
+
+  # show dialog
   $('#popup').modal()

-@goHome = ->
-  Meteor.Router.to '/'
-  location.reload()
+@currentPlayerId = ->
+  localStorage.getItem 'playerId'
+
+@currentPlayer = ->
+  Meteor.users.findOne currentPlayerId()

 @currentGameId = ->
-  id = Session.get 'gameId'
-  unless id then goHome() else id
+  failIfNull Session.get('gameId'), 'Session gameId not set'

 @currentGame = ->
-  game = Games.findOne currentGameId()
-  unless game then goHome() else game
+  failIfNull Games.findOne(currentGameId()),
+    "Current game not found (id: #{currentGameId()})"

 @currentGameFinished = ->
   outOfQuestions = currentGame().currentQuestion >= numberOfQuestions()
@@ -30,27 +49,28 @@
   Session.get 'challengeId'

 @currentChallenge = ->
-  Challenges.findOne currentChallengeId()
+  failIfNull Challenges.findOne(currentChallengeId()),
+    "Current challenge not found (id: #{currentChallengeId()})"
+
+@currentGameIsChallenge = ->
+  return currentChallengeId() or
+    Challenges.findOne { challengerGameId: currentGameId() } or
+    Challenges.findOne { challengeeGameId: currentGameId() }

 @currentHighscore = ->
-  highscore = Highscores.findOne { gameId: currentGameId() }
-  unless highscore then goHome() else highscore
+  failIfNull Highscores.findOne({ gameId: currentGameId() }),
+    'Current game has no highscore'

 @currentQuestionId = ->
   idx = currentGame().currentQuestion
   currentGame().questionIds[idx]

 @currentQuestion = ->
-  Questions.findOne currentQuestionId()
+  failIfNull Questions.findOne(currentQuestionId()),
+    "Current question not found (id: #{currentQuestionId()})"

 @numberOfQuestions = ->
   currentGame().questionIds.length

 @currentAsset = ->
   $(".asset##{currentQuestion().soundId}")[0]
-
-@currentPlayerId = ->
-  localStorage.getItem 'playerId'
-
-@currentPlayer = ->
-  Meteor.users.findOne currentPlayerId()


Update zh-HANS.coffee (#5492)

Update zh-HANS.coffee (#5492)

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -1612,7 +1612,7 @@
     link_google_classroom: "链接谷歌教室"
     select_your_classroom: "选择你的教室"
     no_classrooms_found: "没有找到教室"
-    create_classroom_manually: "手动创建教室"
+    create_classroom_manually: "创建教室"
     classes: "班级"
     certificate_btn_print: "打印"
     certificate_btn_toggle: "中英切换"
@@ -1964,8 +1964,8 @@
     add_teacher_button: "添加老师"
 #    subheader: "You can make your licenses available to other teachers in your organization. Each license can only be used for one student at a time."
     teacher_not_found: "没有找到教室。请确保教室已经创建了一个教师账户。"
-    teacher_not_valid: "这不是一个有效的教师账户，室友教师账户可以分享许可证。"
-    already_shared: "你已经把这些许可证分享给你教师了。"
+    teacher_not_valid: "该教师账户无效，只有教师账户可以分享许可证。"
+    already_shared: "成功分享许可证给教师。"
 #    teachers_using_these: "Teachers who can access these licenses:"
 #    footer: "When teachers revoke licenses from students, the licenses will be returned to the shared pool for other teachers in this group to use."
     you: "（您）"
@@ -2412,10 +2412,10 @@
     advanced_css_selectors: "高级CSS选择器"
     advanced_html_attributes: "高级HTML属性"
     advanced_html_tags: "高级HTML标签"
-    algorithm_average: "求平均值算法"
-    algorithm_find_minmax: "求最大最小值算法"
-    algorithm_search_binary: "二进制寻找算法"
-    algorithm_search_graph: "寻找图算法"
+    algorithm_average: "均值算法"
+    algorithm_find_minmax: "最值算法"
+    algorithm_search_binary: "二分查找算法"
+    algorithm_search_graph: "图搜索算法"
     algorithm_sort: "排序算法"
     algorithm_sum: "求和算法"
     arguments: "参数"
@@ -2427,13 +2427,13 @@
     array_searching: "数组遍历"
     array_sorting: "数组排序"
     arrays: "数组"
-    basic_css_rules: "基本的CSS规则"
-    basic_css_selectors: "基本CSS选择器"
-    basic_html_attributes: "基本HTML属性"
-    basic_html_tags: "基本HTML标签"
+    basic_css_rules: "基础CSS规则"
+    basic_css_selectors: "基础CSS选择器"
+    basic_html_attributes: "基础HTML属性"
+    basic_html_tags: "基础HTML标签"
     basic_syntax: "基本语法"
     binary: "二进制"
-    boolean_and: "布尔值和"
+    boolean_and: "布尔值与"
     boolean_inequality: "布尔值不等于"
     boolean_equality: "布尔值等于"
     boolean_greater_less: "Boolean Greater/Less"
@@ -2544,7 +2544,7 @@
     student_name_placeholder: "输入你的名字"
     teachers_section: "老师:"
     students_section: "学生:"
-    teacher_notified: "我们已经把你想要在课堂上玩更多的CodeCombat游戏，通知到你的老师。"
+    teacher_notified: "已经通知给你的老师，你想要在课堂上玩更多CodeCombat游戏。"

   delta:
     added: "被添加"
@@ -2612,8 +2612,8 @@
     canonical: "这篇说明的英文版本是权威版本。如果各个翻译版本之间有任何冲突，请以英文版为准。"
     third_party_title: "第三方服务"
     third_party_description: "CodeCombat使用了下列第三方服务（除了别的以外）："
-    cookies_message: "CodeCombat使用一些必要的和非必要的cookies."
-    cookies_deny: "减少不必要的cookies"
+    cookies_message: "CodeCombat使用了必要和非必要的cookies."
+    cookies_deny: "禁用非必要的cookies"

   ladder_prizes:
     title: "竞标赛奖项" # This section was for an old tournament and doesn't need new translations now.


Improve spec now ensure cursor position and which is last cursor


:green_heart: Fix broken test due to css changes

--- spec/table-view-spec.coffee
+++ spec/table-view-spec.coffee
@@ -525,7 +525,7 @@
     it 'scrolls the view until the passed-on row become visible', ->
       tableView.makeRowVisible(50)

-      expect(tableView.body.scrollTop()).toEqual(847)
+      expect(tableView.body.scrollTop()).toEqual(849)

   afterEach ->
     window.requestAnimationFrame = requestAnimationFrameSafe


removed spec directory.  was not correclty moved in pull request

--- spec/unit/merge.spec.coffee
+++ spec/unit/merge.spec.coffee
@@ -1,89 +0,0 @@
-should = require 'should'
-merge = require '../../lib/merge'
-
-describe 'merge', ->
-
-	it 'should add keys in target that do not exist at the root', ->
-		src =
-			key1: 'value1'
-			key2: 'value2'
-		target = {}
-
-
-		merge target, src
-
-		target.should.eql target
-
-	it 'should merge existing simple keys in target at the roots', ->
-		src =
-			key1: 'changed'
-			key2: 'value2'
-		target =
-			key1: 'value1'
-			key3: 'value3'
-
-		expected =
-			key1: 'changed'
-			key2: 'value2'
-			key3: 'value3'
-
-		merge target, src
-
-		target.should.eql expected
-
-	it 'should merge nested objects into target', ->
-		src =
-			key1:
-				subkey1: 'changed'
-				subkey3: 'added'
-		target =
-			key1:
-				subkey1: 'value1'
-				subkey2: 'value2'
-
-		expected =
-			key1:
-				subkey1: 'changed'
-				subkey2: 'value2'
-				subkey3: 'added'
-
-		merge target, src
-
-		target.should.eql expected
-
-	it 'should replace simple key with nested object in target', ->
-		src =
-			key1:
-				subkey1: 'subvalue1'
-				subkey2: 'subvalue2'
-		target =
-			key1: 'value1'
-			key2: 'value2'
-
-		expected =
-			key1:
-				subkey1: 'subvalue1'
-				subkey2: 'subvalue2'
-			key2: 'value2'
-
-		merge target, src
-
-		target.should.eql expected
-
-	it 'should replace object with simple key in target', ->
-		src =
-			key1: 'value1'
-		target =
-			key1:
-				subkey1: 'subvalue1'
-				subkey2: 'subvalue2'
-			key2: 'value2'
-
-		expected =
-			key1: 'value1'
-			key2: 'value2'
-
-		merge target, src
-
-		target.should.eql expected
-


double space outta my face

double space outta my face

--- spec/whitespace-spec.coffee
+++ spec/whitespace-spec.coffee
@@ -108,7 +108,6 @@
       editor.getBuffer().save()
       expect(editor.getText()).toBe "foo  \nline break!\n"

-
     it "trims GFM text with a more than two spaces", ->
       editor.activeEditSession.setGrammar(grammar)
       editor.insertText "foo   \nline break!"


Use Project::openSync in specs

Use Project::openSync in specs

--- spec/whitespace-spec.coffee
+++ spec/whitespace-spec.coffee
@@ -11,7 +11,7 @@
     filePath = path.join(directory, 'atom-whitespace.txt')
     fs.writeSync(filePath, '')
     fs.writeSync(path.join(directory, 'sample.txt'), 'Some text.\n')
-    editor = project.open(filePath)
+    editor = project.openSync(filePath)
     buffer = editor.getBuffer()

     atom.activatePackage('whitespace')
@@ -30,7 +30,7 @@
     expect(editor.getText()).toBe "foo\nbar\n\nbaz"

     # works for buffers that are opened after extension is initialized
-    editor = project.open('sample.txt')
+    editor = project.openSync('sample.txt')
     editor.moveCursorToEndOfLine()
     editor.insertText("           ")


Make tests run with promise and non-promise package deactivate

--- spec/whitespace-spec.coffee
+++ spec/whitespace-spec.coffee
@@ -30,8 +30,10 @@
       {whitespace} = atom.packages.getActivePackage('whitespace').mainModule
       expect(whitespace.subscriptions.disposables.size).toBe 2

-      atom.packages.deactivatePackage('whitespace')
-      expect(whitespace.subscriptions.disposables).toBeNull()
+      waitsForPromise ->
+        Promise.resolve(atom.packages.deactivatePackage('whitespace'))
+      runs ->
+        expect(whitespace.subscriptions.disposables).toBeNull()

   describe "when 'whitespace.removeTrailingWhitespace' is true", ->
     beforeEach ->
@@ -318,11 +320,14 @@
   describe "when deactivated", ->
     it "does not remove trailing whitespace from editors opened after deactivation", ->
       atom.config.set("whitespace.removeTrailingWhitespace", true)
-      atom.packages.deactivatePackage('whitespace')
-
-      editor.setText("foo \n")
-      editor.save()
-      expect(editor.getText()).toBe "foo \n"
+
+      waitsForPromise ->
+        Promise.resolve(atom.packages.deactivatePackage('whitespace'))
+
+      runs ->
+        editor.setText("foo \n")
+        editor.save()
+        expect(editor.getText()).toBe "foo \n"

       waitsForPromise ->
         atom.workspace.open('sample2.txt')
@@ -342,8 +347,10 @@
       expect(buffer.getText()).toBe "foo\nbar\n\nbaz"

     it "does not attempt to remove whitespace when the package is deactivated", ->
-      atom.packages.deactivatePackage 'whitespace'
-      expect(buffer.getText()).toBe "foo   \nbar\t   \n\nbaz"
+      waitsForPromise ->
+        Promise.resolve(atom.packages.deactivatePackage 'whitespace')
+      runs ->
+        expect(buffer.getText()).toBe "foo   \nbar\t   \n\nbaz"

   describe "when the 'whitespace:save-with-trailing-whitespace' command is run", ->
     beforeEach ->


fix zoom bug

fix zoom bug

--- bokehjs/src/coffee/tool/zoom_tool.coffee
+++ bokehjs/src/coffee/tool/zoom_tool.coffee
@@ -14,9 +14,8 @@
       super(options)

     eventGeneratorClass: OnePointWheelEventGenerator
-    evgen_options: {buttonText:"Zoom"}
-    tool_events: {
-      zoom: "_zoom"}
+    evgen_options: { buttonText:"Zoom" }
+    tool_events: { zoom: "_zoom" }

     mouse_coords: (e, x, y) ->
       [x_, y_] = [@plot_view.view_state.device_to_sx(x), @plot_view.view_state.device_to_sy(y)]
@@ -31,7 +30,13 @@

       [x, y]  = @mouse_coords(e, screenX, screenY)
       speed   = @mget('speed')
-      factor  = speed * (delta) # * 50)  # TODO
+      factor  = speed * delta
+
+      # clamp the  magnitude of factor, if it is > 1 bad things happen
+      if factor > 0.9
+        factor = 0.9
+      else if factor < -0.9
+        factor = -0.9

       xr = @plot_view.view_state.get('inner_range_horizontal')
       sx_low  = xr.get('start')
@@ -41,10 +46,12 @@
       sy_low  = yr.get('start')
       sy_high = yr.get('end')

-      xstart = @plot_view.xmapper.map_from_target(sx_low  - (sx_low  - x)*factor)
-      xend   = @plot_view.xmapper.map_from_target(sx_high - (sx_high - x)*factor)
-      ystart = @plot_view.ymapper.map_from_target(sy_low  - (sy_low  - y)*factor)
-      yend   = @plot_view.ymapper.map_from_target(sy_high - (sy_high - y)*factor)
+      [xstart, xend] = @plot_view.xmapper.v_map_from_target([
+        sx_low  - (sx_low  - x)*factor, sx_high - (sx_high - x)*factor)
+      ])
+      [ystart, yend] = @plot_view.ymapper.v_map_from_target([
+        sy_low  - (sy_low  - y)*factor), sy_high - (sy_high - y)*factor)
+      ])

       zoom_info = {
         xr: {start: xstart, end: xend}


Add .md extension to generated license

Add .md extension to generated license

--- build/tasks/generate-license-task.coffee
+++ build/tasks/generate-license-task.coffee
@@ -17,7 +17,7 @@

       licenseText = getLicenseText(dependencyLicenses)
       if mode is 'save'
-        targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE')
+        targetPath = path.join(grunt.config.get('atom.appDir'), 'LICENSE.md')
         fs.writeFileSync(targetPath, licenseText)
       else
         console.log licenseText


Fix notifier service uncaught

Fix notifier service uncaught

--- assets/js/services/notifier.coffee
+++ assets/js/services/notifier.coffee
@@ -75,8 +75,8 @@
               $rootScope.$apply(options.deny)
           ]

-      options.title = he.encode(title)
-      options.text = he.encode(text)
+      options.title = he.encode(options.title) if options.title
+      options.text = he.encode(options.text) if options.text

       noty(options)


fix combined fleet export, import for Rui code

--- views/importTab.cjsx
+++ views/importTab.cjsx
@@ -174,12 +174,14 @@
         fleets = []
         for fleet, index in importCode
           continue if fleet.length is 0
+          _fleet = []
           for ship in fleet
-            continue if ship.length is 0
+            continue if !ship[0]? or ship.length is 0
             ship[0] = parseInt ship[0]
             if ship.length is 4
               ship.push []
-          fleets[index] = fleet
+            _fleet.push ship
+          fleets[index] = _fleet
       flag = false
       for fleet in fleets
         break if fleet.lenth is 0
@@ -233,6 +235,8 @@
     code = @props.henseiData[title].ships
     if !code[0][0][0]?
       code = '[' + JSON.stringify(code) + ']'
+    else
+      code = JSON.stringify(code)
     @setState
       code: code
   handleFileImportClick: ->


Improve scoping of tags in Csound document files

--- grammars/csound-document.cson
+++ grammars/csound-document.cson
@@ -9,24 +9,23 @@
     end:   "(</)(CsoundSynthesi[sz]er)(>)"
     beginCaptures:
       1: name: "punctuation.definition.tag.begin.csound-document"
-      2: name: "entity.name.tag.begin.csound-document"
-      3: name: "punctuation.definition.tag.begin.csound-document"
+      2: name: "entity.name.tag.csound-document"
+      3: name: "punctuation.definition.tag.end.csound-document"
     endCaptures:
-      1: name: "punctuation.definition.tag.end.csound-document"
-      2: name: "entity.name.tag.end.csound-document"
+      1: name: "punctuation.definition.tag.begin.csound-document"
+      2: name: "entity.name.tag.csound-document"
       3: name: "punctuation.definition.tag.end.csound-document"
     patterns: [
       {
-        name:  "meta.orchestra.csound-document"
         begin: "(<)(CsOptions)(>)"
         end:   "(</)(CsOptions)(>)"
         beginCaptures:
           1: name: "punctuation.definition.tag.begin.csound-document"
-          2: name: "entity.name.tag.begin.csound-document"
-          3: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
+          3: name: "punctuation.definition.tag.end.csound-document"
         endCaptures:
-          1: name: "punctuation.definition.tag.end.csound-document"
-          2: name: "entity.name.tag.end.csound-document"
+          1: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
           3: name: "punctuation.definition.tag.end.csound-document"
         patterns: [include: "source.csound#comments"]
       },{
@@ -35,11 +34,11 @@
         end:   "(</)(CsInstruments)(>)"
         beginCaptures:
           1: name: "punctuation.definition.tag.begin.csound-document"
-          2: name: "entity.name.tag.begin.csound-document"
-          3: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
+          3: name: "punctuation.definition.tag.end.csound-document"
         endCaptures:
-          1: name: "punctuation.definition.tag.end.csound-document"
-          2: name: "entity.name.tag.end.csound-document"
+          1: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
           3: name: "punctuation.definition.tag.end.csound-document"
         contentName: "source.csound.embedded.csound-document"
         patterns: [include: "source.csound"]
@@ -49,18 +48,18 @@
         end:   "(</)(CsScore)(>)"
         beginCaptures:
           1: name: "punctuation.definition.tag.begin.csound-document"
-          2: name: "entity.name.tag.begin.csound-document"
-          3: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
+          3: name: "punctuation.definition.tag.end.csound-document"
         endCaptures:
-          1: name: "punctuation.definition.tag.end.csound-document"
-          2: name: "entity.name.tag.end.csound-document"
+          1: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
           3: name: "punctuation.definition.tag.end.csound-document"
         contentName: "source.csound-score.embedded.csound-document"
         patterns: [include: "source.csound-score"]
       },{
         name:  "meta.html.csound-document"
-        begin: "(?=<[hH][tT][mM][lL])"
-        end:   "(?<=</[hH][tT][mM][lL]>)"
+        begin: "(?i)(?=<html)"
+        end:   "(?i)(?<=</html>)"
         patterns: [include: "text.html.basic"]
       }
       {include: "#tags"}
@@ -73,15 +72,13 @@
   tags:
     patterns: [
       {
-        begin: "(<)([0-9A-Za-z:-]+)(>)"
-        end:   "(</)([0-9A-Za-z:-]+)(>)"
+        begin: "(</?)([\\w:-]+)"
+        end:   ">"
         beginCaptures:
           1: name: "punctuation.definition.tag.begin.csound-document"
-          2: name: "entity.name.tag.begin.csound-document"
-          3: name: "punctuation.definition.tag.begin.csound-document"
+          2: name: "entity.name.tag.csound-document"
         endCaptures:
-          1: name: "punctuation.definition.tag.end.csound-document"
-          2: name: "entity.name.tag.end.csound-document"
-          3: name: "punctuation.definition.tag.end.csound-document"
+          0: name: "punctuation.definition.tag.end.csound-document"
+        patterns: [include: "text.xml#tagStuff"]
       }
     ]


missing require

missing require

--- src/player.coffee
+++ src/player.coffee
@@ -4,6 +4,7 @@

 getMinBet = require './getMinBet'
 analyzeHand = require './analyzeHand'
+valueHand = require './valueHand'

 module.exports =
   version: ->
@@ -27,7 +28,7 @@
     if value > 0
       return next null, minBet * 10

-    if seriousness > value * 2
+    if seriousness > value * 5
       return next null, 0

     next null, minBet


DRY specs.

DRY specs.

--- spec/javascripts/application/seeds_store_spec.js.coffee
+++ spec/javascripts/application/seeds_store_spec.js.coffee
@@ -44,6 +44,16 @@
     beforeEach (done) ->
       expect(@subject.update(@listByName()))
         .eventually.notify(done)
+    expectReadAll = () ->
+      it 'from the beginning', (done) ->
+        expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 0, 1)).eventually
+          .eql([@list[0]]).notify(done)
+      it 'in the middle', (done) ->
+        expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 1, 2)).eventually
+          .eql([@list[1], @list[2]]).notify(done)
+      it 'beyond scope', (done) ->
+        expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 5, 2)).eventually
+          .eql([@list[5]]).notify(done)
     describe 'name', ->
       beforeEach () ->
         @sortBy = 'name'
@@ -51,28 +61,12 @@
         beforeEach () ->
           @list = @listByName()
           @sortOrderAsc = true
-        it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 0, 1)).eventually
-            .eql([@list[0]]).notify(done)
-        it 'in the middle', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 1, 2)).eventually
-            .eql([@list[1], @list[2]]).notify(done)
-        it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 5, 2)).eventually
-            .eql([@list[5]]).notify(done)
+        expectReadAll()
       describe 'desc', ->
         beforeEach () ->
           @list = @listByName().reverse()
           @sortOrderAsc = false
-        it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 0, 1)).eventually
-            .eql([@list[0]]).notify(done)
-        it 'in the middle', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 1, 2)).eventually
-            .eql([@list[1], @list[2]]).notify(done)
-        it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 5, 2)).eventually
-            .eql([@list[5]]).notify(done)
+        expectReadAll()
     describe 'stars', ->
       beforeEach () ->
         @sortBy = 'stars'
@@ -80,26 +74,10 @@
         beforeEach () ->
           @list = @listByStars()
           @sortOrderAsc = true
-        it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 0, 1)).eventually
-            .eql([@list[0]]).notify(done)
-        it 'in the middle', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 1, 2)).eventually
-            .eql([@list[1], @list[2]]).notify(done)
-        it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 5, 2)).eventually
-            .eql([@list[5]]).notify(done)
+        expectReadAll()
       describe 'desc', ->
         beforeEach () ->
           @list = @listByStars().reverse()
           @sortOrderAsc = false
-        it 'from the beginning', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 0, 1)).eventually
-            .eql([@list[0]]).notify(done)
-        it 'in the middle', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 1, 2)).eventually
-            .eql([@list[1], @list[2]]).notify(done)
-        it 'beyond scope', (done) ->
-          expect(@subject.readFromAll(@sortBy, @sortOrderAsc, 5, 2)).eventually
-            .eql([@list[5]]).notify(done)
+        expectReadAll()


link working badly

link working badly

--- src/render.coffee
+++ src/render.coffee
@@ -33,6 +33,7 @@
   attrs = {
     id: index_label
     class: klass
+    href: world.get 'href'
     style: world.bind() -> style
     click: clicker(world)
     # TODO: add touch events that do not mess up mutation


adding logo

adding logo

Former-commit-id: 8c1efcc18bff12c6daac0bc2a3047b4530ccc5ac [formerly b473c7dbbc377d17be60479733dba2443d19bc07] [formerly aa5f82493e93ab5262f23dff8d4a4361985bab56 [formerly e84062b8caa5aa71f8e8422ca154151bc665a4da]] [formerly b39099b3978904e28dbfe84fca912aebdbe3bfb7 [formerly 15021ad8f1c86826eaf44cba88269731d3b880b5] [formerly 6eceb2f7a254f19adeb52b3d1a0fe52da0db44a1 [formerly 6eceb2f7a254f19adeb52b3d1a0fe52da0db44a1 [formerly 93cace57ec61c6a5ee839b7511a87be760aec1b4]]]]
Former-commit-id: 31924c20484b3cc1058d1b535d95cb155e8adcde [formerly 37b4f54a57a43979c84da1db2d08f899e052e96f] [formerly d59d5d894b671b61425b3e419558bfd8c97f4a47 [formerly 8765bf294652d2e5a69d1f87cdf4ba2f2187e7cb]]
Former-commit-id: 0ce2398521a8ffbbc1bc24a627a01cebd0549ad9 [formerly 07235a63343c181468845c446700e56fe15669e0]
Former-commit-id: 9887ed8eaa5761183b849ddbe5d9e56cd53c9a0f
Former-commit-id: b935d147a50e9519bad3fcb0e2fb8967be392588

--- @client/customizations.coffee
+++ @client/customizations.coffee
@@ -780,36 +780,38 @@
                 """
             DIV
               style:
-                fontStyle: 'italic'
+                #fontStyle: 'italic'
                 marginTop: 20
                 fontSize: 18
                 color: seattle2035_dark

-              "Thanks for your time,"
-
               DIV
                 style:
-                  marginLeft: 0
-
-                "Department of Planning & Development"
-                BR()
-                "City of Seattle"
-
-
-            DIV
-              style: _.extend {}, section_style,
-                margin: 0
-                marginTop: 10
-                fontSize: 18
-
-              'p.s. Email us at '
-              A
-                href: "mailto:2035@seattle.gov"
+                  marginBottom: 18
+                "Thanks for your time,"
+
+              IMG
+                src: asset('seattle2035/DPDLogo.svg')
                 style:
-                  textDecoration: 'underline'
-
-                "2035@seattle.gov"
-              " if there is another Key Proposal you would like us to add below."
+                  height: 50
+                  display: 'block'
+                  marginBottom: 8
+
+
+              DIV
+                style: _.extend {}, section_style,
+                  margin: 0
+                  marginTop: 10
+                  fontSize: 18
+
+                'p.s. Email us at '
+                A
+                  href: "mailto:2035@seattle.gov"
+                  style:
+                    textDecoration: 'underline'
+
+                  "2035@seattle.gov"
+                " if there is another Key Proposal you would like us to add below."


Firefox doesn't support the .innerText property on DOM elements; instead it uses .textContent. o_O

This addresses #6.

--- src/rivets.coffee
+++ src/rivets.coffee
@@ -104,7 +104,10 @@
   enabled:
     stateBinding 'disabled', true
   text: (el, value) ->
-    el.innerText = value or ''
+    if el.innerText?
+      el.innerText = value or ''
+    else
+      el.textContent = value or ''
   html: (el, value) ->
     el.innerHTML = value or ''
   value: (el, value) ->


router: fix autosubscribeNewUsers operation name

--- src/router.coffee
+++ src/router.coffee
@@ -147,7 +147,7 @@
                         for userid in @autosubscribeNewUsers
                             for type in nodeTypes
                                 req = Object.create(opts)
-                                req.operation = 'subscribe-user'
+                                req.operation = 'subscribe-node'
                                 req.node = "/user/#{userid}/#{type}"
                                 req.writes = yes
                                 @run req


Camelcase the smallStepSize option

Camelcase the smallStepSize option

--- src/leaflet.timeline.coffee
+++ src/leaflet.timeline.coffee
@@ -180,7 +180,7 @@
     @showTicks = @timeline.options.showTicks
     @stepDuration = @timeline.options.duration / @timeline.options.steps
     @stepSize = ( @end - @start ) / @timeline.options.steps
-    @smallStepSize = @timeline.options.smallstepsize or @stepSize / 10
+    @smallStepSize = @timeline.options.smallStepSize or @stepSize / 10

   _buildDataList: (container, times) ->
     @_datalist = L.DomUtil.create 'datalist', '', container


Add redirect for controller node

Add redirect for controller node

--- src/server.coffee
+++ src/server.coffee
@@ -89,6 +89,12 @@
 					res.write("#{log[0]}: #{log[1]} \n")
 				res.end()
 			)
+
+			@_app.get('/controller/:nodeId', ( req, res ) =>
+				res.redirect('/controller.html?nodeId=' + req.params.nodeId);
+				res.end()
+			)
+

 			@_server.listen(8080)