Update fr.coffee v0.9 (#5046)

Update fr.coffee v0.9 (#5046)

* Update fr.coffee v0.9

* Update fr.coffee

--- app/locale/fr.coffee
+++ app/locale/fr.coffee
@@ -2538,7 +2538,7 @@
 #    are_you_missing_a: "Are you missing a '$1' after '$2'? "
 #    your_parentheses_must_match: "Your parentheses must match."

-#  apcsp:
+  apcsp:
 #    syllabus: "AP CS Principles Syllabus"
 #    syllabus_description: "Use this resource to plan CodeCombat curriculum for your AP Computer Science Principles class."
 #    computational_thinking_practices: "Computational Thinking Practices"
@@ -2569,60 +2569,60 @@
 #    unit_7: "Unit 7: Personal & Global Impact"
 #    unit_7_activity_1: "Unit 7 Activity: Personal & Global Impact"
 #    unit_7_activity_2: "Unit 7 Activity: Crowdsourcing"
-#    unit_8: "Unit 8: Performance Tasks"
-#    unit_8_description: "Prepare students for the Create Task by building their own games and practicing key concepts."
-#    unit_8_activity_1: "Create Task Practice 1: Game Development 1"
-#    unit_8_activity_2: "Create Task Practice 2: Game Development 2"
-#    unit_8_activity_3: "Create Task Practice 3: Game Development 3"
+    unit_8: "Unité 8 : Tâches de rendement"
+    unit_8_description: "Préparez les élèves à la tâche de création en construisant leurs propres jeux et en pratiquant les concepts clés."
+    unit_8_activity_1: "Créer la tâche pratique 1: Développement du jeu 1"
+    unit_8_activity_2: "Créer la tâche pratique 2: Développement du jeu 2"
+    unit_8_activity_3: "Créer la tâche pratique 3: Développement du jeu 3"
 #    unit_9: "Unit 9: AP Review"
 #    unit_10: "Unit 10: Post-AP"
-#    unit_10_activity_1: "Unit 10 Activity: Web Quiz"
-
-#  parent_landing:
-#    slogan_quote: "\"CodeCombat is really fun, and you learn a lot.\""
+    unit_10_activity_1: "Activité de l'unité 10 : Jeu-questionnaire en ligne"
+
+  parent_landing:
+    slogan_quote: "\"CodeCombat est vraiment amusant, et vous apprenez beaucoup.\""
 #    quote_attr: "5th Grader, Oakland, CA"
-#    refer_teacher: "Refer a Teacher"
-#    focus_quote: "Unlock your child's future"
-#    value_head1: "The most engaging way to learn typed code"
-#    value_copy1: "CodeCombat is child’s personal tutor. Covering material aligned with national curriculum standards, your child will program algorithms, build websites and even design their own games."
-#    value_head2: "Building critical skills for the 21st century"
-#    value_copy2: "Your kids will learn how to navigate and become citizens in the digital world. CodeCombat is a solution that enhances your child’s critical thinking and resilience."
-#    value_head3: "Heroes that your child will love"
-#    value_copy3: "We know how important fun and engagement is for the developing brain, so we’ve packed in as much learning as we can while wrapping it up in a game they'll love."
-#    dive_head1: "Not just for software engineers"
-#    dive_intro: "Computer science skills have a wide range of applications. Take a look at a few examples below!"
-#    medical_flag: "Medical Applications"
-#    medical_flag_copy: "From mapping of the human genome to MRI machines, coding allows us to understand the body in ways we’ve never been able to before."
-#    explore_flag: "Space Exploration"
-#    explore_flag_copy: "Apollo got to the Moon thanks to hardworking human computers, and scientists use computer programs to analyze the gravity of planets and search for new stars."
-#    filmaking_flag: "Filmmaking and Animation"
-#    filmaking_flag_copy: "From the robotics of Jurassic Park to the incredible animation of Dreamworks and Pixar, films wouldn’t be the same without the digital creatives behind the scenes."
-#    dive_head2: "Games are important for learning"
-#    dive_par1: "Multiple studies have found that game-based learning promotes"
-#    dive_link1: "cognitive development"
-#    dive_par2: "in kids while also proving to be"
-#    dive_link2: "more effective"
-#    dive_par3: "in helping students"
-#    dive_link3: "learn and retain knowledge"
-#    dive_par4: ","
-#    dive_link4: "concentrate"
-#    dive_par5: ", and perform at a higher level of achievement."
-#    dive_par6: "Game based learning is also good for developing"
-#    dive_link5: "resilience"
-#    dive_par7: ", cognitive reasoning, and"
-#    dive_par8: ". Science is just telling us what learners already know. Children learn best by playing."
-#    dive_link6: "executive functions"
-#    dive_head3: "Team up with teachers"
-#    dive_3_par1: "In the future, "
-#    dive_3_link1: "coding is going to be as fundamental as learning to read and write"
-#    dive_3_par2: ". We’ve worked closely with teachers to design and develop our content, and we can't wait to get your kids learning. Educational technology programs like CodeCombat work best when the teachers implement them consistently. Help us make that connection by introducing us to your child’s teachers!"
-#    mission: "Our mission: to teach and engage"
-#    mission1_heading: "Coding for today's generation"
-#    mission2_heading: "Preparing for the future"
-#    mission3_heading: "Supported by parents like you"
-#    mission1_copy: "Our education specialists work closely with teachers to meet children where they are in the educational landscape. Kids learn skills that can be applied outside of the game because they learn how to solve problems, no matter what their learning style is."
-#    mission2_copy: "A 2016 survey showed that 64% of girls in 3-5th grade want to learn how to code. There were 7 million job openings in 2015 required coding skills. We built CodeCombat because every child should be given a chance to create their best future."
-#    mission3_copy: "At CodeCombat, we’re parents. We’re coders. We’re educators. But most of all, we’re people who believe in giving our kids the best opportunity for success in whatever it is they decide to do."
+    refer_teacher: "Référer un enseignant"
+    focus_quote: "Déverrouillez l'avenir de votre enfant"
+    value_head1: "La façon la plus engageante d'apprendre le code dactylographié"
+    value_copy1: "CodeCombat est le tuteur personnel de l'enfant. En couvrant du matériel conforme aux normes nationales du curriculum, votre enfant programmera des algorithmes, construira des sites Web et concevra même ses propres jeux."
+    value_head2: "Développer les compétences essentielles pour le XXIe siècle"
+    value_copy2: "Vos enfants apprendront à naviguer et à devenir des citoyens dans le monde numérique. CodeCombat est une solution qui améliore la pensée critique et la résilience de votre enfant."
+    value_head3: "Des héros que votre enfant aimera"
+    value_copy3: "Nous savons à quel point le plaisir et l'engagement sont importants pour le développement du cerveau, alors nous avons fait le maximum d'apprentissage tout en l'enveloppant dans un jeu qu'ils vont adorer."
+    dive_head1: "Pas seulement pour les ingénieurs en logiciel"
+    dive_intro: "Les compétences en informatique ont un large éventail d'applications. Jetez un coup d'œil à quelques exemples ci-dessous !"
+    medical_flag: "Applications médicales"
+    medical_flag_copy: "De la cartographie du génome humain à l'IRM, le codage nous permet de comprendre le corps comme jamais auparavant."
+    explore_flag: "Exploration spatiale"
+    explore_flag_copy: "Apollo s'est rendu sur la Lune grâce à des ordinateurs humains laborieux, et les scientifiques utilisent des programmes informatiques pour analyser la gravité des planètes et rechercher de nouvelles étoiles."
+    filmaking_flag: "Cinéma et animation"
+    filmaking_flag_copy: "De la robotique de Jurassic Park à l'incroyable animation de Dreamworks et Pixar, les films ne seraient pas les mêmes sans les créateurs numériques en coulisses."
+    dive_head2: "Les jeux sont importants pour l'apprentissage"
+    dive_par1: "De nombreuses études ont montré que l'apprentissage basé sur le jeu favorise"
+    dive_link1: "développement cognitif"
+    dive_par2: "chez les enfants tout en s'avérant également être"
+    dive_link2: "plus efficace"
+    dive_par3: "pour aider les étudiants"
+    dive_link3: "apprendre et conserver les connaissances"
+    dive_par4: ","
+    dive_link4: "concentrateur"
+    dive_par5: ", et d'atteindre un niveau de performance plus élevé."
+    dive_par6: "L'apprentissage basé sur le jeu est également bon pour développe"
+    dive_link5: "persévérance"
+    dive_par7: ", le raisonnement cognitif, et"
+    dive_par8: ". La science ne fait que nous dire ce que les apprenants savent déjà. Les enfants apprennent mieux en jouant."
+    dive_link6: "fonctions exécutives"
+    dive_head3: "Faites équipe avec les enseignants"
+    dive_3_par1: "Dans le futur, "
+    dive_3_link1: "le codage sera aussi fondamental que l'apprentissage de la lecture et de l'écriture"
+    dive_3_par2: ". Nous avons travaillé en étroite collaboration avec les enseignants pour concevoir et développer notre contenu, et nous avons hâte que vos enfants apprennent. Les programmes de technologie éducative comme CodeCombat fonctionnent mieux lorsque les enseignants les mettent en œuvre de manière cohérente. Aidez-nous à établir ce lien en nous présentant aux enseignants de votre enfant !"
+    mission: "Notre mission : enseigner et engager"
+    mission1_heading: "Codage pour la génération actuelle"
+    mission2_heading: "Préparer l'avenir"
+    mission3_heading: "Soutenu par des parents comme vous"
+    mission1_copy: "Nos spécialistes de l'éducation travaillent en étroite collaboration avec les enseignants pour rencontrer les enfants là où ils se trouvent dans le paysage éducatif. Les enfants apprennent des compétences qui peuvent être appliquées à l'extérieur du jeu parce qu'ils apprennent à résoudre des problèmes, quel que soit leur style d'apprentissage."
+    mission2_copy: "Une enquête réalisée en 2016 a montré que 64% des filles de la 3ème à la 5ème année veulent apprendre à coder. En 2015, il y avait 7 millions d'emplois vacants qui nécessitaient des compétences en codage. Nous avons construit CodeCombat parce que chaque enfant devrait avoir une chance de créer son meilleur avenir."
+    mission3_copy: "Chez CodeCombat, on est parents. Nous sommes des codeurs. Nous sommes des éducateurs. Mais par-dessus tout, nous sommes des gens qui croient qu'il faut donner à nos enfants les meilleures chances de réussite dans tout ce qu'ils décident de faire."

   parent_modal:
     refer_teacher: "Référence Enseignant"


Diplomat patch Ukrainian

Diplomat patch Ukrainian

дрібні недоліки "з першого рівнЯ" - рівнЮ (#5065)

--- app/locale/uk.coffee
+++ app/locale/uk.coffee
@@ -14,7 +14,7 @@
     top_screenshots_hint: "Учні пишуть код і бачать усі зміни наживо"
     designed_with: "Зважаючи на потреби вчителя"
     real_code: "Справжній код"
-    from_the_first_level: "з першого рівня"
+    from_the_first_level: "з першого рівню"
     getting_students: "Написання коду самостійно сприяє вивченню синтаксису та структури програми."
     educator_resources: "Путівник по курсах"
     course_guides: "і додаткові матеріали"


Close #15 jsonp: true option bug

Close #15 jsonp: true option bug

--- stl/ajax/src/jsonp.coffee
+++ stl/ajax/src/jsonp.coffee
@@ -1,7 +1,7 @@
 #
 # JSONP tunnel for the 'Ajax' interface
 #
-# Copyright (C) 2011 Nikolay Nemshilov
+# Copyright (C) 2011-2012 Nikolay Nemshilov
 #
 class JSONP

@@ -14,7 +14,7 @@
     @ajax  = ajax
     @name  = '__lovely_jsonp' + new Date().getTime()
     @param = ajax.options.jsonp
-    @param = 'callback' if typeof(@jsonp) is 'string'
+    @param = 'callback' if typeof(@jsonp) isnt 'string'
     @param += "="+ @name

     @script = new Element 'script',


remove unused function

remove unused function

--- lib/breakpoint-store.coffee
+++ lib/breakpoint-store.coffee
@@ -37,8 +37,5 @@
         return breakpoint
     return null

-  currentBreakpoints: ->
-    console.log breakpoint for breakpoint in @breakpoints
-
   clear: () ->
     @toggle breakpoint for breakpoint in @breakpoints


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/color.coffee
+++ test/color.coffee
@@ -54,8 +54,8 @@
 test "Color should parse length 4 hex string", ->
   color = Color('b8f0')
   equals color.r(), 187
-  equals color.g(), 255
-  equals color.b(), 68
+  equals color.g(), 68
+  equals color.b(), 255
   equals color.a(), 0.0

 test "Color should parse length 4 hex string with leading #", ->


Added comment

Added comment


DE671:Merge from Development

DE671:Merge from Development

--- c3/app/assets/javascripts/s7_employment/g8_aboutExpenses.coffee
+++ c3/app/assets/javascripts/s7_employment/g8_aboutExpenses.coffee
@@ -1,40 +0,0 @@
-window.initEvents = (
-        haveExpensesForJobYes, haveExpensesForJobNo, whatExpensesForJob,
-        payAnyoneToLookAfterChildrenYes,payAnyoneToLookAfterChildrenNo,
-        nameLookAfterChildren,howMuchLookAfterChildren, howOftenLookAfterChildren,
-        relationToYouLookAfterChildren,relationToPersonLookAfterChildren,
-        payAnyoneToLookAfterPersonYes,payAnyoneToLookAfterPersonNo,
-        nameLookAfterPerson,howMuchLookAfterPerson, howOftenLookAfterPerson,
-        relationToYouLookAfterPerson,relationToPersonLookAfterPerson) ->
-
-  $("#" + haveExpensesForJobYes).on "click", ->
-    $("#haveExpensesForJobWrap").slideDown 500
-    $("#haveExpensesForJobWrap").css('display', "block")
-
-  $("#" + haveExpensesForJobNo).on "click", ->
-    $("#haveExpensesForJobWrap").slideUp 500, ->
-      $("#" + whatExpensesForJob).val("")
-
-  $("#" + payAnyoneToLookAfterChildrenYes).on "click", ->
-    $("#payToLookAfterChildrenJobWrap").slideDown 500
-    $("#payToLookAfterChildrenJobWrap").css('display', "block")
-
-  $("#" + payAnyoneToLookAfterChildrenNo).on "click", ->
-    $("#payToLookAfterChildrenJobWrap").slideUp 500, ->
-      $("#" + nameLookAfterChildren).val("")
-      $("#" + howMuchLookAfterChildren).val("")
-      $("#" + howOftenLookAfterChildren).val("")
-      $("#" + relationToYouLookAfterChildren).val("")
-      $("#" + relationToPersonLookAfterChildren).val("")
-
-  $("#" + payAnyoneToLookAfterPersonYes).on "click", ->
-    $("#payToLookAfterPersonJobWrap").slideDown 500
-    $("#payToLookAfterPersonJobWrap").css('display', "block")
-
-  $("#" + payAnyoneToLookAfterPersonNo).on "click", ->
-    $("#payToLookAfterPersonJobWrap").slideUp 500, ->
-      $("#" + nameLookAfterPerson).val("")
-      $("#" + howMuchLookAfterPerson).val("")
-      $("#" + howOftenLookAfterPerson).val("")
-      $("#" + relationToYouLookAfterPerson).val("")
-      $("#" + relationToPersonLookAfterPerson).val("")


Revert accidental commit

Revert accidental commit

--- library/nucleus/stubs.coffee
+++ library/nucleus/stubs.coffee
@@ -58,7 +58,7 @@
     # usually means partial replacing contents with the new contents.
     # This HTTP method nicely maps to UPDATE method of the storages.
     # Use this method to partially replace the contents of resources.
-    @PATCH: @prototype.unsupported
+    PATCH: @prototype.unsupported

     # Delete the contents of the resources at the establushed path. It
     # generally should destroy the contents of the resource for good.


link to editing for plan when in draft

link to editing for plan when in draft

--- tutor/src/components/course-calendar/plan-display.cjsx
+++ tutor/src/components/course-calendar/plan-display.cjsx
@@ -1,8 +1,9 @@
 React = require 'react'
-Router = require 'react-router'
 camelCase = require 'camelcase'
 BS = require 'react-bootstrap'
 _ = require 'underscore'
+
+TutorLink = require '../link'

 DisplayProperties =
   plan: React.PropTypes.shape(
@@ -89,11 +90,11 @@
       onMouseEnter={_.partial(setHover, true)}
       onMouseLeave={_.partial(setHover, false)}
       ref='plan'>
-      <Router.Link
+      <TutorLink
         to={linkTo}
         params={params}>
           {label}
-      </Router.Link>
+      </TutorLink>
     </div>


Updating tests

Updating tests

--- test/index.coffee
+++ test/index.coffee
@@ -44,3 +44,4 @@
   #   assert.strictEqual actual, expected, button.data('displayname') + ' email populating in modal form'
   #   #clean up after each test
   #   modal.modal('hide')
+


We need to be able to populate the collection dynamically for sub-resources

--- lib/resource-juggling.coffee
+++ lib/resource-juggling.coffee
@@ -23,34 +23,37 @@

   options.toJSON ?= (items, req) -> items

-  seek = (constraints, callback) ->
+  seek = (request, constraints, callback) ->
     if collectionIsRelation
-      options.collection
+      collection = options.collection
+      if typeof options.collection is 'function'
+        collection = options.collection request
+      collection
         where: constraints
       , (err, items) ->
         items = [] unless items
         callback err, items
       return

-    constraints =
+    options.model.all
       where: constraints
-    options.model.all constraints, (err, items) ->
+    , (err, items) ->
       items = [] unless items
       callback err, items

   resource =
     id: options.urlName

-    load: (where, callback) ->
+    load: (request, where, callback) ->
       whereQuery = {}
       whereQuery[options.where] = where
-      seek whereQuery, (err, items) ->
+      seek request, whereQuery, (err, items) ->
         return callback err if err
         callback null, items[0]

     index:
       html: (req, res) ->
-        seek {}, (err, items) ->
+        seek req, {}, (err, items) ->
           if options.addPlaceholderForEmpty and items.length is 0
             blankItem = {}
             for property, defs of options.schema.definitions[options.name].properties
@@ -63,11 +66,18 @@
               items: items
               as: 'item'
       json: (req, res) ->
-        seek {}, (err, items) ->
+        seek req, {}, (err, items) ->
           res.send options.toJSON items, req
       default: exports.contentNegotiator

     create: (req, res) ->
+      if collectionIsRelation
+        newItem = options.collection.build()
+        for property, value of req.body
+          newItem[property] = value
+        newItem.save (err, item) ->
+          res.send options.toJSON item, req
+        return
       options.collection.create req.body, (err, item) ->
         res.send options.toJSON item, req

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

     destroy: (req, res) ->
       req[options.urlName].destroy (err, item) ->
-        res.send options.toJSON item, req
+        res.send options.toJSON req[options.urlName], req

     show:
       html: (req, res) ->


:u5272::saxophone: Updated in browser at strd6.github.io/editor

--- symmetry.coffee
+++ symmetry.coffee
@@ -1,7 +1,9 @@

 mirror = (size, flip) ->
-  midpoint = Point (size.width - 1)/2, (size.height - 1)/2
-
+  midpoint = Point size.width/2, size.height/2
+
+  console.log midpoint
+
   Matrix.translate(midpoint.x, midpoint.y).concat(flip).concat(Matrix.translate(-midpoint.x, -midpoint.y))

 module.exports = Symmetry =


Call the function "http"

Call the function "http"

--- test/tests.coffee
+++ test/tests.coffee
@@ -1,23 +1,23 @@
 assert = chai.assert
-request = httpplease
+http = httpplease
 plugins = httppleaseplugins

 testServerUrl = 'http://localhost:4001'

 describe 'httpplease', ->
   it 'performs a get request', (done) ->
-    request.get "#{ testServerUrl }/getjson", (err, res) ->
+    http.get "#{ testServerUrl }/getjson", (err, res) ->
       assert.equal res.text, JSON.stringify(hello: 'world')
       done()

   it 'identifies errors', (done) ->
-    request.get "#{ testServerUrl }/404", (err, res) ->
+    http.get "#{ testServerUrl }/404", (err, res) ->
       assert.equal err.status, 404
       assert err.isHttpError
       done()

   it 'obeys the errorOn404 option', (done) ->
-    request.get
+    http.get
       url: "#{ testServerUrl }/404"
       errorOn404: false
       (err, res) ->
@@ -30,36 +30,36 @@
       url: "#{ testServerUrl }/headers"
       headers:
         hello: 'world'
-    request.get req, (err, res) ->
+    http.get req, (err, res) ->
       json = JSON.parse res.text
       assert.equal json.hello, 'world'
       done()

   describe 'defaults', ->
     it 'adds defaults', ->
-      assert.equal request.defaults(dummy: 5).defaults().dummy, 5
+      assert.equal http.defaults(dummy: 5).defaults().dummy, 5

-    it "doesn't mutate the request function", ->
-      request.defaults dummy: 5
-      assert.isUndefined request.defaults().dummy
+    it "doesn't mutate the http function", ->
+      http.defaults dummy: 5
+      assert.isUndefined http.defaults().dummy

   describe 'use', ->
     it 'adds a plugin', ->
-      startCount = request.plugins().length
-      assert.equal request.use({}).plugins().length, startCount + 1
+      startCount = http.plugins().length
+      assert.equal http.use({}).plugins().length, startCount + 1

-    it "doesn't mutate the request function", ->
-      startCount = request.plugins().length
-      request.use {}
-      assert.equal request.plugins().length, startCount
+    it "doesn't mutate the http function", ->
+      startCount = http.plugins().length
+      http.use {}
+      assert.equal http.plugins().length, startCount

   describe 'bare', ->
-    it 'creates a request function without plugins', ->
-      assert.equal request.use({}).bare().plugins().length, 0
+    it 'creates a http function without plugins', ->
+      assert.equal http.use({}).bare().plugins().length, 0

 describe 'plugins', ->
   it 'is used for error responses', (done) ->
-    request
+    http
       .use plugins.jsonparser
       .get "#{ testServerUrl }/404", (err, res) ->
         assert.deepEqual err.body, sad: 'panda'
@@ -67,7 +67,7 @@

   describe 'jsonparser', ->
     it 'parses json responses', (done) ->
-      request
+      http
         .use plugins.jsonparser
         .get "#{ testServerUrl }/getjson", (err, res) ->
           assert.deepEqual res.body, hello: 'world'


Correct minor mistakes

Correct minor mistakes

--- library/schema/domain.coffee
+++ library/schema/domain.coffee
@@ -110,7 +110,7 @@
 module.exports.must = must = (pointer) -> (key) ->
     isObject = @properties? or patternProperties?
     assert _.isFunction(pointer), "incorrect pointer for must"
-    assert _.isString(key), "invalid name of property: #{k}"
+    assert _.isString(key), "invalid name of property: #{key}"
     assert isObject, "must can only be used on object"
     required = @required if _.has this, "required"
     @required = (required or []).concat key


vm product form: make #setContents more generic

--- client/app/Applications/Environments.kdapplication/views/vms/vmproductform.coffee
+++ client/app/Applications/Environments.kdapplication/views/vms/vmproductform.coffee
@@ -24,13 +24,12 @@
       when 1
         [subscription] = subscriptions
         @collectData { subscription }
-        @emit 'PackOfferingRequested', subscription
       else
         @showForm 'choice'

-  setContents: (packs) ->
-    @showForm 'pack choice'
-    (@getForm 'pack choice').setContents packs
+  setContents: (type, contents) -> switch type
+    when 'packs'
+      (@getForm 'pack choice').setContents contents

   createChoiceForm: -> new KDView partial: 'this is a plan choice form'

@@ -49,7 +48,8 @@
     @addForm 'upgrade', upgradeForm, ['plan', 'subscription']

     packChoiceForm = @createPackChoiceForm()
-    @forwardEvent packChoiceForm, 'PackOfferingRequested'
+    packChoiceForm.on 'Activated', => @emit 'PackOfferingRequested'
+
     packChoiceForm.on 'PackSelected', (pack) =>
       @checkUsageLimits pack, (err, usage) =>
         @collectData { pack }


examples/test updated a little

examples/test updated a little

--- examples/test.coffee
+++ examples/test.coffee
@@ -21,8 +21,8 @@
 			Then "it should sound good", ->
 				voice.should.eql 'good'

-			And "it should", ->
-			But "it should", ->
+			And "it should do this", ->
+			But "it shouldn't do that", ->

 			Describe '/test/describe.spec', ->


need to require index for coverage to kick in

--- test/get.coffee
+++ test/get.coffee
@@ -1,4 +1,4 @@
-quest  = require "#{__dirname}/../lib/quest"
+quest  = require "#{__dirname}/../index"
 assert = require 'assert'
 _ = require 'underscore'


Project.scan excludes ignored directories

--- src/app/project.coffee
+++ src/app/project.coffee
@@ -16,6 +16,7 @@
   autoIndent: null
   softTabs: null
   softWrap: null
+  ignoredPathRegexes: null

   constructor: (path) ->
     @setPath(path)
@@ -23,6 +24,10 @@
     @setTabText('  ')
     @setAutoIndent(true)
     @setSoftTabs(true)
+    @ignoredPathRegexes = [
+      /\.DS_Store$/
+      /(^|\/)\.git(\/|$)/
+    ]

   getPath: ->
     @rootDirectory?.path
@@ -55,7 +60,10 @@
     deferred

   ignorePath: (path) ->
-    fs.base(path).match(/\.DS_Store/) or path.match(/(^|\/)\.git(\/|$)/)
+    _.find @ignoredPathRegexes, (regex) -> path.match(regex)
+
+  ignorePathRegex: ->
+    @ignoredPathRegexes.map((regex) -> "(#{regex.source})").join("|")

   resolve: (filePath) ->
     filePath = fs.join(@getPath(), filePath) unless filePath[0] == '/'
@@ -125,7 +133,13 @@

   scan: (regex, iterator) ->
     regex = new RegExp(regex.source, 'g')
-    command = "grep --null --perl-regexp --with-filename --line-number --recursive --regexp=\"#{regex.source}\" #{@getPath()}"
+    commands = [
+      "find \"#{@getPath()}\" -type f"
+      "grep --perl-regexp --invert-match --regexp=\"#{@ignorePathRegex()}\""
+      "xargs grep --null --perl-regexp --with-filename --line-number --recursive --regexp=\"#{regex.source}\""
+    ]
+
+    command = commands.join(" | ")
     ChildProcess.exec command, bufferLines: true, stdout: (data) ->
       for grepLine in data.split('\n') when grepLine.length
         nullCharIndex = grepLine.indexOf('\0')


Exact route url hotfix

Exact route url hotfix

Signed-off-by: Caddy Dz <cbc6199cd1cb93e9d3589fb9aa7ecaece7b37833@gmail.com>

--- src/atom/snippets.cson
+++ src/atom/snippets.cson
@@ -8,7 +8,7 @@
     'body': '
\n\t$2:\n\t<input type="text" class="form-control" name="$1" id="$1">\n
\n$3'
   'Vue JS Router':
     'prefix' : 'router'
-    'body': '<router-link to="${1:url}">${2:title}</router-link>\n\t$3'
+    'body': '<router-link to="${1:url}" exact>${2:title}</router-link>\n\t$3'
 '.source.js':
   'vue.component':
     'prefix' : 'vue.component'


act realtime updates fix

act realtime updates fix

--- client/landing/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
+++ client/landing/app/Applications/Activity.kdapplication/activitylistcontroller.coffee
@@ -136,6 +136,8 @@
   addHiddenItem:(activity, index, animation = null)->

     instance = @getListView().addHiddenItem activity, index, animation
+    hiddenItems.push instance
+    instance

   unhideNewHiddenItems = (hiddenItems)->


Teamwork: Refactored index.html template for FacebookTeamwork.

--- client/landing/app/Applications/Teamwork.kdapplication/Views/facebookteamwork.coffee
+++ client/landing/app/Applications/Teamwork.kdapplication/Views/facebookteamwork.coffee
@@ -102,10 +102,12 @@

   exampleItemMarkup: (title, description) ->
     """
-

-
#{title}

-
#{description}

-

+
+

+
#{title}

+
#{description}

+

+
     """

   examplesPageMarkup: (examplesMarkup) ->
@@ -113,16 +115,11 @@

           <title>Facebook App Examples</title>
+          <link rel="stylesheet" type="text/css" href="https://koding-cdn.s3.amazonaws.com/teamwork/tw-fb.css" />

-

-

-
-
Facebook

-

-

-              #{examplesMarkup}
-

+

+            #{examplesMarkup}


Copy .woff2 font files to build.

Copy .woff2 font files to build.

--- community/browser/Gruntfile.coffee
+++ community/browser/Gruntfile.coffee
@@ -277,7 +277,7 @@
             dot: true
             cwd: "<%= yeoman.app %>"
             dest: "<%= yeoman.dist %>/fonts"
-            src: ["components/**/*.{otf,woff,ttf,svg}"]
+            src: ["components/**/*.{otf,woff,woff2,ttf,svg}"]
         }]
     shell:
       dirListing:


string convention

string convention

--- components/autocomplete/index.cjsx
+++ components/autocomplete/index.cjsx
@@ -19,12 +19,12 @@
     value       : React.PropTypes.any

   getDefaultProps: ->
-    className   : ""
+    className   : ''
     colors      : {}
     dataSource  : {}
     exact       : true
     multiple    : true
-    type        : "text"
+    type        : 'text'

   getInitialState: ->
     focus       : false
@@ -57,12 +57,12 @@

     if @state.focus
       children = @refs.suggestions.getDOMNode().children
-      for child, index in children when child.classList.contains "active"
-        child.classList.remove "active"
-        query = child.getAttribute "id"
+      for child, index in children when child.classList.contains 'active'
+        child.classList.remove 'active'
+        query = child.getAttribute 'id'
         break

-    if key_ascii is 13 and query isnt ""
+    if key_ascii is 13 and query isnt ''
       for key, label of @state.suggestions when query.toLowerCase() is label.toLowerCase()
         suggestion = {"#{key}": label}
         break
@@ -76,23 +76,23 @@
         index = if index >= children.length - 1 then 0 else index + 1
       else
         index = if index is 0 then children.length - 1 else index - 1
-      children[index].classList.add "active"
+      children[index].classList.add 'active'

   onBlur: (event) ->
     setTimeout (=> @setState focus: false, suggestions: {}), 300

   onSelect: (event) ->
-    key = event.target.getAttribute "id"
+    key = event.target.getAttribute 'id'
     @_addValue {"#{key}": @state.suggestions[key]}

   onRefreshSelection: (event) ->
     children = @refs.suggestions.getDOMNode().children
-    for child, index in children when child.classList.contains "active"
-      child.classList.remove "active"
+    for child, index in children when child.classList.contains 'active'
+      child.classList.remove 'active'
       break

   onDelete: (event) ->
-    delete @state.values[event.target.getAttribute "id"]
+    delete @state.values[event.target.getAttribute 'id']
     @setState focus: false, values: @state.values
     @props.onChange? @

@@ -100,12 +100,12 @@
   render: ->
     className  = "#{localCSS.root} #{@props.className}"
     className += " #{@props.type}"  if @props.type
-    className += " focus"           if @state.focus
+    className += ' focus'           if @state.focus

       { {@props.label} if @props.label }
       {
         if @props.multiple
-          <ul className={localCSS.values} data-flex="horizontal wrap"
+

             {
               for key, label of @state.values
@@ -113,13 +113,13 @@
             }

       }
-      <Input {...@props} ref="input" value="" label=""
+      <Input {...@props} ref='input' value='' label=''
              onBlur={@onBlur}
              onChange={@onChange}
              onFocus={@onFocus}
              onKeyDown={@onKeyPress}
              />
-       @props.onChange? @), 10
     @setState focus: false, values: values
-    @refs.input.setValue if @props.multiple then "" else value[key]
+    @refs.input.setValue if @props.multiple then '' else value[key]

   _getSuggestions: (query) ->
     suggestions = {}


Fix bug with renamed variable.

Fix bug with renamed variable.

--- guts/policies.coffee
+++ guts/policies.coffee
@@ -16,7 +16,7 @@
         # your life.
         tempActions = _.flatten [ policies[routeActions.controllerName][routeActions.actionName] ]

-        policyResults = _.map actions, (policy) ->
+        policyResults = _.map tempActions, (policy) ->
                 # This is pretty straightforward; we'll loop up the policy in the hash
                 # table and then return back their result (which can just be a true or false
                 #


consumer reuse for invalid queue test work

--- test/consumer.test.coffee
+++ test/consumer.test.coffee
@@ -814,6 +814,56 @@
     ]

+  xit 'test we can consume and interrupt a nameless queue 806', (done)->
+    # INCOMPLETE
+    this.timeout = 60000
+    thisproxy = new proxy.route(7007, 5672, "localhost")
+    amqp = null
+
+    testData = {test:"message"}
+    amqp = null
+    messagesRecieved = 0
+    consumer = null
+    queue = null
+
+    messageProcessor = (m)->
+
+      thisproxy.interrupt()
+      _.delay ()->
+        consumer.resume()
+      , 1000
+
+    async.series [
+      (next)->
+        amqp = new AMQP {host:'localhost', port: 7007}, (e, r)->
+          should.not.exist e
+          next()
+
+      (next)->
+        amqp.queue {queue:""}, (e,q)->
+          should.not.exist e
+
+          q.declare ()->
+            queue = q.queueOptions.queue
+            next()
+
+
+      (next)->
+        consumer = amqp.consume queue, {prefetchCount: 1}, messageProcessor, (e,r)->
+          should.not.exist e
+          next()
+
+        consumer.on 'error', (error)->
+          should.exist error
+          error.error.replyCode.should.eql 404
+
+      (next)->
+        amqp.publish "", queue, testData, {confirm: true}, next
+
+    ]
+
+
+
   it 'test we can close a consumer channel 854.5', (done)->

     amqp = null


disable BBT when broken Zotero Maps 1.0.10 is detected

--- chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
+++ chrome/content/zotero-better-bibtex/zotero-better-bibtex.coffee
@@ -86,6 +86,21 @@
     Zotero.debug('[better' + '-' + 'bibtex] ' + str, level)

 Zotero.BetterBibTeX.extensionConflicts = ->
+  AddonManager.getAddonByID('zoteromaps@zotero.org', (maps) ->
+    return unless maps
+    return if Services.vc.compare(zutilo.version, '1.0.10') > 0
+    Zotero.BetterBibTeX.removeTranslators()
+    Zotero.BetterBibTeX.disabled = '''
+      Better BibTeX has been disabled because it has detected conflicting extension "zotero-maps" 1.0.10 or
+      earlier. Unfortunately this plugin appears to be abandoned, and their issue tracker at
+
+      https://github.com/zotero/zotero-maps
+
+      is not enabled.
+    '''
+    Zotero.BetterBibTeX.flash('Better BibTeX has been disabled', Zotero.BetterBibTeX.disabled)
+  )
+
   AddonManager.getAddonByID('zutilo@www.wesailatdawn.com', (zutilo) ->
     return unless zutilo
     return if Services.vc.compare(zutilo.version, '1.2.10.1') > 0


changed settings path

changed settings path

--- pushd.coffee
+++ pushd.coffee
@@ -3,7 +3,7 @@
 zlib = require 'zlib'
 url = require 'url'
 Netmask = require('netmask').Netmask
-settings = require './settings'
+settings = require 'settings'
 redis = require('redis').createClient(settings.server.redis_socket or settings.server.redis_port, settings.server.redis_host,
                             {no_ready_check: true})
 Subscriber = require('./lib/subscriber').Subscriber


[fix] Expose the raw date to the end

[fix] Expose the raw date to the end


prevent back button on Android

prevent back button on Android


/auth_test

--- apps/auth/app.coffee
+++ apps/auth/app.coffee
@@ -11,6 +11,15 @@

   redirectUrl = req.query['redirect_url']
   res.redirect(redirectUrl + "?uid=#{uid}&token=#{token}")
+)
+
+app.get('/auth_test', (req, res) ->
+  uid = uuid()
+  token = uuid()
+  setToken(uid, token)
+
+  res.write("uid=#{uid}\ntoken=#{token}")
+  res.end()
 )

 httpOptions = (method, path, cookie = null, json = null) ->
@@ -31,10 +40,8 @@
   auth["/users/#{uid}"] = 'rw'
   json = JSON.stringify(auth)
   req = http.request(httpOptions('PUT', "/tokens/#{token}", null, json), (res) ->
-    assert.equal 204, res.statusCode
     res.on 'data', (chunk) ->
       assert.equal Object.keys(JSON.parse(chunk)).length, 0
-    done()
   )
   req.on 'error', (e) ->
     throw new Error(e)


Default to empty feature toggle set.

Default to empty feature toggle set.

--- js-library/app/js/core.coffee
+++ js-library/app/js/core.coffee
@@ -1,4 +1,6 @@
-window.Factlink = {}
+window.Factlink = {
+  can_haz: {}
+}

 # See http://stackoverflow.com/questions/3690447/override-default-jquery-selector-context
 jQuery.noConflict()


fix links save bug

fix links save bug

--- lib/insert-link-view.coffee
+++ lib/insert-link-view.coffee
@@ -58,7 +58,6 @@
     @panel ?= atom.workspace.addModalPanel(item: this, visible: false)
     @previouslyFocusedElement = $(document.activeElement)
     @panel.show()
-
     @fetchPosts()
     @loadSavedLinks =>
       @setFieldsFromSelection()
@@ -208,14 +207,18 @@
       delete @links[text.toLowerCase()]

     file = config.get("siteLinkPath")
-    fs.exists file, (exists) -> CSON.writeFile(file, @links) if exists
+    fs.exists file, (exists) =>
+      CSON.writeFile(file, @links) if exists

   loadSavedLinks: (callback) ->
-    setLinks = (data) => @links = data || {}; callback()
-    readFile = (file) -> CSON.readFile file, (error, data) -> setLinks(data)
+    setLinks = (data) =>
+      @links = data || {}; callback()
+    readFile = (file) ->
+      CSON.readFile file, (error, data) -> setLinks(data)

     file = config.get("siteLinkPath")
-    fs.exists file, (exists) -> if exists then readFile(file) else setLinks()
+    fs.exists file, (exists) ->
+      if exists then readFile(file) else setLinks()

   fetchPosts: ->
     if posts


Wait at least 200ms between requests to geonames.org

--- content/scripts/application.coffee
+++ content/scripts/application.coffee
@@ -89,13 +89,17 @@
   if local_value?
     success(new google.maps.LatLng(local_value[0], local_value[1]))
   else
-    $.getJSON(url, geonames_options, (data) ->
-      if data["status"]?
-        window.geonames_over_limit = new Date
-      else
-        if data["geonames"].length > 0
-          lat = data["geonames"][0]["lat"]
-          lng = data["geonames"][0]["lng"]
-          $.jStorage.set(location, [lat, lng])
-          success(new google.maps.LatLng(lat, lng))
+    window.setTimeout(->
+      $.getJSON(url, geonames_options, (data) ->
+        if data["status"]?
+          window.geonames_over_limit = new Date
+        else
+          if data["geonames"].length > 0
+            lat = data["geonames"][0]["lat"]
+            lng = data["geonames"][0]["lng"]
+            $.jStorage.set(location, [lat, lng])
+            success(new google.maps.LatLng(lat, lng))
+      )
+    , 200
     )
+


update to latest poplockit

update to latest poplockit

--- lib/jquery.poplockit.coffee
+++ lib/jquery.poplockit.coffee
@@ -111,7 +111,7 @@
           return @setPosition('absolute', 'south')
         return @setPosition('fixed', 'south') if @height > viewportHeight and @height < @parentHeight and (scrollTop + viewportHeight) >= (@top + @height) and (scrollTop + viewportHeight) < (@parentHeight + @top)

-      return @setPosition('absolute', 'south') if scrollTop >= @bottom
+      return @setPosition('absolute', 'south') if (scrollTop + viewportHeight) >= @bottom && @height >= viewportHeight
       @setPosition('absolute', 'north')

     # return to default state on destroy


Only unescape truthy path names

Only unescape truthy path names

--- lib/markdown-preview.coffee
+++ lib/markdown-preview.coffee
@@ -11,7 +11,7 @@

     atom.workspace.registerOpener (uriToOpen) ->
       {protocol, pathname} = url.parse(uriToOpen)
-      pathname = querystring.unescape(pathname)
+      pathname = querystring.unescape(pathname) if pathname
       return unless protocol is 'markdown-preview:' and fs.isFileSync(pathname)
       new MarkdownPreviewView(pathname)


:penguin: Use ctrl-f3 for use-selection-as-find-pattern

--- keymaps/find-and-replace.cson
+++ keymaps/find-and-replace.cson
@@ -24,8 +24,7 @@
 '.platform-linux .editor':
   'f3': 'find-and-replace:find-next'
   'shift-f3': 'find-and-replace:find-previous'
-
-  'ctrl-e': 'find-and-replace:use-selection-as-find-pattern'
+  'ctrl-f3': 'find-and-replace:use-selection-as-find-pattern'

 '.platform-darwin .find-and-replace':
   'cmd-enter': 'find-and-replace:replace-all'


Add keybindings for all platforms

Add keybindings for all platforms

--- keymaps/markdown-preview.cson
+++ keymaps/markdown-preview.cson
@@ -1,9 +1,16 @@
 '.workspace':
   'ctrl-M': 'markdown-preview:toggle'

-'.markdown-preview':
+'.platform-darwin .markdown-preview':
   'cmd-+': 'markdown-preview:zoom-in'
   'cmd-=': 'markdown-preview:zoom-in'
   'cmd--': 'markdown-preview:zoom-out'
   'cmd-_': 'markdown-preview:zoom-out'
   'cmd-0': 'markdown-preview:reset-zoom'
+
+'.platform-win32 .markdown-preview, .platform-linux .markdown-preview':
+  'ctrl-+': 'markdown-preview:zoom-in'
+  'ctrl-=': 'markdown-preview:zoom-in'
+  'ctrl--': 'markdown-preview:zoom-out'
+  'ctrl-_': 'markdown-preview:zoom-out'
+  'ctrl-0': 'markdown-preview:reset-zoom'


fix multiple axis

fix multiple axis

--- assets/js/app.coffee
+++ assets/js/app.coffee
@@ -87,9 +87,9 @@
     # Check for single or multi-valued data points
     first_object = JSON.parse(resp.object.data[0].value)

-    if typeof first_object.value is "object"
+    if typeof first_object is "object"
       # Multiple values, assume numeric
-      for key of first_object.value
+      for key of first_object

         data = []
         data.push {date: new Date(datum.date*1000), value: JSON.parse(datum.value)[key]} for datum in resp.object.data


Reenable undo, redo, and transaction specs

--- spec/edit-session-spec.coffee
+++ spec/edit-session-spec.coffee
@@ -2065,7 +2065,7 @@
           editSession.toggleLineCommentsInSelection()
           expect(buffer.lineForRow(10)).toBe "  "

-      xdescribe ".undo() and .redo()", ->
+      describe ".undo() and .redo()", ->
         it "undoes/redoes the last change", ->
           editSession.insertText("foo")
           editSession.undo()
@@ -2113,7 +2113,7 @@
           editSession.redo()
           expect(editSession.getSelectedBufferRanges()).toEqual [[[1, 6], [1, 6]], [[1, 18], [1, 18]]]

-        it "restores folds after undo and redo", ->
+        xit "restores folds after undo and redo", ->
           editSession.foldBufferRow(1)
           editSession.setSelectedBufferRange([[1, 0], [10, Infinity]], preserveFolds: true)
           expect(editSession.isFoldedAtBufferRow(1)).toBeTruthy()
@@ -2136,27 +2136,26 @@
           expect(editSession.isFoldedAtBufferRow(1)).toBeFalsy()
           expect(editSession.isFoldedAtBufferRow(2)).toBeTruthy()

-      xdescribe ".transact([fn])", ->
-        describe "when called without a function", ->
-          it "restores the selection when the transaction is undone/redone", ->
-            buffer.setText('1234')
-            editSession.setSelectedBufferRange([[0, 1], [0, 3]])
-            editSession.transact()
-
-            editSession.delete()
-            editSession.moveCursorToEndOfLine()
-            editSession.insertText('5')
-            expect(buffer.getText()).toBe '145'
-
-            editSession.commit()
-
-            editSession.undo()
-            expect(buffer.getText()).toBe '1234'
-            expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [0, 3]]
-
-            editSession.redo()
-            expect(buffer.getText()).toBe '145'
-            expect(editSession.getSelectedBufferRange()).toEqual [[0, 3], [0, 3]]
+      describe "begin/commitTransaction()", ->
+        it "restores the selection when the transaction is undone/redone", ->
+          buffer.setText('1234')
+          editSession.setSelectedBufferRange([[0, 1], [0, 3]])
+          editSession.beginTransaction()
+
+          editSession.delete()
+          editSession.moveCursorToEndOfLine()
+          editSession.insertText('5')
+          expect(buffer.getText()).toBe '145'
+
+          editSession.commitTransaction()
+
+          editSession.undo()
+          expect(buffer.getText()).toBe '1234'
+          expect(editSession.getSelectedBufferRange()).toEqual [[0, 1], [0, 3]]
+
+          editSession.redo()
+          expect(buffer.getText()).toBe '145'
+          expect(editSession.getSelectedBufferRange()).toEqual [[0, 3], [0, 3]]

       describe "when the buffer is changed (via its direct api, rather than via than edit session)", ->
         it "moves the cursor so it is in the same relative position of the buffer", ->
@@ -2277,7 +2276,7 @@
           expect(buffer.lineForRow(6)).toBe(line7)
           expect(buffer.getLineCount()).toBe(count - 1)

-      xdescribe "when the line being deleted preceeds a fold, and the command is undone", ->
+      describe "when the line being deleted preceeds a fold, and the command is undone", ->
         it "restores the line and preserves the fold", ->
           editSession.setCursorBufferPosition([4])
           editSession.foldCurrentRow()


implemented tests for pusbling and receiving and handling messages

--- spec/lib/exchange-spec.coffee
+++ spec/lib/exchange-spec.coffee
@@ -1,18 +1,71 @@
+EventEmitter = require('events').EventEmitter
 describe 'exchange', ->
+
+  Given -> @exchange = require './../../lib/exchange'
+  Given ->
+    @q = new EventEmitter
+    @q.send = ->
+  Given ->
+    @p = new EventEmitter
+    @p.send = ->
+    @p.subscribe = ->
+  Given -> @h = new EventEmitter

   describe '#make', ->

     context 'with no arguments', ->

+      When -> @res = @exchange.make()
+      Then -> expect(typeof @res).toBe 'object'
+      And -> expect(@res instanceof @exchange).toBe true
+
     context 'with queue, pubsub, handler', ->
+      When -> @res = @exchange.make @q, @p, @h
+      Then -> expect(typeof @res).toBe 'object'
+      And -> expect(@res instanceof @exchange).toBe true
+      And -> expect(@res.queue).toBe @q
+      And -> expect(@res.pubsub).toBe @p
+      And -> expect(@res.handler).toBe @h

   context 'an instance', ->
+
+    Given -> @instance = @exchange.make @q, @p, @h

     describe '#publish', ->

       context 'with message and channel', ->
+        Given -> spyOn(@p,['send']).andCallThrough()
+        When -> @instance.publish ok:1, 'channel'
+        Then -> expect(@p.send).toHaveBeenCalledWith 'channel ' + encodeURIComponent(JSON.stringify(ok:1))

       context 'with message', ->
+        Given -> spyOn(@q, ['send']).andCallThrough()
+        When -> @instance.publish ok:2
+        Then -> expect(@q.send).toHaveBeenCalledWith ok:2

     describe '#channel', ->

+      When -> @res = @instance.channel 'channel'
+      Then -> expect(typeof @res).toBe 'object'
+      And -> expect(@res.id).toBe 'channel'
+
+    describe '.handler', ->
+
+      Given -> @message =
+          data:
+            action:'action'
+
+      context 'receiving a message on a queue', ->
+
+        Given -> spyOn(@instance.handler,['emit']).andCallThrough()
+        When -> @q.emit 'message', @message
+        Then -> expect(@instance.handler.emit).toHaveBeenCalledWith 'action', @message.data, @instance
+
+    describe '.pubsub', ->
+
+      Given -> @message = 'channel ' + encodeURIComponent(JSON.stringify(ok:4))
+
+      context 'receiving a mesage on the pubsub', ->
+        Given -> spyOn(@instance,['emit']).andCallThrough()
+        When -> @p.emit 'message', @message
+        Then -> expect(@instance.emit).toHaveBeenCalledWith 'channel', ok:4


change all status messages to arrays

change all status messages to arrays

--- src/status.coffee
+++ src/status.coffee
@@ -10,12 +10,16 @@
     return callback err, status

-BEGIN_STAGED    = "# Changes to be committed:"
+BEGIN_STAGED    = [
+  "# Changes to be committed:"
+]
 BEGIN_UNSTAGED  = [
   "# Changed but not updated:"
   "# Changes not staged for commit:"
 ]
-BEGIN_UNTRACKED = "# Untracked files:"
+BEGIN_UNTRACKED = [
+  "# Untracked files:"
+]
 FILE            = /^#\s+([^\s]+)[:]\s+(.+)$/
 TYPES =
   added:    "A"
@@ -31,13 +35,13 @@
     @clean = true
     state  = null
     for line in text.split("\n")
-      if line == BEGIN_STAGED
+      if ~BEGIN_STAGED.indexOf(line)
         state = "staged"
         @clean = false
       else if ~BEGIN_UNSTAGED.indexOf(line)
         state = "unstaged"
         @clean = false
-      else if line == BEGIN_UNTRACKED
+      else if ~BEGIN_UNTRACKED.indexOf(line)
         state = "untracked"
         @clean = false
       else if state && match = FILE.exec(line)


Update comments

Update comments

--- src/stdlib.coffee
+++ src/stdlib.coffee
@@ -1,5 +1,5 @@
 # Provides a shorthand for musical notes. Usage:
-# Frequency.A_4 // Defined as 440.0
+# Frequency.A_4 // Defined to be 440.0
 F = Frequencies = class Frequency
   # MIDI Note number -> Hz value
   @noteNumber = (note) ->
@@ -124,15 +124,15 @@
 audio rendering allowing you to modify your environment with sample-level
 time resolution.

-It's recommended you use the DSL provided in buildTrack(), which simplifies the
-process of creating short-lived loops by managing the registration and
-unregistration of callbacks for you.
-
-See `@every()`, `@after()` and `@until()` methods here:
+I recommend using the DSL provided by buildTrack(), which atomatically manages
+callback registration and unregistration to simplify the process of creating
+short-lived loops.
+
+See the `@every()`, `@after()` and `@until()` methods here:
 https://emcmanus.gitbooks.io/tinyrave-libraries/content/timers.html

-The timer is optimized to handle 1000's of callbacks. (Useful for tracks that
-front-load the scheduling of notes, like when using the MIDI adapter.)
+This timer is optimized to handle 1000's of callbacks, which is useful for
+tracks that front-load the scheduling of notes, like the MIDI adapter.
 ###
 class TinyRaveTimer
   constructor: ->
@@ -155,7 +155,7 @@
       @time = time
       if @time >= @nextThreshold
         @fireCallbacks()
-        @updateThreshold() # Descriptors change their registration time when isLoop = true
+        @updateThreshold() # B/C descriptors reset their registration time when isLoop = true
     else
       throw new Error "Time invalid."
     time
@@ -218,9 +218,9 @@
 # Doing this gets us two things:
 #
 # 1) An `expiration` shadow variable. When the timer methods run in an instance
-#    of ShadowScope, they will reference the most-local, shadow copy of
+#    of ShadowScope, they will reference the most-local shadow copy of
 #    @expiration. This allows us to adjust the block expiration in nested
-#    calls.
+#    calls and "unwind" the value as we exit nested scopes.
 #
 # 2) A version of `this` that will still resolve instance variables. If you
 #    define any variables using `this` they will be accessible in other timer


atom: use font Source Code Pro - https://github.com/adobe-fonts/source-code-pro

--- atom/config.cson
+++ atom/config.cson
@@ -1,11 +1,10 @@
 "*":
   editor:
-    invisibles:
-      {}
+    invisibles: {}
     preferredLineLength: 100
-    fontSize: 14
     showIndentGuide: true
     showInvisibles: true
+    fontFamily: "Source Code Pro, Monaco, Consolas, Courier New"
   core:
     themes: [
       "atom-dark-ui"
@@ -16,16 +15,13 @@
   welcome:
     showOnStartup: false
   linter:
-    subtleLinterErrors: [
-      "pylint"
-    ]
+    showErrorPanel: false
   "atom-beautify":
     _analyticsUserId: "65f4271a-cd10-4224-b2bd-ee72bc113080"
     analytics: false
   "vim-mode":
     startInInsertMode: true
-  minimap:
-    {}
+  minimap: {}
   "git-log":
     fontScale: 0.8
   "spell-check":
@@ -40,9 +36,7 @@
       "text.html.erb"
       "text.plain"
     ]
-  "autocomplete-plus":
-    {}
+  "autocomplete-plus": {}
   "markdown-preview":
-    {}
-  "linter-coffeelint":
-    {}
+    useGitHubStyle: true
+  "linter-coffeelint": {}


Adjust linter panel height

Adjust linter panel height

--- atom/config.cson
+++ atom/config.cson
@@ -55,6 +55,7 @@
   "linter-sass-lint":
     noConfigDisable: true
   "linter-ui-default":
+    panelHeight: 69
     showPanel: true
   "markdown-deluxe":
     fontFamily: "Hack"


Update atom config

Update atom config

--- atom/config.cson
+++ atom/config.cson
@@ -20,5 +20,11 @@
     userId: "b6917109-8650-33d4-94c7-9edad015d73f"
   linter: {}
   "highlight-column": {}
+  "block-cursor":
+    primaryColor:
+      red: 195
+      green: 59
+      blue: 50
+      alpha: 1
 "highlight-line":
   hideHighlightOnSelect: true


Ignore max line length warning in Python entirely

--- atom/config.cson
+++ atom/config.cson
@@ -149,6 +149,10 @@
       "source.js.sca.ss"
       "source.ts"
     ]
+  "linter-flake8":
+    ignoreErrorCodes: [
+      "E501"
+    ]
   "linter-ui-default":
     hidePanelWhenEmpty: true
     showPanel: true


chore: update atom config

chore: update atom config

--- atom/config.cson
+++ atom/config.cson
@@ -1,5 +1,6 @@
 "*":
   core:
+    telemetryConsent: "no"
     themes: [
       "one-dark-ui"
       "base16-tomorrow-dark-theme"
@@ -8,6 +9,8 @@
     fontFamily: "Hack"
     fontSize: 12
     lineHeight: 2
+  "exception-reporting":
+    userId: "d6cc59fd-d3e0-48ad-998b-33af591b7072"
   linter: {}
   "linter-eslint":
     disableWhenNoEslintrcFileInPath: true


Change back to using grammar name

Change back to using grammar name

Matching against the scope name of the grammar didn't seem to work in
all cases.

--- atom/init.coffee
+++ atom/init.coffee
@@ -6,14 +6,14 @@
 #

 fileTypes = {
-  "source.gfm": (editor) ->
+  "GitHub Markdown": (editor) ->
     editor.setSoftWrap(true)
     editor.setTabLength(4)

-  "source.java": (editor) ->
+  "Java": (editor) ->
     editor.setTabLength(4)

-  "source.python": (editor) ->
+  "Python": (editor) ->
     editor.setTabLength(4)
 }

@@ -21,7 +21,7 @@
 #
 # editor - Editor to which to apply the grammar-specific settings.
 applySyntaxSettings = (editor) ->
-  func(editor) for scopeRegex, func of fileTypes when scopeRegex.test(editor.getGrammar().scopeName)
+  func(editor) for name, func of fileTypes when name is editor.getGrammar().name

 # Executes for each and every Editor, past and future.
 atom.workspace.eachEditor (editor) ->


user supplied options should overwrite defaults

--- src/coffee/card.coffee
+++ src/coffee/card.coffee
@@ -58,7 +58,7 @@
       nameDisplay: '.name'

   constructor: (el, opts) ->
-    @options = $.extend({}, opts, @defaults)
+    @options = $.extend({}, @defaults, opts)
     @$el = if $(el).is('form') then $(el) else $(el).find 'form'

     unless @options.container


Check for sane maximum values of !dice parameters

--- handlers/toys.coffee
+++ handlers/toys.coffee
@@ -19,6 +19,7 @@
 debug = (require 'debug')('Chatbot:toys')
 api = require '../api'
 Random = require 'random-js'
+{ __, __n } = require '../i18n'

 mt = do Random.engines.mt19937
 do mt.autoSeed
@@ -38,6 +39,12 @@
 				[ dice, sides ] = parameters.split /d/
 			sides = 6 if not sides? or sides is ''
 			dice = 1 if not dice? or dice is ''
+			if sides > 150
+				api.replyTo message, __("The maximum number of sides is 150.")
+				return
+			if dice > 50
+				api.replyTo message, __("The maximum number of dices is 50.")
+				return
 			api.sendMessage Random.dice(sides, dice)(mt).join(', '), yes, callback

 		else


Changed to proper followRedirect

Changed to proper followRedirect

cc @lbryant

See https://github.com/mikeal/request#requestoptions-callback

--- proxy.coffee
+++ proxy.coffee
@@ -55,7 +55,7 @@
       uri: url
       method: req.method
       headers: req.headers
-      followRedirects: not config.followRedirects
+      followRedirect: not config.followRedirects

     reqDomain.run ->
       req.pipe(request(options)).pipe res


capitalize first letter of user email

capitalize first letter of user email

--- proxy.coffee
+++ proxy.coffee
@@ -261,8 +261,10 @@
     loginView: (req, res) =>
         @userManager.all (err, users) =>
             if users?.length > 0 and not err
-                username = helpers.hideEmail users[0].value.email
-                res.render 'login', username: username
+                name = helpers.hideEmail users[0].value.email
+                if name?
+                    name = name.charAt(0).toUpperCase() + name.slice(1)
+                res.render 'login', username: name
             else
                 res.redirect 'register'

@@ -276,8 +278,8 @@
     authenticatedAction: (req, res) =>
         res.send success: req.isAuthenticated()

+    # Check user credentials and keep user authentication through session.
     authenticate: (req, res) =>
-        # Check user credentials and keep user authentication through session.
         answer = (err) =>
             if err
                 @sendError res, "Login failed"
@@ -298,12 +300,12 @@
                     else
                         req.logIn user, {}, answer

-        authenticator(req, res)
+        authenticator req, res

     loginAction: (req, res) =>
         req.body.username = "owner"
-        @authenticate(req, res)
+        @authenticate req, res

     # Clear authentication credentials from session for current user.
     logoutAction: (req, res) =>


Change the algorithm to suggest shard. Related to #1237 and #1186

--- admin/static/coffee/namespaces/shards.coffee
+++ admin/static/coffee/namespaces/shards.coffee
@@ -58,31 +58,38 @@
                 @display_msg error_msg
                 return

-            if distr_keys.length < 2
-                error_msg = "There is not enough data in the database to make balanced shards."
+            if distr_keys.length < new_num_shards
+                error_msg = 'There is not enough data in the database to make '+distr_keys.length+' balanced shards.'
                 @display_msg error_msg
                 return

-            current_shard_count = 0
-            split_points = [""]
+            current_count = 0 # Global count to spread errors among shards
+            split_points = []
             no_more_splits = false
-            for key in distr_keys
-                if split_points.length >= new_num_shards
-                    no_more_splits = true
-                current_shard_count += data[key]
-                if current_shard_count >= rows_per_shard and not no_more_splits
-                    split_points.push(key)
-                    current_shard_count = 0
+            for key, i in distr_keys
+                if i is 0
+                    if key isnt '' # For safety. The empty string is always the smallest key
+                        return 'Error'
+                    split_points.push key
+                    current_count += data[key]
+                    continue
+
+                # If we have just enough keys left, we just add all of them as split points
+                # keys_left <= splits_point left to add
+                if distr_keys.length-i <= new_num_shards-split_points.length # We don't add 1 because there is null
+                    split_points.push key
+                    continue
+
+                # Else we check if we have enough keys
+                if current_count >= rows_per_shard*split_points.length
+                    split_points.push key
+                current_count += data[key]
+
             split_points.push(null)

             shard_set = []
             for splitIndex in [0..(split_points.length - 2)]
                 shard_set.push(JSON.stringify([split_points[splitIndex], split_points[splitIndex + 1]]))
-
-            if shard_set.length < new_num_shards
-                error_msg = "There is only enough data to make " + shard_set.length + " balanced shards."
-                @display_msg error_msg
-                return

             if event?.which? and event.which is 13
                 @shard_table()


Comment

Comment

--- js/token-poker-hubot-dealer.coffee
+++ js/token-poker-hubot-dealer.coffee
@@ -84,6 +84,7 @@

   # TODO: optionally protect admin commands by list of admins
   robot.hear /^poker admin (.*)/i, (msg) ->
+    # OMG - It's like I'm trying to kill Uncle Bob with this code.
     try
       dealer = currentDealer(msg)
       return if !dealer


Fix for files with no checksum

Fix for files with no checksum

--- backend/merge.coffee
+++ backend/merge.coffee
@@ -71,6 +71,17 @@
         if doc.checksum?
             doc.checksum = doc.checksum.toLowerCase()
             return not doc.checksum.match /^[a-f0-9]{40}$/
+        else
+            return false
+
+    # TODO comments, tests
+    sameBinary: (one, two, callback) ->
+        if one.checksum? and one.checksum is two.checksum
+            return true
+        else if one.remote?.file
+            oneId = one.remote.file._id
+            twoId = two.remote.file._id
+            return oneId and oneId is twoId
         else
             return false

@@ -141,7 +152,7 @@

     # Expectations:
     #   - the file path and name are present and valid
-    #   - the checksum is present
+    #   - the checksum is valid, if present
     # Actions:
     #   - force the 'file' docType
     #   - add the creation date if missing
@@ -165,7 +176,7 @@
                 if file
                     doc._rev = file._rev
                     doc.creationDate ?= file.creationDate
-                    if file.checksum is doc.checksum
+                    if @sameBinary file, doc
                         doc.size  ?= file.size
                         doc.class ?= file.class
                         doc.mime  ?= file.mime
@@ -211,7 +222,7 @@
     # Expectations:
     #   - the new file path and name are present and valid
     #   - the old file path and name are present and valid
-    #   - the checksum is present
+    #   - the checksum is valid, if present
     #   - the two paths are not the same
     #   - the revision for the old file is present
     # Actions:


log using stdout.write instead of console.info

node-webkit intercepts console.info and adds its own junk to the log

--- proxy.coffee
+++ proxy.coffee
@@ -3,8 +3,8 @@
   n = t = 0
   (s) ->
     if (t1 = +new Date) - t > T then t = t1; n = 1
-    if ++n < N then console?.info? process.uptime().toFixed(3) + ' ' + s
-    else if n == N then console?.info? '... logging temporarily suppressed'
+    if ++n < N then process?.stdout?.write? "#{process.uptime().toFixed 3} #{s}\n"
+    else if n == N then process?.stdout?.write? '... logging temporarily suppressed\n'

 rm = (a, x) -> i = a.indexOf x; (if i != -1 then a.splice i, 1); return
 b64 = (s) -> Buffer(s).toString 'base64'


Whitespace killer.

Whitespace killer.

--- core/KDCustomHTMLView.coffee
+++ core/KDCustomHTMLView.coffee
@@ -4,7 +4,7 @@

     @tagName = options if typeof options is "string"
     @tagName ?= options.tagName ? "div"
-
+
     if @tagName is "a" and not options.attributes?.href?
       options.attributes = href : "#"
     super


Switched to CoffeeScript string interpolation

--- resources/assets/scripts/app/services/track-stats.coffee
+++ resources/assets/scripts/app/services/track-stats.coffee
@@ -23,7 +23,8 @@
             loadStats: (id) ->
                 return def if def
                 def = new $.Deferred()
-                $http.get('/api/web/tracks/' + id + '/stats').success (stats) ->
+                url = "/api/web/tracks/#{ id }/stats"
+                $http.get(url).success (stats) ->
                     def.resolve stats

                 def.promise()


Revert changes to editor-view

Revert changes to editor-view

--- src/editor-view.coffee
+++ src/editor-view.coffee
@@ -4,7 +4,6 @@
 Editor = require './editor'
 CursorView = require './cursor-view'
 SelectionView = require './selection-view'
-
 fs = require 'fs-plus'
 _ = require 'underscore-plus'
 TextBuffer = require 'text-buffer'
@@ -122,9 +121,6 @@
     @newSelections = []

     @setPlaceholderText(placeholderText) if placeholderText
-
-    @contentsComponent = new EditorContentsComponent({editor})
-    @renderedLines.replaceWith(@contentsComponent.element)

     if editor?
       @edit(editor)
@@ -335,7 +331,8 @@

   # Checkout the HEAD revision of this editor's file.
   checkoutHead: ->
-    @editor.checkoutHead()
+    if path = @editor.getPath()
+      atom.project.getRepo()?.checkoutHead(path)

   configure: ->
     @subscribe atom.config.observe 'editor.showLineNumbers', (showLineNumbers) => @gutter.setShowLineNumbers(showLineNumbers)
@@ -972,8 +969,6 @@
     unless @isOnDom() and @isVisible()
       @redrawOnReattach = true
       return
-
-    return

     scrollViewWidth = @scrollView.width()
     @updateRenderedLines(scrollViewWidth)
@@ -1472,7 +1467,6 @@

   # Copies the current file path to the native clipboard.
   copyPathToClipboard: ->
-    @editor.copyPathToClipboard()
     path = @editor.getPath()
     atom.clipboard.write(path) if path?


clarify docs around lineHeight

clarify docs around lineHeight

--- src/editor-view.coffee
+++ src/editor-view.coffee
@@ -760,6 +760,10 @@

   # Public: Gets the line height for the editor
   #
+  # Note that this is different from `lineHeight`, which is the computed
+  # height of a line using the bounding box.  This is the property value of
+  # CSS `line-height`.
+  #
   # Returns a {Float} identifying the CSS line-height.
   getLineHeight: ->
     parseFloat(@css('line-height'))


replace ATOM_HOME in issue title with generic placeholder

--- lib/notification-issue.coffee
+++ lib/notification-issue.coffee
@@ -60,6 +60,7 @@

   getIssueTitle: ->
     title = @notification.getMessage()
+    title = title.replace(process.env.ATOM_HOME, '$ATOM_HOME')
     if title.length > TITLE_CHAR_LIMIT
       title = title.substring(0, TITLE_CHAR_LIMIT - 3) + '...'
     title


engine data module

engine data module

--- src/engine_data.coffee
+++ src/engine_data.coffee
@@ -1,7 +1,7 @@
 ###*
 The Data module provides methods to store global and persistent data in the engine.

-
+    engine.data

 @name Data
 @fieldOf Engine


Add isTeacher method

Add isTeacher method

--- src/flux/course.coffee
+++ src/flux/course.coffee
@@ -97,6 +97,9 @@
       periods = @_get(courseId).periods or []
       sortedPeriods = PeriodHelper.sort(periods)

+    isTeacher: (courseId) ->
+      !!_.findWhere(@_get(courseId)?.roles, type: 'teacher')
+
 extendConfig(CourseConfig, new CrudConfig())
 {actions, store} = makeSimpleStore(CourseConfig)
 module.exports = {CourseActions:actions, CourseStore:store}


Ace: Removed ace notifications.

Ace: Removed ace notifications.

--- client/Ace/ace.coffee
+++ client/Ace/ace.coffee
@@ -93,7 +93,6 @@

   saveFinished:(err, res)->
     unless err
-      @notify 'Successfully saved!', 'success'
       @lastSavedContents = @lastContentsSentForSave
       @emit 'FileContentRestored'
       # unless @askedForSave
@@ -205,7 +204,6 @@
   fetchContents:(callback)->
     file = @getData()
     unless /localfile:/.test file.path
-      @notify 'Loading...', null, null, 10000
       file.fetchContents callback
       # {vmName, path} = file
       # FSHelper.getInfo FSHelper.plainPath(path), vmName, (err, info)=>


Disable hints and preloader

Disable hints and preloader

For now

--- framer/Framer.coffee
+++ framer/Framer.coffee
@@ -68,7 +68,7 @@

 Framer.Extras.MobileScrollFix.enable() if Utils.isMobile()
 Framer.Extras.TouchEmulator.enable() if not Utils.isTouch()
-Framer.Extras.Hints.enable() if not Utils.isFramerStudio()
+# Framer.Extras.Hints.enable() if not Utils.isFramerStudio()
 Framer.Extras.ErrorDisplay.enable() if not Utils.isFramerStudio()
 Framer.Extras.TouchEmulator.enable() if not Utils.isFramerStudio()
-Framer.Extras.Preloader.enable() if not Utils.isFramerStudio()
+# Framer.Extras.Preloader.enable() if not Utils.isFramerStudio()


Unsubscribe abstract subscription when search result is destroyed. Fixes #4

--- client/results.coffee
+++ client/results.coffee
@@ -103,14 +103,25 @@
 Template.publicationSearchResult.events =
   'click .preview-link': (e, template) ->
     e.preventDefault()
-    Meteor.subscribe 'publications-by-id', @_id, ->
-      Deps.afterFlush =>
-        $(template.findAll '.abstract').slideToggle(200)
+
+    if template._publicationHandle
+      # We ignore the click if handle is not yet ready
+      $(template.findAll '.abstract').slideToggle('fast') if template._publicationHandle.ready()
+    else
+      template._publicationHandle = Meteor.subscribe 'publications-by-id', @_id, =>
+        Deps.afterFlush =>
+          $(template.findAll '.abstract').slideToggle('fast')

     return # Make sure CoffeeScript does not return anything

+Template.publicationSearchResult.created = ->
+  @_publicationHandle = null
+
 Template.publicationSearchResult.rendered = ->
   $(@findAll '.scrubber').iscrubber()
+
+Template.publicationSearchResult.destroyed = ->
+  @_publicationHandle.stop() if @_publicationHandle

 Template.sidebarSearch.rendered = ->
   $(@findAll '.chzn').chosen


Send the status code with the HTTP request size metric

--- libraries/metrics/http.coffee
+++ libraries/metrics/http.coffee
@@ -17,7 +17,7 @@
 				routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1)
 				Metrics.timing("http_request", responseTimeMs, null, {method:req.method, status_code: res.statusCode, path:routePath})
 				if requestSize
-					Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, path:routePath})
+					Metrics.summary("http_request_size_bytes", requestSize, {method:req.method, status_code: res.statusCode, path:routePath})
 				remoteIp = req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress
 				reqUrl = req.originalUrl || req.url
 				referrer = req.headers['referer'] || req.headers['referrer']


collider display bug fix

collider display bug fix

--- lib/_stationary.tmlib.coffee
+++ lib/_stationary.tmlib.coffee
@@ -121,7 +121,7 @@
                             @collider.worldview = true
                             @collider.sprite.visible = DEBUG
                             @collider.visible = DEBUG
-                            @collider.alpha = if (DEBUG) then 0.5 else 1.0
+                            @collider.opacity = @collider.sprite.alpha = if (DEBUG) then 0.5 else 1.0
                             @collider._xback = @collider.x = @x - @collider._offsetx
                             @collider._yback = @collider.y = @y - @z + @collider._offsety


better looking defs

better looking defs

--- library/membrane/auxes.coffee
+++ library/membrane/auxes.coffee
@@ -62,8 +62,8 @@
     # these definitions when you need a typical parasites, such as
     # the one that parsites on all standalone (non zombie) services
     # or the one that parasites on all services, including zombies.
-    @P_EVERYWHERE = (h, r, decide) -> return decide true
-    @P_STANDALONE = (h, r, d) -> d not h.objectOf Zombie
+    @PEVERYWHERE = (h, r, decide) -> return decide true
+    @PSTANDALONE = (h, r, d) -> d not h.objectOf Zombie

     # Register current service that invokes the method as parasite.
     # This means that the service will be automatically included to


minor syntax convs

minor syntax convs

--- library/nucleus/scaled.coffee
+++ library/nucleus/scaled.coffee
@@ -287,8 +287,8 @@
     # for instantiating, configuring and launching up the servers.
     # This version goes to the Seaport hub to obtain the options!
     startupHttpsServer: ->
-        type = "https".toUpperCase().bold
-        assert _.isObject config = nconf.get()
+        assert type = "https".toUpperCase().bold
+        assert _.isObject config = try nconf.get()
         assert _.isObject(@seaport), "got no seaport"
         msg = "Got #{type} port from the Seaport: %s"
         assert identica = @constructor.identica()
@@ -307,8 +307,8 @@
     # for instantiating, configuring and launching up the servers.
     # This version goes to the Seaport hub to obtain the options!
     startupHttpServer: ->
-        type = "http".toUpperCase().bold
-        assert _.isObject config = nconf.get()
+        assert type = "http".toUpperCase().bold
+        assert _.isObject config = try nconf.get()
         assert _.isObject(@seaport), "got no seaport"
         msg = "Got #{type} port from the Seaport: %s"
         assert identica = @constructor.identica()


qemux86-64.coffee: Remove archived:true instruction since we are now shipping an image and not a directory

Signed-off-by: Praneeth <fea9c151a4839e984ce3a4de9f1aa1eeae9d990b@gmail.com>

--- qemux86-64.coffee
+++ qemux86-64.coffee
@@ -39,7 +39,6 @@
 		fstype: 'resin-sdcard'
 		version: 'yocto-jethro'
 		deployArtifact: 'resin-image-qemux86-64.resin-sdcard'
-		archive: true
 		compressed: true

 	configuration:


Fix cat.coffee

Fix cat.coffee

--- scripts/cat.coffee
+++ scripts/cat.coffee
@@ -1,19 +1,20 @@
 # Description:
-#   Example scripts for you to examine and try out.
+#   Cat Images
 #
 # Notes:
-#   They are commented out by default, because most of them are pretty silly and
-#   wouldn't be useful and amusing enough for day to day huboting.
-#   Uncomment the ones you want to try and experiment with.
-#
-#   These are from the scripting documentation: https://github.com/github/hubot/blob/master/docs/scripting.md
+#   Cat
 # Commands:
 #   hubot cat - 猫(*´ω｀*)

 module.exports = (robot) ->
+  robot.hear /cat(\s*)$/i, (msg) ->
+    query = "猫"
+    imageMe msg, query, (url) ->
+      msg.send url

-  robot.hear /cat/i, (msg) ->
-    imageMe msg, "猫", (url) ->
+  robot.hear /cat (.+)/i, (msg) ->
+    query = "猫 " + msg.match[1]
+    imageMe msg, query, (url) ->
       msg.send url

 imageMe = (msg, query, animated, faces, cb) ->


Switched double quotes with single quotes

--- settings/dart.cson
+++ settings/dart.cson
@@ -1,3 +1,3 @@
-".source.dart":
+'.source.dart':
   editor:
-    commentStart: "// "
+    commentStart: '// '


remove mountpoint on umount

remove mountpoint on umount

--- kites/sharedHosting/mounter.coffee
+++ kites/sharedHosting/mounter.coffee
@@ -160,8 +160,15 @@
           if err
             callback err
           else
-            # @removeMount options,(err,res)->
-            callback null,res
+            fs.rmdir options.mountpoint, (err)->
+              # not a big issue
+              if err?
+                console.warn "Couldn't remove mountpoint #{options.mountpoint}: #{err.message}"
+              else
+                console.log "mountpoint #{options.mountpoint} has been removed"
+            @removeMountConf options,(err,res)->
+              callback err if err?
+              callback null,res

   # Safe
   readMountInfo: (options, callback)->
@@ -260,7 +267,7 @@
             log.info info = "[ok] config successfully created"
             callback null, info

-  removeMount: (options, callback)->
+  removeMountConf: (options, callback)->

     # this method will remove mount config related to remote host from user's mount config

@@ -295,6 +302,7 @@
           else
             log.info info = "[OK] config successfully updated"
             callback null, info
+

   mountSshDriveWithKey: (options, callback)->
     # mount SSHfs to the user's home directory
@@ -506,4 +514,4 @@
                 callback err

-module.exports = mounter+module.exports = mounter


updated z-index

updated z-index

--- public/dreamcatcher/controllers/entries/books_controller.coffee
+++ public/dreamcatcher/controllers/entries/books_controller.coffee
@@ -11,7 +11,7 @@

     $('#entryField .book').each (i, el) =>
       @closeBook $(el)
-      $(el).droppable {
+      $(el).droppable {
         drop: (ev, ui) =>
           entryMeta = {
             entry: {
@@ -22,6 +22,11 @@
           @entryModel.update entryId, entryMeta, =>
             notice 'successful moved'
             ui.draggable.remove()
+
+        over: (ev, ui) =>
+          bookEl = $(ev.target)
+          @openBook bookEl
+          $('.entryDrop-active', bookEl).show()
       }

     $('#entryField .thumb-2d').each (i, el) =>


Updates the file snippet

Updates the file snippet

--- snippets/file.cson
+++ snippets/file.cson
@@ -1,4 +1,4 @@
 '.source.inspec':
   'Describe file':
     'prefix': 'file'
-    'body': "# http://inspec.io/docs/reference/resources/file/\ndescribe file('${1:name}') do\n  it { should${2:_not} ${3:exist} }${4}\nend"
+    'body': "# http://inspec.io/docs/reference/resources/file/\ndescribe file('${1:/tmp/filename}') do\n  it { should${2:_not} ${3:exist} }\n  it { should be_owned_by '${4:user}'}\n  its('content') { should${5:_not} match /${6:content}/}${7}\nend"


Rename projection rebuilder's projectionsToRebuild to queue

--- source/server/infrastructure/projection-rebuilder.coffee
+++ source/server/infrastructure/projection-rebuilder.coffee
@@ -14,7 +14,7 @@
       throw new Error 'You have to provide an array of projection qualifiers.'

     realCollectionsBackups = {}
-    projectionsToRebuild = []
+    queue = []

     # Loop over all projections that should be rebuilt
     for projectionId in options.projections
@@ -27,11 +27,11 @@

       # Tell the projection that it will be rebuilt now
       projection.enterRebuildMode()
-      projectionsToRebuild.push projection
+      queue.push projection

     # Loop through all events and hand them individually to all projections
     for event in @commitStore.getAllEvents()
-      projection.on(event, true) for projection in projectionsToRebuild
+      projection.on(event, true) for projection in queue

     # Update the real collection data with the in-memory versions
     # for the specified projections only.
@@ -42,11 +42,11 @@
       if inMemoryData.length
         realCollection.batchInsert inMemoryData
       else
-        throw new Error "No data to insert after replaying projection for #{collectionId}"
+        throw new Error "No data to insert after replaying events for #{collectionId}"
       # Restore original collections
       @injector.override(collectionId).to realCollection

-    for projection in projectionsToRebuild
+    for projection in queue
       projection.exitRebuildMode()

   _getCollectionIdsOfProjection: (projection) ->


update image urls

update image urls

--- src/ihavenoidea.coffee
+++ src/ihavenoidea.coffee
@@ -28,20 +28,21 @@
 ]

 images = [
-  'http://i.imgur.com/pOme4ix.jpg',
-  'http://i3.kym-cdn.com/photos/images/original/000/234/739/fa5.jpg',
-  'http://i1.kym-cdn.com/photos/images/original/000/234/765/b7e.jpg',
-  'http://i0.kym-cdn.com/photos/images/original/000/234/142/196.jpg',
-  'http://i2.kym-cdn.com/photos/images/original/000/234/137/5c4.jpg',
-  'http://i3.kym-cdn.com/photos/images/newsfeed/000/490/406/dd3.jpeg',
-  'http://i0.kym-cdn.com/photos/images/newsfeed/000/464/510/a5b.jpg',
-  'http://i1.kym-cdn.com/photos/images/original/000/310/183/6a0.jpg',
-  'http://i3.kym-cdn.com/photos/images/original/000/308/125/1ee.jpg',
-  'http://i0.kym-cdn.com/photos/images/original/000/305/236/ddc.jpg',
-  'http://i3.kym-cdn.com/photos/images/original/000/305/235/07a.jpg',
-  'http://i0.kym-cdn.com/photos/images/original/000/284/499/a69.jpg',
-  'http://i1.kym-cdn.com/photos/images/original/000/258/461/be0.jpg',
-  'http://i0.kym-cdn.com/photos/images/original/000/234/767/8d0.jpg'
+  'http://imgur.com/XhZzd2h',
+  'http://imgur.com/GtgkJ38',
+  'http://imgur.com/Jv3qULQ',
+  'http://imgur.com/1hrVmZD',
+  'http://imgur.com/xC0JCFK',
+  'http://imgur.com/kFNAAeX',
+  'http://imgur.com/9s62t7y',
+  'http://imgur.com/QJ4MoXP',
+  'http://imgur.com/ugZ2tGn',
+  'http://imgur.com/DeyWrC2',
+  'http://imgur.com/tkbLyTG',
+  'http://imgur.com/g8EbISz',
+  'http://imgur.com/RuFZdPR',
+  'http://imgur.com/YLEM3Ns',
+  'http://imgur.com/1TWbKbW'
 ]

 regex = new RegExp gaffes.join('|'), 'ig'


Code cleanup

Code cleanup


fixed .DESCRIPTION prefix

fixed .DESCRIPTION prefix

--- snippets/language-powershell.cson
+++ snippets/language-powershell.cson
@@ -12,7 +12,7 @@
     'prefix': 'new'
     'body': 'New-Object'
   '.DESCRIPTION':
-    'prefix': '.s'
+    'prefix': '.d'
     'body': '.DESCRIPTION\n'
   '.EXAMPLE':
     'prefix': '.e'


Update insert function snippet.

Update insert function snippet.

Add LINK section to comments. Remove one of the EXAMPLE sections. Add an OUTPUTS section. Indent the comments correctly. Capitalize the SYNOPSIS keyword. Fix variable for body.

--- snippets/language-powershell.cson
+++ snippets/language-powershell.cson
@@ -25,7 +25,7 @@
     'body': '.SYNOPSIS\n'
   'Function Cmdlet':
     'prefix': 'func'
-    'body': '<#\n.Synopsis\nShort description\n.DESCRIPTION\nLong description\n.EXAMPLE\nExample of how to use this cmdlet\n.EXAMPLE\nAnother example of how to use this cmdlet\n#>\nfunction ${1:Verb}-${2:Noun}\n{\n\t[CmdletBinding()]\n\t[OutputType([int])]\n\tParam\n\t(\n\t\t# Param1 help description\n\t\t[Parameter(Mandatory, ValueFromPipelineByPropertyName, Position=0)]\n\t\t\$Param1,\n\n\t\t# Param2 help description\n\t\t[int]\n\t\t\$Param2\n\t)\n\tBegin\n\t{$\n\t\t{3:# code}\n\t}\n\tProcess\n\t{\n\t}\n\tEnd\n\t{\n\t}\n}'
+    'body': '<#\n.SYNOPSIS\n\tShort description\n\n.DESCRIPTION\n\tLong description\n\n.OUTPUTS\n\tThe value returned by this cmdlet\n\n.EXAMPLE\n\tExample of how to use this cmdlet\n\n.LINK\n\tTo other relevant cmdlets or help\n#>\nFunction ${1:Verb}-${2:Noun}\n{\n\t[CmdletBinding()]\n\t[OutputType([Nullable])]\n\tParam\n\t(\n\t\t# Param1 help description\n\t\t[Parameter(Mandatory, ValueFromPipelineByPropertyName, Position=0)]\n\t\t\$Param1,\n\n\t\t# Param2 help description\n\t\t[int]\n\t\t\$Param2\n\t)\n\tBegin\n\t{\n\t\t${3:# code}\n\t}\n\tProcess\n\t{\n\t}\n\tEnd\n\t{\n\t}\n}'
   'Switch':
     'prefix': 'switch'
     'body': 'switch (\$${1:x})\n{\n\t"value1" {}\n\t{\$_ -in "A","B","C"} {}\n\t"value3" {}\n\tDefault {}\n}'


Move Dispatcher#{current,previous}Route initialization one level lower to avoid setting them before promise is resolved

--- src/chaplin/dispatcher.coffee
+++ src/chaplin/dispatcher.coffee
@@ -92,10 +92,8 @@

   # Handler for the controller lazy-loading.
   controllerLoaded: (route, params, options, Controller) ->
-    @previousRoute = @currentRoute
-    @currentRoute = _.extend {}, route, {previous: utils.beget(@previousRoute)}
-    controller = new Controller params, @currentRoute, options
-    @executeBeforeAction controller, @currentRoute, params, options
+    controller = new Controller params, route, options
+    @executeBeforeAction controller, route, params, options

   # Executes controller action.
   executeAction: (controller, route, params, options) ->
@@ -130,9 +128,11 @@
     before = controller.beforeAction

     executeAction = =>
-      if controller.redirected or @currentRoute and route isnt @currentRoute
+      if controller.redirected or @currentRoute and route is @currentRoute
         controller.dispose()
         return
+      @previousRoute = @currentRoute
+      @currentRoute = _.extend {}, route, {previous: utils.beget(@previousRoute)}
       @executeAction controller, route, params, options

     unless before


Fix to ensure a controller gets disposed if there is a redirect in the action

--- src/chaplin/dispatcher.coffee
+++ src/chaplin/dispatcher.coffee
@@ -98,13 +98,13 @@

       # Passing new parameters that the action method will receive.
       @currentController.dispose params, route, options
-
-    # Call the controller action with params and options.
-    controller[route.action] params, route, options
-
+
     # Save the new controller and its parameters.
     @currentController = controller
     @currentParams = params
+
+    # Call the controller action with params and options.
+    controller[route.action] params, route, options

     # Stop if the action triggered a redirect.
     return if controller.redirected


Fix not sending a response to /favicon.ico requests.

Otherwise, it waits until the connection times out.

--- viewer/app.coffee
+++ viewer/app.coffee
@@ -77,7 +77,10 @@
     return tag_html

 handleRequests = (request, response, next) ->
-    unless request.url is '/favicon.ico'
+    if request.url is '/favicon.ico'
+        response.writeHead(404)
+        response.end()
+    else
         # The GitHub API doesn't handle trailing slashes, so trim them.
         url = request.url
         if url[url.length - 1] is '/'


Simplify tests

Simplify tests

--- test/index.coffee
+++ test/index.coffee
@@ -1,8 +1,6 @@
 assert = require('assert')
-jsdom = require('jsdom').jsdom
-doc = jsdom('')
-global.window = doc.createWindow()
-$      = require('jquery')
+window = require('jsdom').jsdom().createWindow()
+$      = require('jquery')(window)
 global.jQuery = $

 require('../src/jquery.payment')
@@ -138,7 +136,7 @@
     it 'should fail if year or month is NaN', ->
       topic = $.payment.validateCardExpiry '12', NaN
       assert.equal topic, false
-
+
     it 'should support year shorthand', ->
       assert.equal $.payment.validateCardExpiry('05', '20'), true