modify radio to work with tests

modify radio to work with tests

--- app/scripts/robot/radio.coffee
+++ app/scripts/robot/radio.coffee
@@ -23,7 +23,7 @@
         callback(channel, update) for callback in callbacks[channel]

     # fake radio event sent every 100 ms
-    mockEnabled = false
+    mock = false
     mockPromise = undefined
     mockRadio = ->
       now = new Date().getTime()
@@ -33,6 +33,10 @@
         time: now
         value: num
         })
+    enableMock = (millis = 100) ->
+      unless mock
+        mock = true
+        mockPromise = $interval(mockRadio, millis)

     _radioAddr = ''
     _portPath = ''
@@ -42,7 +46,12 @@
       _radioAddr = radioAddr

       _ndl3Radio.close() if _ndl3Radio?
-      radio = requireNode('ndl3radio')
+      if requireNode?
+        radio = requireNode('ndl3radio')
+      else
+        enableMock()
+        return
+
       _ndl3Radio = new radio.Radio()

       if _portPath != portPath
@@ -75,10 +84,7 @@
         radioInit(args...)
         _init = true
         return true
-      enableMock: (millis = 100) ->
-        unless mockEnabled
-          mockEnabled = true
-          mockPromise = $interval(mockRadio, millis)
+      enableMock: enableMock
       initialized: ->
         return _init
       close: ->
@@ -111,8 +117,7 @@
               object._channel = channel
               _ndl3Radio.send(object)
           else
-            console.log "_ndl3Radio not defined"
-            return false
+            console.log "_ndl3Radio not defined, not sending"

           console.log "radio channel 'chname': sent \nobject"
           .replace(/object/, JSON.stringify(object, null, 4))


Add doc.

Add doc.

--- app/javascripts/chart.coffee
+++ app/javascripts/chart.coffee
@@ -9,17 +9,21 @@
     # values to graph. The chart values are obtained by calling
     # the input format x-axis accessor for each chart data series.
     #
-    # The input dataSpec contains the follwing x and y attributes:
+    # The input dataSpec contains the following x and y attributes:
     # * x is the x-axis {label, accessor}
-    # * y is the y-axis {[{label, accessor}, ...], precision},
-    # where label is the data series chart label and accessor
-    # is the data series value to chart, and precision is the
-    # decimal precision to use for all data series values
-    #
-    # The result contains the following attributes:
+    # * y is the y-axis {[{label, color, accessor}, ...], precision},
+    # where:
+    # * label is the data series chart label
+    # * color is the data series chart color
+    # * accessor is the data value access function
+    # * precision is the decimal precision to use for all data series
+    #   values
+    #
+    # The result configuration object contains the following properties:
     # * data - the nvd3 chart data
-    # * color - the nvd3 color function
-    # * maxMin - the maximum and minimum chart y-axis display values
+    # * yLabel - the nvd3 yAxisLabel value
+    # * yFormat - the nvd3 yAxisTickFormat function
+    # * yMaxMin - the nvd3 forcey range
     #
     # @param data the resource objects to graph
     # @param dataSpec the data access specification
@@ -72,12 +76,12 @@
           coordinates = (data, xAccessor, yAccessor) ->
             [xAccessor(rsc), yAccessor(rsc)] for rsc in data

-          key: dataSeries.label
+          key: y.label
           values: coordinates(data, x.accessor, y.accessor)
-          color: dataSeries.color
-
-        for dataSeries in dataSpec.y.data
-         configureADataSeries(data, dataSpec.x, dataSeries)
+          color: y.color
+
+        for y in dataSpec.y.data
+         configureADataSeries(data, dataSpec.x, y)

       # Adds padding to the give value range as follows:
       # * the the chart max is the next higher significant


[grunt] add function for converting locale into ISO format; pass it to Nunjucks' as `page.isoLocale`

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -136,6 +136,26 @@
     # for other — only first part
     if _matched[3] then _matched[1] + '-' + _matched[2] else _matched[1]

+  ###*
+   * Get region code from locale, without language
+   * @param {string} locale Locale, from which should be taken region code
+   * @return {string} Region code from locale
+  ###
+  getRegioncode = (locale) ->
+    _matched = locale.match(/^(\w*)-?(\w*)-?(\w*)/i)
+    # See note for `getLangcode` for explanations. It's same, but just for the region code
+    if _matched[3] then _matched[3] else _matched[2]
+
+  ###*
+   * Convert locale into ISO format: `{langcode}_{REGIONCODE}`
+   * @param {string} locale Locale, which should be converted
+   * @return {string} Locale in ISO format
+  ###
+  isoLocale = (locale) ->
+    _langcode = getLangcode(locale)
+    _region   = getRegioncode(locale).toUpperCase()
+    locale =  _langcode + '_' + _region
+
   # ===============
   # Load l10n files
   # ===============
@@ -474,6 +494,7 @@
           data.page = data.page || {}

           data.page.locale     = currentLocale
+          data.page.isoLocale  = isoLocale(currentLocale)
           data.page.rtl        = _.find(taskConfig.i18n.locales, { locale: currentLocale }).rtl
           data.page.url        = if pagedir == '.' then '' else pagedir
           data.page.breadcrumb = if pagedir == '.' then ['.'] else pagedir.split('/')


modify task script

modify task script

--- tasks/install-jsdoc-toolkit.coffee
+++ tasks/install-jsdoc-toolkit.coffee
@@ -63,6 +63,6 @@
     grunt.task.run [
       'download-jsdoc-toolkit',
       'extract-jsdoc-toolkit',
-      'copy:' + extracted_directory_name + install_path ':' + install_path,
+      'copy:' + extracted_directory_name + install_path + ':' + install_path,
       'finalize-jsdoc-toolkit'
     ]


Enable tsv

Enable tsv

--- src/coffee/convert.coffee
+++ src/coffee/convert.coffee
@@ -7,11 +7,12 @@
     cell

 class Table
-  constructor: (@lines) ->
+  constructor: (@lines, @sep) ->
     @name = @lines[0]
-    @columns = @lines[1].split(',')
-    @records = @lines.slice(2).map (l) ->
-       l.split(',').map(convertCell)
+    @columns = @lines[1].split(@sep)
+    console.log(@sep)
+    @records = @lines.slice(2).map (l) =>
+      l.split(@sep).map(convertCell)

   # nullable
   toSQL: (mani, detail) ->
@@ -45,13 +46,21 @@
 nonEmpty = (str) -> str != ''
 dropEmptyLine = (xs) -> _.dropWhile(xs, isEmpty)

+matchCount = (str, re) -> (str.match(re) || []).length
+
+decideSeparator = (str) ->
+  comma = matchCount(str, /,/g)
+  tab = matchCount(str, /\t/g)
+  if comma > tab then ',' else '\t'
+
 @convert = (mani, detail, csv) ->
+  sep = decideSeparator(csv)
   lines = dropEmptyLine(csv.split('\n'))
   tables = while lines.length > 0
     tableLines = _.takeWhile(lines, nonEmpty)
     lines = _.dropWhile(lines, nonEmpty)
     lines = dropEmptyLine(lines)
-    new Table(tableLines)
+    new Table(tableLines, sep)
   tables.map (t) -> t.toSQL(mani, detail)
     .filter (s) -> s?
     .join('\n\n')


Update de-DE.coffee (#5972)

Update de-DE.coffee (#5972)

Some lines from the top landing page

Co-authored-by: Valentin Bryukhanov <53545457af642b0f8712bb2cc004f120ce4436f4@gmail.com>

--- app/locale/de-DE.coco.coffee
+++ app/locale/de-DE.coco.coffee
@@ -61,15 +61,16 @@
 #    for_leaders_subtitle4: "Real-World Skills"
 #    for_leaders_subblurb4: "Students build grit and develop a growth mindset through coding challenges that prepare them for the 500K+ open computing jobs."
     for_teachers_title: "Für Lehrer"
-#    for_teachers_blurb: "Tools to Unlock Student Potential"
+    for_teachers_blurb: "Wie Sie das Potential Ihrer Schüler freisetzen"
     for_teachers_subtitle1: "Projektbasiertes Lernen"
-#    for_teachers_subblurb1: "Promote creativity, problem-solving, and confidence in project-based courses where students develop their own games and webpages."
-#    for_teachers_subtitle2: "Teacher Dashboard"
-#    for_teachers_subblurb2: "View data on student progress, discover curriculum resources, and access real-time support to empower student learning."
-#    for_teachers_subtitle3: "Built-in Assessments"
-#    for_teachers_subblurb3: "Personalize instruction and ensure students understand core concepts with formative and summative assessments."
-#    for_teachers_subtitle4: "Automatic Differentiation"
-#    for_teachers_subblurb4: "Engage all learners in a diverse classroom with practice levels that adapt to each student's learning needs."
+    for_teachers_subblurb1: "Fördern Sie Kreativität, Problemlösungskompetenzen und Selbstvertrauen in Projektkursen, in denen Schüler ihre eigenen Spiele und Webseiten entwickeln."
+    for_teachers_subtitle2: "Lehrer Dashboard"
+    for_teachers_subblurb2: "Sehen Sie, welche Fortschritte Ihre Schülerinnen und Schüler machen, entdecken Sie Unterichtsmaterialien und greifen Sie auf direkte Unterstützung zu, um Ihren Schülerinnen und Schüler erfolgreiches Lernen zu ermöglichen."
+#View data on student progress, discover curriculum resources, and access real-time support to empower student learning."
+    for_teachers_subtitle3: "Vorgefertigte Prüfungen"
+    for_teachers_subblurb3: "Passen Sie die Aufgabenstellungen individuell an und stellen Sie mit formativer und summativer Beurteilung sicher, dass die Schülerinnen und Schüler die Grundkonzepte wirklich verstehen."
+    for_teachers_subtitle4: "Individuelle Differenzierung"
+    for_teachers_subblurb4: "Integrieren Sie Schülerinnen und Schüler in heterogenen Klassen mit Übungen, die sich an die individuellen Bedürfnisse der Lernenden anpassen."
 #    game_based_blurb: "CodeCombat is a game-based computer science program where students type real code and see their characters react in real time."
 #    get_started: "Get started"
 #    global_title: "Join Our Global Community of Learners and Educators"
@@ -91,8 +92,8 @@
 #    teachers_love_codecombat_blurb2: "Would recommend CodeCombat to other computer science teachers"
 #    teachers_love_codecombat_blurb3: "Say that CodeCombat helps them support students’ problem solving abilities"
 #    teachers_love_codecombat_subblurb: "In partnership with McREL International, a leader in research-based guidance and evaluations of educational technology."
-#    top_banner_blurb: "Parents, give your child the gift of coding and personalized instruction with our live teachers!"
-#    try_the_game: "Try the game"
+    top_banner_blurb: "Eltern können hier die ersten Online-Kurse kostenfrei buchen."
+    try_the_game: "Das Spiel ausprobieren"
     classroom_edition: "Klassenraum Edition:"
     learn_to_code: "Lerne zu Programmieren:"
     play_now: "Jetzt spielen"
@@ -156,16 +157,16 @@
     view_profile: "Zeige mein Profil"
     view_progress: "Fortschritt ansehen"
     go_to_courses: "Zu meinen Kursen"
-    want_coco: "Wollen Sie CodeCombat an Ihrer Schule?"
-#    educator: "Educator"
-#    student: "Student"
-#    our_coding_programs: "Our Coding Programs"
-#    codecombat: "CodeCombat"
-#    ozaria: "Ozaria"
-#    codecombat_blurb: "Our original coding game. Recommended for parents, individuals, educators, and students who want to experience one of the most-loved coding games in the world."
-#    ozaria_blurb: "An adventure game and Computer Science program where students master the lost magic of coding to save their world. Recommended for educators and students."
-#    try_codecombat: "Try CodeCombat"
-#    try_ozaria: "Try Ozaria"
+    want_coco: "Wollen Sie CodeCombat an Ihrer Schule einsetzen?"
+    educator: "Lehrkraft"
+    student: "Schüler"
+    our_coding_programs: "Unsere Programme zum Programmieren lernen"
+    codecombat: "CodeCombat"
+    ozaria: "Ozaria"
+    codecombat_blurb: "Das Original. Ein Spiel zum Programmieren lernen. Empfehlenswert für Eltern, Individuen, Lehrkräfte und Schüler, die in eines der weltweit beliebtesten Spiele zum Programmieren eintauchen möchten."
+    ozaria_blurb: "Ein Adventure und Informatik-Lernprogramm, in dem Schüler die verlorene Magie des Programmierens meistern um ihre Welt zu retten. Empfohlen für Lehrkräfte und Schüler."
+    try_codecombat: "CodeCombat testen"
+    try_ozaria: "Ozaria testen"

   nav:
 #    educators: "Educators"
@@ -185,12 +186,12 @@
     legal: "Rechtliches"
     privacy: "Datenschutz"
     about: "Über"
-#    impact: "Impact"
+    impact: "Referenzen" #impact - oder Leuchtturm-Projekte
     contact: "Kontakt"
     twitter_follow: "Folge uns auf Twitter"
     my_classrooms: "Meine Klassen"
     my_courses: "Meine Kurse"
-#    my_teachers: "My Teachers"
+    my_teachers: "Meine Lehrer"
     careers: "Karriere mit CodeCombat!"
     facebook: "Facebook"
     twitter: "Twitter"
@@ -211,7 +212,7 @@
     apcsp: "AP CS Prinzipien"
     parent: "Eltern"
 #    esports: "Esports"
-#    browser_recommendation: "For the best experience we recommend using the latest version of Chrome. Download the browser here!"
+    browser_recommendation: "Für die beste Funktionalität empfehlen wir als Browser die aktuelle Version von Chrome. Hier herunterladen!"

   modal:
     close: "Schließen"


Adds helper ordering to tests

Adds helper ordering to tests

--- app/templates/Gruntfile.coffee
+++ app/templates/Gruntfile.coffee
@@ -18,7 +18,12 @@
           transform: ["coffeeify"]
       test:
         files:
-          "test/specs.js": ["test/spec/**/*.js", "test/spec/**/*.coffee"]
+          "test/specs.js": [
+            "test/spec/**/*helper.js"
+            "test/spec/**/*helper.coffee"
+            "test/spec/**/*spec.js"
+            "test/spec/**/*spec.coffee"
+          ]
         options:
           debug: true
           transform: ["coffeeify"]


Prefer to reject promises with real Error objects

--- src/altmetric.coffee
+++ src/altmetric.coffee
@@ -14,7 +14,7 @@
     new Promise (resolve, reject) ->
       robot.http(url).get() (err, res, body) ->
         if err
-          reject(err.message)
+          reject(err)
         else
           resolve(JSON.parse(body))

@@ -24,7 +24,7 @@
         .header('Content-Type', 'application/json')
         .post(JSON.stringify(data)) (err, res, body) ->
           if err
-            reject(err.message)
+            reject(err)
           else
             resolve(JSON.parse(body))

@@ -35,9 +35,9 @@
         if results.hasOwnProperty(id)
           getJSON("http://api.altmetric.com/v1/id/#{ results[id] }?include_sections=images")
         else
-          throw "no altmetrics for #{id}"
+          throw new RangeError("no altmetrics for #{id}")
       .then (citation) ->
         res.send "#{ citation.images.medium }#.png"
         res.send "http://www.altmetric.com/details/#{ citation.altmetric_id }"
       .catch (error) ->
-        res.send "Sorry, I couldn't donut that for you: #{error}"
+        res.send "Sorry, I couldn't donut that for you: #{error.message}"


Do not generate source-maps

Do not generate source-maps


Allow longer lines

Allow longer lines


Fixed Gruntfile to provide standalone component.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -22,6 +22,9 @@
           "test/test.js": "test/*.coffee"

     componentbuild:
+      options:
+        standalone: "Dropzone"
+
       app:
         # output: "build/"
         name: "build"
@@ -30,7 +33,6 @@
         # config: "component.json"
         # styles: false
         # scripts: true
-        standalone: "Dropzone"

     copy:
       component:


Change Atom themes.

Change Atom themes.

--- Atom/config.cson
+++ Atom/config.cson
@@ -4,6 +4,10 @@
       "atom-beautify"
     ]
     telemetryConsent: "no"
+    themes: [
+      "one-light-ui"
+      "solarized-light-syntax"
+    ]
     useTreeSitterParsers: false
   editor:
     fontSize: 13


Add current user to process text modules.

--- app/assets/javascripts/app/controllers/agent_ticket_create.coffee
+++ app/assets/javascripts/app/controllers/agent_ticket_create.coffee
@@ -475,6 +475,7 @@
           @textModule.reload(
             ticket:
               customer: user
+            user: App.Session.get()
           )

         new App.WidgetUser(


closePasswordFields clears password fields and errors

--- app/components/profile-settings-page/profile-settings-page.coffee
+++ app/components/profile-settings-page/profile-settings-page.coffee
@@ -38,4 +38,6 @@
       $scope.showPasswordFields = true

     $scope.closePasswordFields = ->
+      $scope.passwordParams = {}
+      $scope.passwordErrors = {}
       $scope.showPasswordFields = false


Handle race condition on window load after quick nav away

This is a cosmetic error fix

--- app/views/HomeView.ozar.coffee
+++ app/views/HomeView.ozar.coffee
@@ -120,7 +120,7 @@
         @openModalView(new CreateAccountModal({startOnPath: 'teacher'}))

     window.addEventListener 'load', ->
-      $('#core-curriculum-carousel').data('bs.carousel').$element.on 'slid.bs.carousel', (event) ->
+      $('#core-curriculum-carousel').data('bs.carousel')?.$element.on 'slid.bs.carousel', (event) ->
         nextActiveSlide = $(event.relatedTarget).index()
         $buttons = $('.control-buttons > button')
         $buttons.removeClass 'active'


fixed bug preventing attributes to be removed on script and style tags

--- src/api/utils.coffee
+++ src/api/utils.coffee
@@ -173,8 +173,8 @@
     return elem.attribs[name]

 removeAttr = exports.removeAttr = (elem, name) ->
-  if elem.type is 'tag' and elem.attribs
-
+  if isTag(elem.type) and elem.attribs
+
     if elem.attribs[name]
       if rboolean.test elem.attribs[name]
         elem.attribs[name] = false


better radio/checkbox tests

better radio/checkbox tests

--- tests/all.coffee
+++ tests/all.coffee
@@ -18,7 +18,7 @@
 		assert document.body?
 	it "has DOCUMENT_ELEMENT node type", ->
 		assert.equal document.nodeType, 9, "document.nodeType"
-	describe 'creating a new element', ->
+	describe '.createElement()', ->
 		div = document.createElement('div')
 		it 'has node type', ->
 			assert.equal div.nodeType, 1
@@ -36,7 +36,6 @@
 				document.body.appendChild div
 				document.body.removeChild div
 				assert.equal document.body.childNodes.length, 0
-
 	describe '.getElementsByTagName()', ->
 		it "should find a single element", ->
 			document.body.innerHTML = "
"
@@ -47,14 +46,12 @@
 		it "is not case sensitive", ->
 			document.body.innerHTML = "

"
 			assert.equal document.body.getElementsByTagName('div').length, 2
-
 	describe '.getElementById()', ->
 		it 'finds a single element', ->
 			div = document.createElement("div")
 			div.id = "getElemId"
 			document.body.appendChild(div)
 			assert.equal document.getElementById("getElemId"), div
-
 	describe ".attributes", ->
 		it "is read/write", ->
 			div = document.createElement 'div'
@@ -92,7 +89,6 @@
 				attr = div.getAttributeNode("name")
 				assert.equal attr.value, "foo"
 				assert.equal attr.nodeValue, "foo"
-
 	describe ".childNodes", ->
 		it "every node should have .childNodes", ->
 			div = document.createElement("div")
@@ -210,23 +206,29 @@
 				select.selectedIndex = 1
 				assert.equal select.selectedIndex, 1, 'select.selectedIndex * 2'
 				assert.equal select.value, 'B', 'select.value'
-	it "input_radio",  ->
-		test_doc = global.dom.createDocument()
-		test_doc.body.innerHTML = "<input type='radio' selected>"
-		input = test_doc.body.childNodes[0]
-		assert.equal input.constructor.name, "HTMLInputElement"
-		assert.equal input.hasAttribute('selected'), true, 'input.hasAttr'
-		assert.equal input.getAttribute('selected'), ''
-		assert.equal input.selected, true, 'input.selected'
-		input.removeAttribute('selected')
-		assert.equal input.selected, false, 'input.selected'
-		assert.equal input.value, "on"
-	it "input_checkbox",  ->
-		test_doc = global.dom.createDocument()
-		test_doc.body.innerHTML = "<input type='checkbox' checked >"
-		input = test_doc.body.childNodes[0]
-		assert.equal input.checked, true, 'input.checked'
-		assert.equal input.value, "on"
+		describe "<input type='radio'>", ->
+			test_doc = global.dom.createDocument()
+			test_doc.body.innerHTML = "<input type='radio' selected>"
+			input = test_doc.body.childNodes[0]
+			it "should be an HTMLInputElement", ->
+				assert.equal input.constructor.name, "HTMLInputElement"
+			it "has a 'selected' attribute", ->
+				assert.equal input.hasAttribute('selected'), true
+			it "having selected attribute means selected is true", ->
+				assert.equal input.getAttribute('selected'), ''
+				assert.equal input.selected, true
+				input.removeAttribute('selected')
+				assert.equal input.selected, false
+			it "should have a default value of 'on'", ->
+				assert.equal input.value, "on"
+		describe "<input type='checkbox'>", ->
+			test_doc = global.dom.createDocument()
+			test_doc.body.innerHTML = "<input type='checkbox' checked >"
+			input = test_doc.body.childNodes[0]
+			it "should have a special .checked property", ->
+				assert.equal input.checked, true, 'input.checked'
+			it "should have a default value of 'on'", ->
+				assert.equal input.value, "on"
 	it "can create/render comments",  ->
 		comment_doc = global.dom.createDocument()
 		comment = comment_doc.createComment("comment text")
@@ -261,7 +263,6 @@
 	html = require('../html/parser')

 	test_parse = (input, output, debug = false) ->
-		message = ""
 		try
 			result = html.parse(input, document, debug).toString(false, true)
 			output ?= input
@@ -307,7 +308,6 @@
 		p: () -> test_escape '
', '<p>'
 		amp: () -> test_escape '&', '&'
 		mixed: () -> test_escape '?input=foo&bar&key=value', '?input=foo&bar&key=value',
-# TODO: more escape and unescape tests
 	}

 	TestReport()


removed an unnecessary line of code

removed an unnecessary line of code

--- source/javascripts/mincha.coffee
+++ source/javascripts/mincha.coffee
@@ -144,7 +144,6 @@
         $(".#{@chag()}.shema").find(".dow, .date").removeClass('hidden')
     if @hebrew_date.isRoshHashana()
       if @hebrew_date.isShabbat()
-        $(".#{@chag()}").find(".ends, .rabbenu-tam").removeClass("hidden")
         $(".#{@chag()}.afternoon-shiur").find(".dow, .date").removeClass("hidden")
       else
         $(".#{@chag()}.shofar").removeClass("hidden").find(".time").html(time_format(@today().hour(10).minute(30)))


Atom - Dont allow scroll past the end, had some issues

--- atom/config.cson
+++ atom/config.cson
@@ -20,7 +20,6 @@
       "atom-dark-syntax"
     ]
   editor:
-    scrollPastEnd: true
     tabLength: 4
   "exception-reporting":
     userId: "82a26126-5c31-4531-b32c-a1877d4677e0"


cleanup

cleanup

--- pimatic-wink-config-schema.coffee
+++ pimatic-wink-config-schema.coffee
@@ -1,5 +1,4 @@
 # #pimatic-wink configuration options
-# Declare your config option for your plugin here.
 module.exports = {
   title: "pimatic-wink config options"
   type: "object"


Remove non bare compilation

Remove non bare compilation

--- src/nodes.coffee
+++ src/nodes.coffee
@@ -318,7 +318,7 @@
   # It would be better not to generate them in the first place, but for now,
   # clean up obvious double-parentheses.
   compileRoot: (o) ->
-    o.indent  = if o.bare then '' else TAB
+    o.indent  = ''
     o.level   = LEVEL_TOP
     @spaced   = yes
     o.scope   = new Scope null, this, null, o.referencedVars ? []
@@ -326,19 +326,7 @@
     # end up being declared on this block.
     o.scope.parameter name for name in o.locals or []
     prelude   = []
-    unless o.bare
-      preludeExps = for exp, i in @expressions
-        break unless exp.unwrap() instanceof Comment
-        exp
-      rest = @expressions[preludeExps.length...]
-      @expressions = preludeExps
-      if preludeExps.length
-        prelude = @compileNode merge(o, indent: '')
-        prelude.push @makeCode "\n"
-      @expressions = rest
-    fragments = @compileWithDeclarations o
-    return fragments if o.bare
-    [].concat prelude, @makeCode("(function() {\n"), fragments, @makeCode("\n}).call(this);\n")
+    @compileWithDeclarations o

   # Compile the expressions body for the contents of a function, with
   # declarations of all inner variables pushed up to the top.


Remove reference to unused string helper

--- apps/location/index.coffee
+++ apps/location/index.coffee
@@ -4,7 +4,6 @@

 express = require 'express'
 routes = require './routes'
-{ parameterize } = require '../../components/util/string.coffee'

 app = module.exports = express()
 app.set 'views', __dirname + '/templates'


Indent e2e result with 4 spaces.

Indent e2e result with 4 spaces.

--- test/smoke.e2e.coffee
+++ test/smoke.e2e.coffee
@@ -14,4 +14,4 @@
 if !fs.existsSync(tmpDir) then fs.mkdirSync(tmpDir, 0o744)

 # Write JSON Schema of tweet
-fs.writeFileSync("#{tmpDir}/tweet.schema.json", JSON.stringify(schema, null, "  "))+fs.writeFileSync("#{tmpDir}/tweet.schema.json", JSON.stringify(schema, null, "    "))


coffeescript doesn't like \0 (or maybe it's V8?). Anyway, changed it to \u0000

--- test/test.blob.coffee
+++ test/test.blob.coffee
@@ -29,7 +29,7 @@
 				blob.data.should.be.an.instanceof Buffer
 			it "has correct contents", ->
 				shasum = crypto.createHash "sha1"
-				shasum.update "blob #{blob.data.length}\0"
+				shasum.update "blob #{blob.data.length}\u0000"
 				shasum.update blob.data.toString("binary")
 				shasum.digest("hex").should.equal blob.id
 			it "is immutable", -> utils.checkImmutable blob, "data"


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/point.coffee
+++ src/point.coffee
@@ -44,6 +44,7 @@

   Point:: =
     ###*
+
     ###
     ###*
     Creates a copy of this point.


metric: added createTrade and completeTrade

--- src/models/metric.coffee
+++ src/models/metric.coffee
@@ -183,6 +183,28 @@
     numerator:
       select: 'count(userId)'
       from: 'claimReward'
+      where: (day) ->
+        "time >= #{dayToMS day}ms AND time < #{dayToMS day + 1}ms"
+  }
+  {
+    name: 'create trade'
+    apps: ['kitten-cards']
+    format: '0'
+    isGroupSizeDependent: true
+    numerator:
+      select: 'count(userId)'
+      from: 'createTrade'
+      where: (day) ->
+        "time >= #{dayToMS day}ms AND time < #{dayToMS day + 1}ms"
+  }
+  {
+    name: 'complete trade'
+    apps: ['kitten-cards']
+    format: '0'
+    isGroupSizeDependent: true
+    numerator:
+      select: 'count(userId)'
+      from: 'completeTrade'
       where: (day) ->
         "time >= #{dayToMS day}ms AND time < #{dayToMS day + 1}ms"
   }


(feature) Expose process function via API.

--- src/more_markdown.coffee
+++ src/more_markdown.coffee
@@ -40,7 +40,7 @@

   # creates an advanced markdown processor for that specific dom element
   # does some magic to remove flickering etc.
-module.exports =
+API =
   create: (element_id, config) ->
     activeProcessors = config.processors

@@ -131,3 +131,8 @@
           else
             console.log(err)
         swap active, buffer
+  process: (markdown, config) ->
+    API.create("", config).processMarkdown(markdown)
+
+
+module.exports = API


Removed dead comment

Removed dead comment

--- assets/js/application.coffee
+++ assets/js/application.coffee
@@ -39,7 +39,6 @@
       done = (html) ->
         $deferred.hide().html(html).fadeIn(100)
         initTracePanels()
-        # clearInterval timer
       fail = (xhr, status, error) ->
         done "
Failed to load content#{if error then ': ' + error else ''}
"
       $.get(Tendril.deferred).done(done).fail(fail)


Exclude SDES terminator from sdesItems

Exclude SDES terminator from sdesItems

--- rtp.coffee
+++ rtp.coffee
@@ -283,30 +283,25 @@
       chunk.ssrc_csrc = bits.read_bits 32
       chunk.sdesItems = []
       chunk.sdes = {}
-      moreSDESItems = true
-      while moreSDESItems
+      loop
         sdesItem = {}
         sdesItem.type = bits.read_byte()
-
-        # RFC 3550, 6.5: "No length octet follows the null item type octet"
-        if sdesItem.type isnt 0
-          sdesItem.octetCount = bits.read_byte()
-          if sdesItem.octetCount > 255
-            throw new Error "octet count too large: #{sdesItem.octetCount} <= 255"
-          sdesItem.text = bits.read_bytes(sdesItem.octetCount).toString 'utf8'
-
+        if sdesItem.type is 0  # terminate the list
+          # skip until the next 32-bit boundary
+          bytesPastBoundary = (bits.current_position().byte - startBytePos) % 4
+          if bytesPastBoundary > 0
+            while bytesPastBoundary < 4
+              nullOctet = bits.read_byte()
+              if nullOctet isnt 0x00
+                throw new Error "padding octet must be 0x00: #{nullOctet}"
+              bytesPastBoundary++
+          break
+
+        sdesItem.octetCount = bits.read_byte()
+        if sdesItem.octetCount > 255
+          throw new Error "octet count too large: #{sdesItem.octetCount} <= 255"
+        sdesItem.text = bits.read_bytes(sdesItem.octetCount).toString 'utf8'
         switch sdesItem.type
-          when 0  # terminate the list
-            # skip until the next 32-bit boundary
-            bytesPastBoundary = (bits.current_position().byte - startBytePos) % 4
-            if bytesPastBoundary > 0
-              while bytesPastBoundary < 4
-                nullOctet = bits.read_byte()
-                if nullOctet isnt 0x00
-                  throw new Error "padding octet must be 0x00: #{nullOctet}"
-                bytesPastBoundary++
-
-            moreSDESItems = false  # end the loop
           when 1  # Canonical End-Point Identifier
             chunk.sdes.cname = sdesItem.text
           when 2  # User Name


[api] Added `user.events([eventType...], cb)` for getting all (or a subset of) events for a given user

--- src/octonode/user.coffee
+++ src/octonode/user.coffee
@@ -38,5 +38,22 @@
       return cb(err) if err
       if s isnt 200 then cb(new Error('User following error')) else cb null, b

+  # Get events performed by a user
+  # '/users/pksunkara/events' GET
+  # TODO: page
+  events: (events, cb) ->
+    if !cb and typeof events == 'function'
+      cb = events
+      events = null
+    else if !Array.isArray events
+      events = [events]
+
+    @client.get "/users/#{@login}/events", (err, s, b)  ->
+      return cb(err) if err
+      return cb(new Error('User events error')) if s isnt 200
+
+      cb null, b.filter (event) ->
+        return events.indexOf(event.type) != -1
+
 # Export module
 module.exports = User


Minus some debugging statements.

Minus some debugging statements.

--- src/quote.coffee
+++ src/quote.coffee
@@ -111,7 +111,6 @@
         [x, speaker, hours, minutes, ampm] = m
         [hours, minutes] = [parseInt(hours), parseInt(minutes)]
         hours += 12 if ampm is 'PM'
-        msg.reply "hours: #{hours} minutes: #{minutes}"
         timestamp = moment({hours: hours, minutes: minutes})
         ts = timestamp.format('h:mm A d MMM YYYY')
       else if speaker? and line.length > 0


Robot.RedisBrain extends Robot.Brain

Robot.RedisBrain extends Robot.Brain

--- src/robot.coffee
+++ src/robot.coffee
@@ -8,9 +8,9 @@
   # dispatch them to matching listeners.
   #
   # path - String directory full of Hubot scripts to load.
-  constructor: (path, name = "Hubot") ->
+  constructor: (path, name = "Hubot", brain = Robot.RedisBrain) ->
     @name        = name
-    @brain       = new Robot.Brain()
+    @brain       = new brain()
     @commands    = []
     @Response    = Robot.Response
     @listeners   = []
@@ -166,6 +166,26 @@
 class Robot.Brain
   # Represents somewhat persistent storage for the robot.
   #
+  # Returns a new Brain with no external storage.  Extend this!
+  constructor: () ->
+    @data =
+      users: { }
+
+  save: (cb) ->
+  close: ->
+
+  # Merge keys loaded from a DB against the in memory representation
+  #
+  # Returns nothing
+  #
+  # Caveats: Deeply nested structures don't merge well
+  mergeData: (data) ->
+    for k of (data or { })
+      @data[k] = data[k]
+
+class Robot.RedisBrain extends Robot.Brain
+  # Represents somewhat persistent storage for the robot.
+  #
   # Returns a new Brain that's trying to connect to redis
   #
   # Previously persisted data is loaded on a successful connection
@@ -173,8 +193,7 @@
   # Redis connects to a environmental variable REDISTOGO_URL or
   # fallsback to localhost
   constructor: () ->
-    @data =
-      users: { }
+    super()

     info = Url.parse process.env.REDISTOGO_URL || 'redis://localhost:6379'
     @client = Redis.createClient(info.port, info.hostname)
@@ -204,15 +223,6 @@
     clearInterval @saveInterval
     @save => @client.quit()

-  # Merge keys loaded from redis against the in memory representation
-  #
-  # Returns nothing
-  #
-  # Caveats: Deeply nested structures don't merge well
-  mergeData: (data) ->
-    for k of (data or { })
-      @data[k] = data[k]
-
 class Robot.Message
   # Represents an incoming message from the chat.
   #


Wait 1 second to exit to give in flight requests some chance to succeed

--- src/slack.coffee
+++ src/slack.coffee
@@ -38,7 +38,8 @@
   error: (error) =>
     @robot.logger.error "Received error #{error.toString()}"
     @robot.logger.error error.stack
-    process.exit 1
+    @robot.logger.error "Exiting in 1 second"
+    setTimeout process.exit.bind(process, 1), 1000

   loggedIn: (self, team) =>
     @robot.logger.info "Logged in as #{self.name} of #{team.name}, but not yet connected"


Removed bad parentheses from regex expression


msg.reply body was being returned on 201 or in any other case.

--- src/scripts/janky.coffee
+++ src/scripts/janky.coffee
@@ -85,7 +85,8 @@
       if statusCode == 201
         msg.reply body
       else
-        msg.reply body
+        console.log body
+        response = "Error F7U12: Can't Setup."

   robot.respond /ci toggle ([-_\.0-9a-zA-Z]+)/i, (msg) ->
     app    = msg.match[1]


fix docs

fix docs

--- src/scripts/theta.coffee
+++ src/scripts/theta.coffee
@@ -2,7 +2,8 @@
 #   A Hubot script to capture image data using RICOH THETA
 #
 # Configuration:
-#   None
+#   HUBOT_SLACK_CHANNEL_ID
+#   HUBOT_SLACK_TOKEN
 #
 # Commands:
 #   hubot theta - capture image data using RICOH THETA


Always to downcase comparisons on platform and os family names (#70)

--- src/tasks/helpers.coffee
+++ src/tasks/helpers.coffee
@@ -13,17 +13,17 @@
 # @return [Boolean] false When it is not possible to build from this environment from this environment.
 canBuild = (targetPlatform) ->
   compatibility =
-    'amazon-fireos': ['darwin', 'Windows', 'Linux']
-    'android': ['darwin', 'Windows', 'Linux']
-    'blackberry10': ['darwin', 'Windows']
+    'amazon-fireos': ['darwin', 'windows', 'linux']
+    'android': ['darwin', 'windows', 'linux']
+    'blackberry10': ['darwin', 'windows']
     'ios': ['darwin']
-    'Ubuntu': ['Linux'] # Specifically Ubuntu
-    'wp7': ['Windows']
-    'wp8': ['Windows'] # Specifically Windows 8
-    'win8': ['Windows'] # Specifically Windows 8
+    'ubuntu': ['linux'] # Specifically Ubuntu
+    'wp7': ['windows']
+    'wp8': ['windows'] # Specifically Windows 8
+    'win8': ['windows'] # Specifically Windows 8
     'tizen': []

-  _.contains compatibility[targetPlatform], require('platform').os.family
+  _.contains compatibility[targetPlatform.toLowerCase()], require('platform').os.family.toLowerCase()

 module.exports = helpers = (grunt) ->


fix tree generation

fix tree generation

--- src/treeGenerator.coffee
+++ src/treeGenerator.coffee
@@ -14,17 +14,21 @@
    return 0;
   )
   allSynsets = _.flatten(docs)
+
   progressCorpusTree = new ProgressBar('Create corpus tree [:bar] :percent', { total: _.size(allSynsets) })
-
-  attachHypernyms = (synset, child) =>
+  attachHypernyms = (synset, words, docIndices) =>
     if not bsTree.has(synset.synsetid)
       insert_synset = new SynsetNode synset
-      insert_synset.children.push(child.synsetid)
+      insert_synset.words = words
+      insert_synset.docs = docIndices
       bsTree.set(synset.synsetid, insert_synset)
-      if synset.hypernym.length > 0 then attachHypernyms(synset.hypernym[0], synset.synsetid)
     else
       existing_synset = bsTree.get(synset.synsetid)
-      existing_synset.children.push(child.synsetid)
+      existing_synset.words = existing_synset.words.concat(words)
+      existing_synset.docs = _.union(existing_synset.docs, docIndices)
+      docIndices = existing_synset.docs
+    if synset.hypernym.length > 0 then attachHypernyms(synset.hypernym[0], words, docIndices)
+    return

   for synset in allSynsets
     if not bsTree.has(synset.synsetid)
@@ -36,7 +40,7 @@
       existing_synset.baseWords =  existing_synset.baseWords?.concat(synset.baseWords)
     if synset.parentId and synset.parentId != 'root'
       parent = WORDNETIFY_SYNSETS_TREE[synset.parentId]
-      attachHypernyms(parent, synset)
+      attachHypernyms(parent, synset.words, synset.docs)
     progressCorpusTree.tick()

   hashTable = {}


Turn off popup autopan.

Turn off popup autopan.

--- src/views.coffee
+++ src/views.coffee
@@ -131,7 +131,7 @@
                 location = unit.get('location')
                 if location?
                     coords = location.coordinates
-                    popup = L.popup(closeButton: false).setContent "
#{unit.get_text 'name'}
"
+                    popup = L.popup(closeButton: false, autoPan: false).setContent "
#{unit.get_text 'name'}
"
                     marker = L.marker([coords[1], coords[0]], icon: icon)
                         .bindPopup(popup)


Minor code documentation to clarify purpose of `zappa.adapter`.

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -581,6 +581,8 @@
   compile: (template, data) ->
     template = engine.compile(template, data)
     (data) ->
+      # Merge down `@params` into `@`
+      # Bonus: if `databag` is enabled, `@params` will be the complete databag.
       for k, v of data.params
         if typeof data[k] is 'undefined' and k not in options.blacklist
           data[k] = v


Provide bound IP address upon startup.

Provide bound IP address upon startup.

--- src/zappa.coffee
+++ src/zappa.coffee
@@ -693,17 +693,20 @@
             else options[k] = v

   zapp = zappa.app(root_function,options)
-  app = zapp.app
+  {server,app} = zapp

   express_ready = ->
-    log 'Express server listening on port %d in %s mode',
-      zapp.server.address()?.port, app.settings.env
-    log "Zappa #{zappa.version} orchestrating the show"
+    addr = server.address()
+    log """
+      Express server listening on #{addr.address}:#{addr.port} in #{app.settings.env} mode.
+      Zappa #{zappa.version} orchestrating the show.
+
+    """

   if host
-    zapp.server.listen port, host, express_ready
+    server.listen port, host, express_ready
   else
-    zapp.server.listen port, express_ready
+    server.listen port, express_ready

   zapp


bugfix

bugfix

--- client.iced
+++ client.iced
@@ -142,13 +142,13 @@
         if file.url
           file.status = 'success'
           file.statusLabel = '就绪'
+          await fs.stat file.dest_path, defer e, dest_stats
+          file.finished = dest_stats?.size == file.size
+
           if stats.retrieves.filter((r)-> r.task.id == task.id && r.file.name == file.name).length
             task.finished = false
           else
-            await fs.stat file.dest_path, defer e, dest_stats
-            if dest_stats?.size == file.size
-              file.finished = true
-            else
+            if !file.finished
               task.finished = false
               stats.retrieves.push
                 task: task


[JS] testing beforeunload stuff

[JS] testing beforeunload stuff


Refactor tests

Refactor tests

--- test/gulp-rebuild-html-test.coffee
+++ test/gulp-rebuild-html-test.coffee
@@ -8,64 +8,68 @@

   describe 'in buffer mode', ->

-    it 'should parse and rebuild html', (done) ->
-      stream = rebuild
-        onopentag: (name, attrs, createAttrStr) ->
-          if attrs.class?
-            attrs.class = ("js-#{cls}" for cls in  attrs.class.split /\s+/g).join ' '
-          "<#{name}#{createAttrStr attrs}>"
-      stream.on 'data', (file) ->
-        expect file.contents.toString()
-        .toBe """
-

-
abcdefghi

-
jkl

-

-        """
-      stream.on 'end', ->
-        done()
-      stream.write new File contents: new Buffer """
-

-
abcdefghi

-
jkl

-

-      """
-      stream.end()
+    test = (rebuildOpts, source, expected) ->
+      (done) ->
+        rebuildStream = rebuild rebuildOpts
+        rebuildStream.on 'data', (outputFile) ->
+          expect outputFile.contents.toString()
+          .toBe expected
+        rebuildStream.on 'end', ->
+          done()
+        rebuildStream.write new File contents: new Buffer source
+        rebuildStream.end()
+
+    it 'should parse and rebuild html', test
+      onopentag: (name, attrs, createAttrStr) ->
+        if attrs.class?
+          attrs.class = ("module-#{cls}" for cls in  attrs.class.split /\s+/g).join ' '
+        "<#{name}#{createAttrStr attrs}>"
+    , """
+

+
abcdefghi

+
jkl

+

+    """
+    , """
+

+
abcdefghi

+
jkl

+

+    """

   describe 'in stream mode', ->

-    test = (done, rebuildOpts, chunks, expected) ->
-      writableStream = new PassThrough
+    test = (rebuildOpts, sourceChunks, expected) ->
+      (done) ->
+        contentStream = new PassThrough

-      rebuildStream = rebuild rebuildOpts
-      rebuildStream.on 'data', (newFile) ->
-        newFile.pipe es.wait (err, data) ->
-          expect data.toString()
-          .toBe expected
-          done()
-      rebuildStream.write new File contents: writableStream
-      rebuildStream.end()
+        rebuildStream = rebuild rebuildOpts
+        rebuildStream.on 'data', (outputFile) ->
+          outputFile.pipe es.wait (err, data) ->
+            expect data.toString()
+            .toBe expected
+            done()
+        rebuildStream.write new File contents: contentStream
+        rebuildStream.end()

-      writeChunk = ->
-        if chunks.length > 0
-          chunk = chunks.shift()
-          writableStream.write new Buffer chunk
-          setTimeout writeChunk, 100
-        else
-          writableStream.end()
-      writeChunk()
+        writeChunk = ->
+          if sourceChunks.length > 0
+            contentStream.write new Buffer sourceChunks.shift()
+            setTimeout writeChunk, 100
+          else
+            contentStream.end()
+        writeChunk()

-    it 'should parse and rebuild html', (done) ->
-      test done,
+    it 'should parse and rebuild html', test
         onopentag: (name, attrs, createAttrStr) ->
           if attrs.class?
             attrs.class = ("module-#{cls}" for cls in  attrs.class.split /\s+/g).join ' '
           "<#{name}#{createAttrStr attrs}>"
       , [
-        """
\n"""
-        """
abcdefghi
\n"""
-        """
jkl
\n"""
-        """
"""
+        '
\n'
+        '
abcdefghi
\n'
+        '
jkl
\n'
+        '
'
       ]
       , """


add shift sorting for tagIds

add shift sorting for tagIds

--- both/methods/shift/shift.coffee
+++ both/methods/shift/shift.coffee
@@ -25,7 +25,13 @@

 				tmpShifts.push shift for shift in shifts.fetch()
 				tmpShifts.push _id: shiftId, start: start
-				tmpShifts.sort (a, b) -> a.start - b.start
+				tmpShifts.sort (a, b) ->
+					if a.start != b.start
+						a.start - b.start
+					else if a.tagId < b.tagId
+						-1
+					else
+						1
 				newShifts.push shift._id for shift in tmpShifts

 				newDay.shifts = newShifts


chat: list previous replies if scrolled up to top [#78432058]

--- client/Social/Activity/views/privatemessage/pane.coffee
+++ client/Social/Activity/views/privatemessage/pane.coffee
@@ -40,6 +40,19 @@
     @listController.getListView().on 'EditMessageReset', @input.bound 'focus'

     @filterLinks = null
+
+    KD.singleton('windowController').on 'ScrollHappened', @bound 'handleScroll'
+
+
+  handleScroll: do ->
+
+    previous = 0
+
+    KD.utils.throttle ->
+      current = document.body.scrollTop
+      @listPreviousReplies()  if current < 20 and current < previous
+      previous = current
+    , 200

   createInputWidget: ->


Refactored substitute

Refactored substitute

--- src/cuffs/template.coffee
+++ src/cuffs/template.coffee
@@ -102,24 +102,24 @@
         # Convenience function
         new Template(node).compile().applyContext(new Context object)

-    substitute = (str, context, getVars = false)->
+    getVars = (str)->
+        results = []
+        while ref = SUBSTITUTION_REGEX.exec(str)
+            [raw, name] = ref
+            results.push raw: raw, name: name
+        results
+
+    substitute = (str, context)->
         # Do substitution of values from a context in a string, eg
         # "foo: #{bar}" replaces `#{bar}` with `context.get('bar')`
-        retstr = str
-        vars = []

-        match = ->
-            SUBSTITUTION_REGEX.exec str
+        vars = getVars str

-        while ref = match()
-            [sub, variable] = ref
-            vars.push variable
-            value = context.get(variable)
-            retstr = retstr.replace(sub, value)
+        for {raw, name} in vars
+            str = str.replace(raw, context.get(name))

-        if getVars
-            return [retstr, vars]
-        return retstr
+        str
+

     optionize = (str, separator = ',')->
         obj = {}
@@ -132,9 +132,10 @@
         obj

     return Cuffs.Template = {
-        render: render
-        substitute: substitute
-        optionize: optionize
-        Template: Template
-        Binding: Binding
+        getVars    : getVars
+        optionize  : optionize
+        substitute : substitute
+        render     : render
+        Binding    : Binding
+        Template   : Template
     }


payment: fix error handling in `PaymentController#_runWrapper` method

--- client/Main/payment/paymentcontroller.coffee
+++ client/Main/payment/paymentcontroller.coffee
@@ -262,8 +262,7 @@
   _runWrapper: (options, callback) ->
     {fn, subscriptionTag, packTag} = options

-    kallback = (err, subscription) =>
-      return callback err  if err
+    kallback = (subscription) =>
       if subscription
         KD.remote.api.JPaymentPack.one tags: packTag, (err, pack) =>
           return callback err  if err
@@ -276,8 +275,10 @@
     group = KD.getGroup()
     if group.slug is "koding"
       @fetchSubscriptionsWithPlans tags: [subscriptionTag], (err, subscriptions) =>
-        return  if KD.showError err
+        return callback err  if err
         [subscription] = subscriptions
         kallback subscription
     else
-      @fetchGroupSubscription kallback
+      @fetchGroupSubscription (err, subscription) ->
+        return callback err  if err
+        kallback subscription


New Greetings wookie (star wars) taelon (earth final conflict)

--- support/greetings.coffee
+++ support/greetings.coffee
@@ -166,6 +166,8 @@
     [ "Beatles",        "Good morning, good morning. Good morning ah" ]
     [ "Megamind",       "Ollo?" ]
     [ "Rickroll",       "Never gonna give you up, Never gonna let you down, Never gonna run around and desert you, Never gonna make you cry, Never gonna say goodbye, Never gonna tell a lie and hurt you." ]
+    [ "Wookie",         "raaaaaahhgh raaaaaahhgh aaaaahnr"]
+    [ "Taelon",         "Sinuai Euhura"]
 ]

 class GreetingsRepository


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -1,5 +1,5 @@
 ###*
-The `Clampable` module provides helper methods to clamp object properties. This module is included by default in Gam
+The `Clampable` module provides helper methods to clamp object properties. This module is included by default in `GameObject

     player = GameObject
       x: 40


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -1,7 +1,8 @@
 ###*
 The Clampable module provides helper methods to clamp object properties.

-    player =
+    player = GameObject
+      x:

 @name Clampable
 @module


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clampable.coffee
+++ src/clampable.coffee
@@ -1,5 +1,5 @@
 ###*
-The Clampable module provides helper methods to clamp object properties.
+The `Clampable` module provides helper methods to clamp object properties.

     player = GameObject
       x: 40


Fixed ensureNonexistentPath.

Fixed ensureNonexistentPath.

--- client/landing/app/MainApp/fs/fshelper.coffee
+++ client/landing/app/MainApp/fs/fshelper.coffee
@@ -84,9 +84,9 @@
       withArgs : {path}
     , callback

-  @getSafePath = (path, callback=noop)->
+  @ensureNonexistentPath = (path, callback=noop)->
     KD.getSingleton('kiteController').run
-      method   : "fs.getSafePath"
+      method   : "fs.ensureNonexistentPath"
       withArgs : {path}
     , callback


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -220,6 +220,7 @@
           xw = target.width/2
           yw = target.height/2
           return Collision.rayRectangle source, direction,
+            x
             xw: xw
             yw: yw
         else


collision with regular bounds

collision with regular bounds

--- src/collision.coffee
+++ src/collision.coffee
@@ -220,7 +220,7 @@
           xw = target.width/2
           yw = target.height/2

-          # Convert from bounds rect to centeredBounds rect.
+          # Convert from bounds rect to centeredBounds rect
           return Collision.rayRectangle source, direction,
             x: target.x + xw
             y: target.y + yw


(- new noop) Hide reactor-tracing behind an environment variable

--- Paws/Source/reactor.coffee
+++ Paws/Source/reactor.coffee
@@ -204,7 +204,7 @@

    # Generate the form of object passed to receivers.
    @receiver_parameters: (stagee, subject, message)->
-      new Thing stagee, subject, message
+      new Thing(stagee, subject, message).rename '<receiver params>'

    # The core reactor of this implementation, `#realize` will ‘process’ a single `Staging` from this
    # `Unit`'s queue. Returns `true` if a `Staging` was acquired and in some way processed, and
@@ -212,15 +212,17 @@
    realize: ->
       return no unless staging = @next()
       {stagee, result, requestedMask} = staging
+      prior_position = stagee.position

       return yes if stagee.complete()
       return yes unless combo = reactor.advance stagee, result

       @current = stagee

-      Paws.info 'Stagee: ', stagee
-      Paws.info '   Subject: ', combo.subject if combo.subject
-      Paws.info '   Message: ', combo.message if combo.message
+      if process.env['TRACE_REACTOR']
+         Paws.alert "-- #{stagee} ← #{result}"
+         Paws.alert "   #{prior_position.with(context: yes, tag: no).toString()}" if prior_position?
+         Paws.alert "   ┗> #{combo.subject} × #{combo.message}" if combo.subject?

       # If the staging has passed #next, then it's safe to grant it the ownership it's requesting
       @table.give stagee, requestedMask if requestedMask


Remove empty file.

Remove empty file.


message create fix

message create fix

--- app/assets/javascripts/app/controllers/messages/article.js.coffee
+++ app/assets/javascripts/app/controllers/messages/article.js.coffee
@@ -80,7 +80,7 @@
         @renderHeader()

     Message.bind 'create', (record) =>
-      if record.conversation()?.eql(@current)
+      if record.conversation().eql?(@current)
         @add([record])

     @active (params = {}) ->


clean

clean

--- coffee/views/controls/position_control.coffee
+++ coffee/views/controls/position_control.coffee
@@ -72,9 +72,6 @@
     getMoveMatrix:(e) ->
         @_getMoveMatrix(@_getSnapedPoint(e))

-    getMoveTransform: (e) ->
-        SVGUtil.toD3Transform(@getMoveTransform(e)).toString()
-
     movePosition:(matrix) =>
         @getItem().attr('transform', SVGUtil.toD3Transform(matrix).toString())
         # @getItem().setMatrix(matrix)


Inlined two methods

Inlined two methods

--- core/app/backbone/views/fact_relations/vote_view.coffee
+++ core/app/backbone/views/fact_relations/vote_view.coffee
@@ -26,19 +26,13 @@

     unless is_current_opinion
       @_originalFactOpinion = @model.getFact().getFactWheel().userOpinion()
-      @_set_fact_opinion opinion
+      @model.getFact().getFactWheel().setActiveOpinionType opinion

   unset_fact_opinion: (opinion) ->
     is_current_opinion = @model.getFact().getFactWheel().isUserOpinion opinion
     if is_current_opinion
       if @_originalFactOpinion?
-        @_set_fact_opinion @_originalFactOpinion
+        @model.getFact().getFactWheel().setActiveOpinionType @_originalFactOpinion
         @_originalFactOpinion = null
       else
-        @_unset_fact_opinion opinion
-
-  _set_fact_opinion: (opinion) ->
-    @model.getFact().getFactWheel().setActiveOpinionType opinion
-
-  _unset_fact_opinion: (opinion) ->
-    @model.getFact().getFactWheel().unsetActiveOpinionType opinion
+        @model.getFact().getFactWheel().unsetActiveOpinionType opinion


beaglebone-green-wifi: Update flashing information in cofee file

Update flashing info in dashboard with regards
to leds behavior on particular boards.

Signed-off-by: Alexandru Costache <2d2dfcfad7b9832058fd41884a8955d042a85275@balena.io>

--- beaglebone-green-wifi.coffee
+++ beaglebone-green-wifi.coffee
@@ -1,11 +1,11 @@
 deviceTypesCommon = require '@resin.io/device-types/common'
 { networkOptions, commonImg, instructions } = deviceTypesCommon

-BBB_FLASH = 'Power up the <%= TYPE_NAME %> while holding down the small button near the SD slot.
-You need to keep it pressed until the blue LEDs start flashing wildly.'
+BBGW_FLASH = 'Power up the <%= TYPE_NAME %>.'
+BBGW_REMOVE_POWER = 'Wait 5 seconds after the blue leds stopped flashing wildly, then remove power from the board. On some boards the leds will shut down completely.'

 postProvisioningInstructions = [
-	instructions.BOARD_SHUTDOWN
+	BBGW_REMOVE_POWER
 	instructions.REMOVE_INSTALL_MEDIA
 	instructions.BOARD_REPOWER
 ]
@@ -24,7 +24,7 @@
 		instructions.ETCHER_SD
 		instructions.EJECT_SD
 		instructions.FLASHER_WARNING
-		BBB_FLASH
+		BBGW_FLASH
 	].concat(postProvisioningInstructions)

 	gettingStartedLink:


Allow any file extension

Allow any file extension

--- app/assets/javascripts/georgia/media.js.coffee
+++ app/assets/javascripts/georgia/media.js.coffee
@@ -11,7 +11,6 @@
   # set options here!
   $('#fileupload').fileupload('option',
     maxFileSize: 2000000,
-    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
     maxNumberOfFiles: 50
   )


Add (failing) tests for invalid remote items

--- test/post.coffee
+++ test/post.coffee
@@ -391,6 +391,50 @@
                 itemEl.attrs.should.have.property "id", "test-C-2"
                 should.exist itemEl.getChild("entry", NS.ATOM), "missing element: <entry/>"

+        it "must not be replicated if the Atom is invalid", (done) ->
+            # The minimum we need for items is author/uri, content, published, updated and id.
+            msgs = [
+                server.makePubsubEventMessage("buddycloud.ds9.sf", "buddycloud.example.org")
+                    .c("items", node: "/user/sisko@ds9.sf/posts")
+                    .c("item", id: "test-C-4")
+                    .cnode(server.makeAtom(content: "Test post C4", author_uri: "acct:sisko@ds9.sf", id: "test-C-4")
+                        .getChild("author").remove("uri").root()),
+                server.makePubsubEventMessage("buddycloud.ds9.sf", "buddycloud.example.org")
+                    .c("items", node: "/user/sisko@ds9.sf/posts")
+                    .c("item", id: "test-C-5")
+                    .cnode(server.makeAtom(content: "Test post C5", author_uri: "acct:sisko@ds9.sf", id: "test-C-5")
+                        .remove("content")),
+                server.makePubsubEventMessage("buddycloud.ds9.sf", "buddycloud.example.org")
+                    .c("items", node: "/user/sisko@ds9.sf/posts")
+                    .c("item", id: "test-C-6")
+                    .cnode(server.makeAtom(content: "Test post C6", author_uri: "acct:sisko@ds9.sf", id: "test-C-6")
+                        .remove("published")),
+                server.makePubsubEventMessage("buddycloud.ds9.sf", "buddycloud.example.org")
+                    .c("items", node: "/user/sisko@ds9.sf/posts")
+                    .c("item", id: "test-C-7")
+                    .cnode(server.makeAtom(content: "Test post C7", author_uri: "acct:sisko@ds9.sf", id: "test-C-7")
+                        .remove("updated")),
+                server.makePubsubEventMessage("buddycloud.ds9.sf", "buddycloud.example.org")
+                    .c("items", node: "/user/sisko@ds9.sf/posts")
+                    .c("item", id: "test-C-8")
+                    .cnode(server.makeAtom(content: "Test post C8", author_uri: "acct:sisko@ds9.sf", id: "test-C-8")
+                        .remove("id"))
+            ]
+            async.series [(cb) ->
+                for msgEl in msgs
+                    server.emit "stanza", msgEl.root()
+                setTimeout cb, 500
+
+            , (cb) ->
+                async.forEach [4..8], (i, cb2) ->
+                    iq = server.makePubsubGetIq("picard@enterprise.sf", "buddycloud.example.org", "retrieve-C-#{i}")
+                        .c("items", node: "/user/sisko@ds9.sf/posts")
+                        .c("item", id: "test-C-#{i}")
+
+                    server.doTest iq, "got-iq-retrieve-C-#{i}", cb2, testErrorIq "cancel", "item-not-found"
+                , cb
+            ], done
+
         it "must not be replicated if the sender is not authoritative", (done) ->
             async.series [(cb) ->
                 entryEl = server.makeAtom content: "Test post C3", author: "picard@enterprise.sf", id: "test-C-3"


Better minification.

Better minification.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -58,19 +58,19 @@
 			options:
 				require: ['./lib/validation.js']

-		uglify:
-			all:
-				src: './browserified/bundle.js'
-				dest: './browserified/bundle.min.js'
-
 		concat:
 			scripts:
 				src: [
 					'./bower_components/jquery/dist/jquery.min.js'
 					'./bower_components/bootstrap/dist/js/bootstrap.min.js'
 					'./bower_components/jquery-pjax/jquery.pjax.js'
-					'./browserified/bundle.min.js'
-				]
+					'./browserified/bundle.js'
+				]
+				dest: './assets/scripts.big.js'
+
+		uglify:
+			all:
+				src: './assets/scripts.big.js'
 				dest: './assets/scripts.js'

 		mustcontain:
@@ -183,7 +183,7 @@

 	# Custom tasks.
 	grunt.registerTask 'check', ['mustcontain', 'coffeelint', 'jshint:all']
-	grunt.registerTask 'build', ['browserify', 'uglify', 'concat']
+	grunt.registerTask 'build', ['browserify', 'concat', 'uglify']
 	grunt.registerTask 'docs', ['codo']

 	testTask = ['clean:lib_cov', 'jscoverage', 'coffeeCoverage']


Minor Grunt watch tasks note.

Minor Grunt watch tasks note.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -63,6 +63,7 @@
         ext: '.css'
         extDot: 'last'
     watch:
+      # Caveat: These watch tasks do not clean.
       css:
         files: '{src,tests}/**/*.scss'
         tasks: ['sass']


fix(templates): correct paths

fix(templates): correct paths

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -123,7 +123,8 @@

     ngtemplates:
       zentodone:
-        src: '<%= app.app %>/views/*.html'
+        cwd: '<%= app.app %>'
+        src: 'views/*.html'
         dest: '.tmp/templates.js'
         options:
           htmlmin:


Grunt watches shared/ folder for client.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -50,7 +50,7 @@
         files: ['client/**/*.styl']
         tasks: 'stylus'
       js:
-        files: ['client/app/**/*.coffee']
+        files: ['client/app/**/*.coffee', 'shared/**/*.coffee']
         tasks: 'coffee'
       vendor:
         files: ['client/vendor/**/*.js']


fix: use project coffee

fix: use project coffee

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -29,7 +29,7 @@
       specs: src: "lib/**/*.spec.js"

     #Compile coffee
-    exec: compile: cmd: "coffee --compile --transpile --output lib/ src/"
+    exec: compile: cmd: "./node_modules/coffeescript/bin/coffee --compile --transpile --output lib/ src/"

     # Run tests
     mochaTest:


Changed the port of Flo and added directory in the process

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -7,6 +7,7 @@
                 options:
                     bare: true
                 files: {
+                    'server.js': 'dev/server.coffee'
                     'dev/public/assets/dist/modules/config.js': 'dev/public/assets/app/modules/config.coffee'
                 }
             tests:
@@ -37,7 +38,7 @@
         flo:
             serve:
                 options:
-                    port: 9999
+                    port: 8000
                     dir: './'
                     glob: []
                     resolvers: [{
@@ -49,6 +50,7 @@
                             reload: true
                     }, {
                         files: [
+                            'dev/*.coffee',
                             'dev/public/assets/app/modules/*.coffee',
                             'dev/var/test-public/modules/*.coffee'
                         ]


Remove unused things.

Remove unused things.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -102,9 +102,9 @@
           processContent: (content, path) ->
             name = ///temp/(.*)\.js///.exec(path)[1]
             # data = content
-            data = content.replace /require\('/g, "req('"
+            data = content.replace /require\('/g, "loader('"
             """
-            req.register('#{name}', function(exports, localReq, module) {
+            loader.register('#{name}', function(e, r, module) {
             #{data}
             });
             """
@@ -170,70 +170,28 @@

         (function(){

-        var req = (function() {
+        var loader = (function() {
           var modules = {};
           var cache = {};

-          var has = function(object, name) {
-            return ({}).hasOwnProperty.call(object, name);
-          };
-
-          var expand = function(root, name) {
-            var results = [], parts, part;
-            if (/^\\.\\.?(\\/|$)/.test(name)) {
-              parts = [root, name].join('/').split('/');
-            } else {
-              parts = name.split('/');
-            }
-            for (var i = 0, length = parts.length; i < length; i++) {
-              part = parts[i];
-              if (part === '..') {
-                results.pop();
-              } else if (part !== '.' && part !== '') {
-                results.push(part);
-              }
-            }
-            return results.join('/');
-          };
-
-          var dirname = function(path) {
-            return path.split('/').slice(0, -1).join('/');
-          };
-
-          var localRequire = function(path) {
-            return function(name) {
-              var dir = dirname(path);
-              var absolute = expand(dir, name);
-              return req(absolute);
-            };
-          };
-
+          var dummy = function() {return function() {};};
           var initModule = function(name, definition) {
             var module = {id: name, exports: {}};
-            definition(module.exports, localRequire(name), module);
+            definition(module.exports, dummy(), module);
             var exports = cache[name] = module.exports;
             return exports;
           };

-          var req = function(name) {
-            var path = expand(name, '.');
-
-            if (has(cache, path)) return cache[path];
-            if (has(modules, path)) return initModule(path, modules[path]);
-
-            var dirIndex = expand(path, './index');
-            if (has(cache, dirIndex)) return cache[dirIndex];
-            if (has(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);
-
+          var loader = function(path) {
+            if (cache.hasOwnProperty(path)) return cache[path];
+            if (modules.hasOwnProperty(path)) return initModule(path, modules[path]);
             throw new Error('Cannot find module "' + name + '"');
           };

-          var register = function(bundle, fn) {
+          loader.register = function(bundle, fn) {
             modules[bundle] = fn;
           };
-
-          req.register = register;
-          return req;
+          return loader;
         })();

@@ -241,10 +199,10 @@
         footer: '''

         var regDeps = function(Backbone, _) {
-          req.register('backbone', function(exports, require, module) {
+          loader.register('backbone', function(exports, require, module) {
             module.exports = Backbone;
           });
-          req.register('underscore', function(exports, require, module) {
+          loader.register('underscore', function(exports, require, module) {
             module.exports = _;
           });
         };
@@ -252,14 +210,14 @@
         if (typeof define === 'function' && define.amd) {
           define(['backbone', 'underscore'], function(Backbone, _) {
             regDeps(Backbone, _);
-            return req('chaplin');
+            return loader('chaplin');
           });
         } else if (typeof module === 'object' && module && module.exports) {
           regDeps(require('backbone').Backbone, require('underscore'));
-          module.exports = req('chaplin');
+          module.exports = loader('chaplin');
         } else if (typeof require === 'function') {
           regDeps(window.Backbone, window._);
-          window.Chaplin = req('chaplin');
+          window.Chaplin = loader('chaplin');
         } else {
           throw new Error('Chaplin requires Common.js or AMD modules');
         }


Make sure the app file is loaded first

Make sure the app file is loaded first

This has the module declaration that other parts of the app require.  This will probably change as the app gets bigger and module organisation becomes more apparent.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -64,7 +64,10 @@

     jasmine:
       test:
-        src: "lib/assets/javascripts/*.js"
+        src: [
+          "lib/assets/javascripts/meducation_front_end.js"
+          "lib/assets/javascripts/*.js"
+        ]
         options:
           specs: "tmp/test/js/*Spec.js"
           helpers: [
@@ -76,7 +79,10 @@
           ]
           keepRunner: true
       coverage:
-        src: "lib/assets/javascripts/*.js"
+        src: [
+          "lib/assets/javascripts/meducation_front_end.js"
+          "lib/assets/javascripts/*.js"
+        ]
         options:
           specs: "tmp/test/js/*Spec.js"
           helpers: [


feat(grunt): use custom regex for leading quotes fix

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -248,6 +248,7 @@
     leading_quotes:
       options:
         elements: "p, li, h1, h2, h3, h4, h5, h6"
+        regex: /「|『|“|‘|（/
         class: "leading-indent-fix"
         verbose: true


Fix globbing pattern to exclude Stylus mixins from build

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -67,7 +67,7 @@
         files: [
           expand: yes
           cwd: 'src'
-          src: ['**/*.styl', '**/!_*.styl']
+          src: ['**/*.styl', '!**/_*.styl']
           dest: 'build/'
           rename: changeExt 'styl', 'css'
         ]


compile coffeescript with sourcemaps

compile coffeescript with sourcemaps

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -74,6 +74,7 @@

       options:
         bare: true
+        sourceMap: true

     # Module conversion
     # -----------------


remove versioning

remove versioning

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -56,7 +56,7 @@
 		grunt.task.run 'concat'

 		grunt.config.set('uglify.dist.dest',
-			'<%= pkg.distDirectory %>/<%= pkg.name %>-<%= pkg.version %>.js'
+			'<%= pkg.distDirectory %>/<%= pkg.name %>-latest.js'
 		)

-		grunt.task.run 'uglify'+		grunt.task.run 'uglify'


chore: do not check travis build

chore: do not check travis build

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -1,4 +1,10 @@
 module.exports = (grunt) ->
+
+  grunt.initConfig
+    'auto-release': options:
+      checkTravisBuild: false
+    'bump': options:
+      pushTo: 'upstream'

   grunt.loadTasks 'tasks'
   grunt.loadNpmTasks 'grunt-npm'


Gruntfile: Better file selectors for watch targets.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -154,10 +154,10 @@
         options          :
           reload         : yes
       html               :
-        files            : [ '*.html' ]
+        files            : [ 'public/**/*.html' ]
       src                :
-        files            : [ '**/*.coffee' ]
-        tasks            : [ 'clean', 'mkdir', 'coffee', 'coffee2closure', 'deps', 'karma:headless' ]
+        files            : [ 'src/lib/**/*.coffee' ]
+        tasks            : [ 'coffee', 'coffee2closure', 'deps', 'karma:headless' ]
       styl               :
         files            : [ 'src/styl/**/*.styl' ]
         tasks            : [ 'stylus' ]


Don't lint tasks/node_modules

Don't lint tasks/node_modules

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -123,6 +123,7 @@
         'exports/**/*.coffee'
         'src/**/*.coffee'
         'tasks/**/*.coffee'
+        '!tasks/node_modules/**/*.coffee'
         'Gruntfile.coffee'
       ]
       test: [


Tweak list of languages for Highlight.js.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -115,7 +115,8 @@
 	marked.setOptions
 		smartypants: true
 		highlight: (code) ->
-			return hljs.highlightAuto(code, ['html', 'css', 'javascript']).value
+			hl = hljs.highlightAuto(code, ['html', 'scss', 'css', 'javascript'])
+			return hl.value

 	docsMenu =


use single quotes

use single quotes

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -4,18 +4,18 @@
 # Licensed under the MIT license.
 # https://github.com/dciccale/grunt-git-committers/blob/master/LICENSE-MIT

-"use strict"
+'use strict'

 module.exports = ->

   @initConfig
     jshint:
-      all: ["tasks/*.js", "<%= nodeunit.tests %>"]
+      all: ['tasks/*.js', '<%= nodeunit.tests %>']
       options:
-        jshintrc: ".jshintrc"
+        jshintrc: '.jshintrc'

     nodeunit:
-      tests: ["test/*_test.js"]
+      tests: ['test/*_test.js']

   @loadTasks 'tasks'


Fix code style, remove debug log.

Fix code style, remove debug log.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -115,9 +115,7 @@
 	marked.setOptions
 		smartypants: true
 		highlight: (code) ->
-			html = hljs.highlightAuto(code, ['html', 'css', 'javascript'])
-			console.log html.language
-			return html.value
+			return hljs.highlightAuto(code, ['html', 'css', 'javascript']).value

 	docsMenu =
@@ -421,7 +419,7 @@
 		sequelize.sync({force: true}).success(->
 			SearchIndex.bulkCreate(rows)
 				.success(done)
-				.error((message)->
+				.error((message) ->
 					console.log 'Error when saving Dash index:', message
 					done()
 				)


dont' run integration on travis

dont' run integration on travis

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -658,7 +658,6 @@
     'test_core'
     'test_ui'
     'test_chrome'
-    'integration_test'
   ]

   taskManager.add 'everything', [


Live reload on examples

Live reload on examples

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -70,7 +70,7 @@

     regarde:
       livereloadJS:
-        files: ['test/**/*.js']
+        files: ['test/**/*.js', 'examples/vendor/*.js']
         tasks: ['livereload']
       livereloadCSS:
         files: ['examples/vendor/backbone.modal.css']


Do not install bower components each time.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -155,7 +155,7 @@
           targetDir: "<%= appConfig.dev %>/components"
           layout: "byComponent"
           cleanTargetDir: true
-          install: true
+          install: false

     karma:
       options:
@@ -226,7 +226,7 @@

   grunt.registerTask "build:dev", [
     "clean"
-    "bower" # TODO a little bit slow
+    "bower"
     "coffeelint"
     "coffee"
     "less"


build(grunt): bumps package.json only

build(grunt): bumps package.json only

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -13,6 +13,10 @@

     'auto-release': options: checkTravisBuild: false
     'npm-contributors': options: commitMessage: 'chore: update contributors'
+    bump:
+      options:
+        files: ['package.json']
+        commitFiles: ['package.json']

   # Actually load this plugin's task. Mainly for testing
   grunt.loadTasks('tasks')


[Dev] Add new command "comments:clear" on CommentListView

--- src/renderer/scripts/views/main/comment/collectionView.coffee
+++ src/renderer/scripts/views/main/comment/collectionView.coffee
@@ -14,6 +14,9 @@

         app.nsenStream.onDidChangeStream =>
             @_listenLiveEvents()
+
+        app.command.on "comments:clear", =>
+            @$el.empty()

         app.contextMenu.add "body", [
              {


refresh state correctly

refresh state correctly

--- lib/build/build-state-view.coffee
+++ lib/build/build-state-view.coffee
@@ -84,7 +84,7 @@
     @socket.on 'update', (job) =>
       console.log "task updated"
       @find('.task-state').text job.state
-      @updateQRCode(job.data.platform) if job.state == 'complete'
+      @showState(job)

     @socket.on 'stdout', (out) =>
       out_element = @find('#out')
@@ -117,7 +117,6 @@
   showState: (task) ->
     @loading.show()

-    @loading.hide() if task.state == 'failed'
     switch task.state
       when 'complete'
         @loading.hide()


fixed cloneSubplan bug in when there are consecutive barriers and faceting

--- src/gg/scale/scale.coffee
+++ src/gg/scale/scale.coffee
@@ -214,6 +214,8 @@
      md = @domain()
      unless @domainSet
        if @domainUpdated and md? and md.length == 2
+         if _.isNaN(domain[0]) or _.isNaN(domain[1])
+           throw Error("domain is invalid: #{domain}")
          @domain [
            Math.min md[0], domain[0]
            Math.max md[1], domain[1]


update gruntfile to hide system tests

update gruntfile to hide system tests

--- GruntFile.coffee
+++ GruntFile.coffee
@@ -100,7 +100,8 @@
   grunt.loadNpmTasks 'grunt-http-server'

   grunt.registerTask 'test-unit', ['karma:unit']
-  grunt.registerTask 'test-system', ['http-server','karma:e2e']
+  # grunt.registerTask 'test-system', ['http-server','karma:e2e']

-  grunt.registerTask 'default', [ 'clean', 'bower','coffee', 'uglify', 'copy:*','test-unit', 'test-system' ]
+  # grunt.registerTask 'default', [ 'clean', 'bower','coffee', 'uglify', 'copy:*','test-unit', 'test-system' ]
+  grunt.registerTask 'default', [ 'clean', 'bower','coffee', 'uglify', 'copy:*','test-unit' ]


Compile nu.nl javascript and css

Compile nu.nl javascript and css

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -69,10 +69,14 @@
           'build/js/loader/loader_bookmarklet.js'
         ]
         dest: 'build/factlink_loader_bookmarklet.js'
+      publisher:
+        src:  'build/js/publisher_poc/nu.js'
+        dest: 'build/nu.js'
     less:
       build:
         files:
           'build/css/basic.css': 'app/css/basic.less'
+          'build/css/publisher_poc/nu.nl.css': 'app/css/publisher_poc/nu.nl.less'
     cssmin:
       build:
         options:


Actually run tests on travis-ci

Actually run tests on travis-ci

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -41,4 +41,4 @@
   grunt.registerTask('test', 'mochacov:test')

   grunt.registerTask('default', 'watch')
-  grunt.registerTask('travis', 'check')
+  grunt.registerTask('travis', 'check', 'test')


fix(grunt): Fixed grunt coffee watch task not compiling code correctly

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -168,7 +168,7 @@
     watch:
       js:
         files: ["src/**/*.coffee", "src/*.coffee"]
-        tasks: ["coffee", "concat:appJs", "clean", "copy:public"]
+        tasks: ["coffee", "concat:jqueryui", "concat:appJs", "clean", "copy:public"]
         options: interrupt: true
       css:
         files: ["src/css/*.styl"]


Copy index.html to 404.html

Copy index.html to 404.html

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -56,6 +56,9 @@
           cwd:      '<%= CLIENT_DIR %>'
           src:      '<%= ALL_FILES %>'
           dest:     '<%= BUILD_DIR %>'
+        ,
+          src:      '<%= CLIENT_DIR %>/index.html'
+          dest:     '<%= CLIENT_DIR %>/404.html'
         ]

       # Make components HTTP-accessible
@@ -79,6 +82,9 @@
           cwd:      '<%= CLIENT_DIR %>'
           src:      '<%= HTML_FILES %>'
           dest:     '<%= BUILD_DIR %>'
+        ,
+          src:      '<%= CLIENT_DIR %>/index.html'
+          dest:     '<%= CLIENT_DIR %>/404.html'
         ]

     # Validate app `client` and `server` JS
@@ -174,11 +180,11 @@

     # Output for optimized app index
     usemin:
-      html:         '<%= BUILD_DIR %>/index.html'
+      html:         [ '<%= BUILD_DIR %>/index.html', '<%= BUILD_DIR %>/404.html' ]

     # Input for optimized app index
     useminPrepare:
-      html:         '<%= BUILD_DIR %>/index.html'
+      html:         [ '<%= BUILD_DIR %>/index.html', '<%= BUILD_DIR %>/404.html' ]

   # Dependencies


Rename files with underscore to dash.

Rename files with underscore to dash.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -90,11 +90,11 @@
       options:
         singleRun: not grunt.option('debug')
       unit:
-        configFile: 'test/conf/karma_conf.coffee'
+        configFile: 'test/conf/karma-conf.coffee'

     protractor:
       e2e:
-        configFile: 'test/conf/protractor_conf.coffee'
+        configFile: 'test/conf/protractor-conf.coffee'

     markdown:
       compile:


Fix browserstack build error handling

Fix browserstack build error handling

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -91,9 +91,9 @@
       setCommitStatus(sha, 'pending')
         .then(browserstack(grunt))
         .then(
-          (output) ->
-            setCommitStatus(sha, 'success')
-          (error) ->
-            setCommitStatus(sha, 'failure')
-              .then -> throw error
-        ).then(done, -> done(3))
+          (output) -> setCommitStatus(sha, 'success')
+          (error) -> setCommitStatus(sha, 'failure').then(-> Promise.reject(error))
+        ).then(done, ->
+          grunt.log.error(error.message)
+          done(1)
+        )


Add release task

Add release task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -72,6 +72,20 @@
       jasmine:
         command: "jasmine-node --verbose --captureExceptions test"

+    bump:
+      options:
+        files: ['package.json']
+        updateConfigs: ['pkg']
+        commit: true
+        commitMessage: 'Bump version to %VERSION%'
+        commitFiles: ['-a']
+        createTag: true
+        tagName: 'v%VERSION%'
+        tagMessage: 'Version %VERSION%'
+        push: true
+        pushTo: 'origin'
+        gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
+
   # load plugins that provide the tasks defined in the config
   grunt.loadNpmTasks "grunt-coffeelint"
   grunt.loadNpmTasks "grunt-contrib-clean"
@@ -86,3 +100,6 @@
   grunt.registerTask "coverage", ["build", "shell:coverage"]
   grunt.registerTask "test", ["build", "shell:jasmine"]
   grunt.registerTask "default", ["test"]
+  grunt.registerTask 'release', 'Release a new version, push it and publish it', (target) ->
+    target = 'patch' unless target
+    grunt.task.run "bump-only:#{target}", 'test', 'bump-commit'


feat(Gruntfile.coffee): #898 - reference ajax requester for initiating S3 MPU requests

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -68,6 +68,7 @@
         './client/js/s3/uploader.js',
         './client/js/s3/policysignature.ajax.requester.js',
         './client/js/s3/uploadsuccess.ajax.requester.js',
+        './client/js/s3/multipart.initiate.ajax.requester.js',
         './client/js/s3/handler.xhr.js',
         './client/js/s3/handler.form.js',
         './client/js/s3/jquery-plugin.js'


Add some comments to the vulcanize helper function

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -983,6 +983,10 @@

 fullyVulcanize = (basePath, srcFilename, destFilename, browserify = false) ->
   tasks = []
+
+  # this adds the rule to the task to the global gruntConfig object as well as
+  # adding the text needed to run it in a rule to the list of rules that will be
+  # returned
   addTask = (component, task, rule) ->
     gruntConfig[component][task] = rule
     tasks.push(component + ':' + task)
@@ -992,10 +996,14 @@
   intermediateFile = path.join(realBasePath, destFilename + '-inline.html')
   destFile = path.join(realBasePath, destFilename + '.html')

+  # The basic vulcanize tasks, we do both steps in order to get all the
+  # javascript into a separate file
   addTask('vulcanize', destFile + 'Inline', doVulcanize(srcFile, intermediateFile, true, false))
   addTask('vulcanize', destFile + 'Csp', doVulcanize(intermediateFile, destFile, false, true))

   if browserify
+    # If we need to brewserify the file, there also needs to be a step to replace
+    # some of the strings in the vulcanized html file to refer to the static version
     browserifyPath = path.join(basePath, destFilename)
     addTask('string-replace', destFile + 'Vulcanized', finishVulcanized(realBasePath, destFilename))
     addTask('browserify', browserifyPath, Rule.browserify(browserifyPath, {}))


Fix build bug with latest lodash

Fix build bug with latest lodash

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -22,7 +22,7 @@
                 # "<%= grunt.template.today('yyyy-mm-dd HH:mm') %>\n" +
                 "<%= pkg.homepage ? '  * ' + pkg.homepage + '\\n' : '' %>" +
                 "  * Copyright (c) <%= grunt.template.today('yyyy') %> <%= pkg.author.name %>;" +
-                " Licensed <%= _.pluck(pkg.licenses, 'type').join(', ') %> */\n"
+                " Licensed <%= _.map(pkg.licenses, 'type').join(', ') %> */\n"

     clean:
         build:


do a build before a test run

do a build before a test run

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -219,6 +219,7 @@

   # Test
   grunt.registerTask "test", [
+    "build"
     "validate"
     "shell:server"
     "shell:sleep" # Allow server to get completely ready