Adding some comments to the js file

Adding some comments to the js file

--- sli/admin-tools/admin-rails/app/assets/javascripts/realms.js.coffee
+++ sli/admin-tools/admin-rails/app/assets/javascripts/realms.js.coffee
@@ -2,6 +2,10 @@
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

+# Converts the data returned by the realm API into a simpler object
+# that's basically an array of table rows, the first column being
+# the client role and the second being the SLI role.
+# e.g. [ ['foo', 'Educator'], ['bar', 'Leader'] ]
 `getTableData = function(json) {
         toReturn = [];
         for (var i in json.role) {
@@ -26,6 +30,9 @@
 	return map;
 }
 `
+
+# Takes our table data and converts it into the mapping object
+# needed by the API.
 `mapData = function(data) {
 	var map = {};
 	var role = [];
@@ -45,6 +52,7 @@
 	return map;
 }`

+# Helper function used by mapData
 `
 getSliRoleObject = function(sliRole, roleData) {
   for (var i in roleData) {


tab space size is corrected

tab space size is corrected

--- client/landing/app/CommonViews/linkviews/grouplinkview.coffee
+++ client/landing/app/CommonViews/linkviews/grouplinkview.coffee
@@ -1,13 +1,13 @@
 class GroupLinkView extends LinkView

-	constructor: (options = {}, data) ->
-		super options, data
-		@setClass "profile"
+  constructor: (options = {}, data) ->
+    super options, data
+    @setClass "profile"

-	render:->
-		slug = @getData().slug
-		@setAttribute "href", "/#{slug}"
-		super
+  render:->
+    {slug} = @getData()
+    @setAttribute "href", "/#{slug}"
+    super

-	pistachio:->
-		super "{{#(title)}}"
+  pistachio:->
+    super "{{#(title)}}"


profile: hide edit button for about input when editing

--- client/landing/app/MainApp/lazy/staticprofileaboutview.coffee
+++ client/landing/app/MainApp/lazy/staticprofileaboutview.coffee
@@ -28,6 +28,7 @@
         callback : =>
           @$('.about-body').addClass 'hidden'
           @editView.show()
+          @editButton.hide()
       @editView = new KDView
         cssClass : 'hidden about-edit'

@@ -48,6 +49,7 @@
             @$('.about-body').removeClass 'hidden'
             @saveButton.hideLoader()
             @aboutView.updatePartial Encoder.htmlDecode value.html
+            @editButton.show()

       @editView.addSubView @cancelButton = new KDButtonView
         title : 'Cancel'
@@ -55,7 +57,7 @@
         callback :=>
           @editView.hide()
           @$('.about-body').removeClass 'hidden'
-
+          @editButton.show()
     else
       @editButton = new KDView
         cssClass : 'hidden'


little cleanup working prototype

little cleanup working prototype

--- views/index.coffee
+++ views/index.coffee
@@ -84,8 +84,6 @@
       refreshPositions: true
       start: (event, ui) ->
         className = ui.helper.context.className.toString()
-        startTop = ui.offset.top
-        start_left = ui.offset.left
       stop: (event, ui) ->
         piecePath= ui.helper.context.src.match(/chess_pieces*.*/)
         pieceName = piecePath.toString().replace("chess_pieces/", "")


Remove unused test artifacts

Remove unused test artifacts

--- test/unit/client_test.coffee
+++ test/unit/client_test.coffee
@@ -107,7 +107,6 @@
       expect(client.getSession().key1).to.equal("[custom_session_key1_value]")

   describe 'filters', ->
-    backtrace_line = null
     process      = null
     report       = null
     getProcessor = null
@@ -115,8 +114,7 @@
     client       = null

     beforeEach ->
-      backtrace_line = sinon.spy()
-      process        = sinon.spy((error) -> { backtrace: [ backtrace_line ] })
+      process        = sinon.spy((error) -> {})
       report         = sinon.spy()
       getProcessor   = -> { process: process }
       getReporter    = -> { report: report }


added first set unit tests

added first set unit tests

--- tests/bb_set.test.coffee
+++ tests/bb_set.test.coffee
@@ -1,15 +1,70 @@
 assert = require "assert"
 { BankersBox } = require "bankersbox"

-exports.testDummy = ->
-  assert.equal true, true, "dummy test"
+exports.testTypeSet = ->
+  bb = new BankersBox(1)
+  bb.sadd "myset", "foo"
+  assert.equal bb.type("myset"), "set", "test set type"
+
+exports.testSaddNewMember = ->
+  bb = new BankersBox(1)
+  assert.equal bb.sadd("foo", "bar"), 1, "test sadd new member"
+
+exports.testSaddExistingMember = ->
+  bb = new BankersBox(1)
+  bb.sadd "foo", "bar"
+  assert.equal bb.sadd("foo", "bar"), 0, "test sadd existing member"
+
+exports.testScardNonKey = ->
+  bb = new BankersBox(1)
+  assert.equal bb.scard("myset"), 0, "test scard non existent key"
+
+exports.testScard = ->
+  bb = new BankersBox(1)
+  bb.sadd "myset", "a"
+  bb.sadd "myset", "b"
+  bb.sadd "myset", "c"
+  assert.equal bb.scard("myset"), 3, "test scard"
+
+exports.testSisimemberNonKey = ->
+  bb = new BankersBox(1)
+  assert.equal bb.sismember("myset", "foo"), false, "test sismember non existent key"
+
+exports.testSismemberTrue = ->
+  bb = new BankersBox(1)
+  bb.sadd "myset", "foo"
+  bb.sadd "myset", "bar"
+  assert.equal bb.sismember("myset", "foo"), true, "test sismember true 1"
+  assert.equal bb.sismember("myset", "bar"), true, "test sismember true 2"
+
+exports.testSismemberTrue = ->
+  bb = new BankersBox(1)
+  bb.sadd "myset", "foo"
+  bb.sadd "myset", "bar"
+  assert.equal bb.sismember("myset", "baz"), false, "test sismember false 1"
+  assert.equal bb.sismember("myset", "qux"), false, "test sismember false 2"
+
+exports.testSmembersNonKey = ->
+  bb = new BankersBox(1)
+  assert.eql bb.smembers("myset"), [], "test smemebers non existent key"
+
+exports.testSmembers = ->
+  bb = new BankersBox(1)
+  bb.sadd "myset", "a"
+  bb.sadd "myset", "b"
+  bb.sadd "myset", "c"
+  ret = bb.smembers "myset"
+  assert.equal ret.length, 3, "test smembers return length"
+  assert.includes ret, "a", "test smembers contains a"
+  assert.includes ret, "b", "test smembers contains b"
+  assert.includes ret, "c", "test smembers contains c"

 ###
 * [SETS](http://redis.io/commands#set
-  * sadd
-  * scard
-  * sismember
-  * smembers
+  x* sadd
+  x* scard
+  x* sismember
+  x* smembers
   * smove
   * spop
   * srandmember


Check for property in keys.

Check for property in keys.

--- test/unit/helpersSpec.coffee
+++ test/unit/helpersSpec.coffee
@@ -69,12 +69,12 @@
             .to.equal(obj.anInt)

         it 'should make the camelCase alias enumerable', ->
-          expect('anInt' of obj, 'The camelCase property is' +
+          expect('anInt' in Object.keys(obj), 'The camelCase property is' +
                                               ' still enumerable')
             .to.be.true

         it 'should make the underscore property non-enumerable', ->
-          expect('an_int' of obj, 'The underscore property is' +
+          expect('an_int' in Object.keys(obj), 'The underscore property is' +
                                                ' still enumerable')
             .to.be.false


Updates the query for further install shots to MPv2.

--- src/desktop/apps/show/components/flickity_zoom_sequence/view.coffee
+++ src/desktop/apps/show/components/flickity_zoom_sequence/view.coffee
@@ -17,7 +17,7 @@
       variables: show_id: @showId, page: @page
       query: '
         query ShowInstallShotsViewQuery ($show_id: String!, $page: Int) {
-          partner_show(id: $show_id) {
+          partner_show: show(id: $show_id) {
             install_shots: images(page: $page, default: false) {
               carousel_dimension: resized(height: 300, version: "large") {
                 width


fix typo in Errors, only two underscores in __proto__

--- services/web/app/coffee/Features/Errors/Errors.coffee
+++ services/web/app/coffee/Features/Errors/Errors.coffee
@@ -31,56 +31,56 @@
 	error.name = "UnsupportedFileTypeError"
 	error.__proto__ = UnsupportedFileTypeError.prototype
 	return error
-UnsupportedFileTypeError.prototype.__proto___ = Error.prototype
+UnsupportedFileTypeError.prototype.__proto__ = Error.prototype

 UnsupportedBrandError = (message) ->
 	error = new Error(message)
 	error.name = "UnsupportedBrandError"
 	error.__proto__ = UnsupportedBrandError.prototype
 	return error
-UnsupportedBrandError.prototype.__proto___ = Error.prototype
+UnsupportedBrandError.prototype.__proto__ = Error.prototype

 UnsupportedExportRecordsError = (message) ->
 	error = new Error(message)
 	error.name = "UnsupportedExportRecordsError"
 	error.__proto__ = UnsupportedExportRecordsError.prototype
 	return error
-UnsupportedExportRecordsError.prototype.__proto___ = Error.prototype
+UnsupportedExportRecordsError.prototype.__proto__ = Error.prototype

 V1HistoryNotSyncedError = (message) ->
 	error = new Error(message)
 	error.name = "V1HistoryNotSyncedError"
 	error.__proto__ = V1HistoryNotSyncedError.prototype
 	return error
-V1HistoryNotSyncedError.prototype.__proto___ = Error.prototype
+V1HistoryNotSyncedError.prototype.__proto__ = Error.prototype

 ProjectHistoryDisabledError = (message) ->
 	error = new Error(message)
 	error.name = "ProjectHistoryDisabledError"
 	error.__proto__ = ProjectHistoryDisabledError.prototype
 	return error
-ProjectHistoryDisabledError.prototype.__proto___ = Error.prototype
+ProjectHistoryDisabledError.prototype.__proto__ = Error.prototype

 V1ConnectionError = (message) ->
 	error = new Error(message)
 	error.name = "V1ConnectionError"
 	error.__proto__ = V1ConnectionError.prototype
 	return error
-V1ConnectionError.prototype.__proto___ = Error.prototype
+V1ConnectionError.prototype.__proto__ = Error.prototype

 UnconfirmedEmailError = (message) ->
 	error = new Error(message)
 	error.name = "UnconfirmedEmailError"
 	error.__proto__ = UnconfirmedEmailError.prototype
 	return error
-UnconfirmedEmailError.prototype.__proto___ = Error.prototype
+UnconfirmedEmailError.prototype.__proto__ = Error.prototype

 EmailExistsError = (message) ->
 	error = new Error(message)
 	error.name = "EmailExistsError"
 	error.__proto__ = EmailExistsError.prototype
 	return error
-EmailExistsError.prototype.__proto___ = Error.prototype
+EmailExistsError.prototype.__proto__ = Error.prototype

 module.exports = Errors =
 	NotFoundError: NotFoundError


remove console.log

remove console.log

--- services/clsi/app/coffee/CompileManager.coffee
+++ services/clsi/app/coffee/CompileManager.coffee
@@ -161,7 +161,6 @@
 			catch err
 				logger.err err:err, command:command, directory:directory, project_id:project_id, "error reading word count output"
 				return callback(err)
-			console.log "rooooof"
 			callback null, CompileManager._parseWordcountFromOutput(stdout)

 	_parseWordcountFromOutput: (output) ->


fixed

fixed

--- test/init.test.coffee
+++ test/init.test.coffee
@@ -1,14 +1,13 @@
 ## -- Dependencies -----------------------------------------------------------------------

+fs        = require 'fs'
 pkg       = require '../package.json'
-fs        = require 'fs'
 scripts   = require 'sailor-scripts'

 ## -- Setup ------------------------------------------------------------------------------

 opts =
   log: level: "silent"
-  plugins: [pkg.name]

 SCOPE =
   MODULE       : process.cwd()
@@ -21,7 +20,7 @@
     scripts.newBase ->
       scripts.linkDependency dependency for dependency in SCOPE.DEPENDENCIES
       scripts.link SCOPE.MODULE, SCOPE.LINK
-      scripts.writePluginFile pkg.name
+      scripts.writeModuleFile pkg.name
       scripts.lift SCOPE.TEST, opts, done
   else
     scripts.clean "#{SCOPE.TEST}/.tmp/"


Removed old test file.

Removed old test file.

--- test/newserver.coffee
+++ test/newserver.coffee
@@ -1,50 +0,0 @@
-Path          = require('path')
-EventEmitter  = require('events').EventEmitter
-Server        = require('../lib/server')
-BrowserServer = require('../lib/server/browser_server')
-
-class MockClient extends EventEmitter
-
-server = null
-browsers = null
-
-exports['tests'] =
-    'setup' : (test) ->
-        server = new Server
-            appPath : '/'
-            staticDir : Path.join(__dirname, 'files')
-        server.once 'ready', () ->
-            browsers = server.browsers
-            test.done()
-
-    'basic' : (test) ->
-        bserver = new BrowserServer('browser1')
-        browser = bserver.browser
-        client = new MockClient()
-        client.on 'loadFromSnapshot', (cmd) ->
-            console.log('loadFromSnapshot')
-            console.log(cmd)
-        client.on 'attachSubtree', (cmd) ->
-            console.log('attachSubtree')
-            console.log(cmd)
-            test.done()
-        browser.load('http://localhost:3001/blank.html')
-        browser.once 'load', () ->
-            doc = browser.window.document
-            doc.body.appendChild(doc.createElement('div'))
-            bserver.addSocket(client)
-            setTimeout () ->
-                testDiv = doc.createElement('div')
-                embedded = doc.createElement('div')
-                testDiv.appendChild(embedded)
-                doc.body.appendChild(testDiv)
-            , 0
-
-    'teardown' : (test) ->
-        server.once 'close', () ->
-            reqCache = require.cache
-            for entry of reqCache
-                if /jsdom/.test(entry)
-                    delete reqCache[entry]
-            test.done()
-        server.close()


Remove extracted method

Remove extracted method

--- app/assets/javascripts/admin/bulk_product_update.js.coffee
+++ app/assets/javascripts/admin/bulk_product_update.js.coffee
@@ -237,15 +237,6 @@
       if $scope.limit < $scope.products.length
         $scope.limit = $scope.limit + 5

-    $scope.setMessage = (model, text, style, timeout) ->
-      model.text = text
-      model.style = style
-      $timeout.cancel model.timeout  if model.timeout
-      if timeout
-        model.timeout = $timeout(->
-          $scope.setMessage model, "", {}, false
-        , timeout, true)
-

     $scope.displayUpdating = ->
       StatusMessage.display 'progress', 'Saving...'


Temporary Internet Explorer fix for Non Touch Screen devices.

--- source/scripts/utils/touch.coffee
+++ source/scripts/utils/touch.coffee
@@ -1,2 +1,2 @@
-isMobile = !!('ontouchstart' of window) or !!('onmsgesturechange' of window)
+isMobile = !!('ontouchstart' of window) or navigator.msMaxTouchPoints
 module.exports = isMobile


Update analytics.log.event indexes to match prod

These were applied as single indexes directly in production.

--- server/analytics/AnalyticsLogEvent.coffee
+++ server/analytics/AnalyticsLogEvent.coffee
@@ -6,6 +6,7 @@
     type: Date
     'default': Date.now
 }, {strict: false})
-AnalyticsLogEventSchema.index({event: 1, created: -1})
+AnalyticsLogEventSchema.index event: 1
+AnalyticsLogEventSchema.index created: -1

 module.exports = AnalyticsLogEvent = mongoose.model('analytics.log.event', AnalyticsLogEventSchema)


Add brackets in account resource

Add brackets in account resource

--- app/assets/javascripts/sprangular/resources/account.coffee
+++ app/assets/javascripts/sprangular/resources/account.coffee
@@ -72,7 +72,8 @@
     signup: (data) ->
       params =
         spree_user: data
-      $http.post '/api/account', $.param params
+
+      $http.post('/api/account', $.param(params))
         .success (data) ->
           service.reload().then (data) ->
             Cart.reload()


Makes hashes work properly in new files folder names

fixes CNVS-17694

Test Plan:
	- Enable New Files
	- Add a folder with a hash in the name (e.g. Chapter #1)
	- You should not get a 404 error when navigating to that folder.

Change-Id: I4f5f9e0e4388d4280e972b1ba1fcc47b6231a609
Reviewed-on: https://gerrit.instructure.com/46405
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
QA-Review: Jahnavi Yetukuri <ed2b2672ccc2e59e56c0615df7f01b579202e014@instructure.com>
Product-Review: Clay Diffrient <9dff2e5c98626d20d2848250c411e8009465bb87@instructure.com>

--- app/coffeescripts/react_files/components/ShowFolder.coffee
+++ app/coffeescripts/react_files/components/ShowFolder.coffee
@@ -41,7 +41,13 @@
       @props.currentFolder?.off(null, null, this)

     buildFolderPath: (splat) ->
-      encodeURI('/' + (splat || ''))
+      # We don't want the slashes to go away so we are doing some magic here
+      if (splat)
+        splat = splat.split('/').map((splatPiece) ->
+          encodeURIComponent(splatPiece)
+        ).join('/')
+
+      '/' + (splat || '')

     getCurrentFolder: ->
       path = @buildFolderPath(@props.params.splat)


add litcoffee to supported file formats

add litcoffee to supported file formats

--- command.coffee
+++ command.coffee
@@ -57,6 +57,7 @@
 notSources   = {}
 watchers     = {}
 optionParser = null
+coffee_exts  = ['.coffee', '.litcoffee']

 # Run `coffee` by parsing passed options and determining what action to take.
 # Many flags cause us to divert before compiling anything. Flags passed after
@@ -81,13 +82,13 @@
     compilePath source, yes, path.normalize source

 # Compile a path, which could be a script or a directory. If a directory
-# is passed, recursively compile all '.coffee' extension source files in it
-# and all subdirectories.
+# is passed, recursively compile all '.coffee' and '.litcoffee' extension source
+# files in it and all subdirectories.
 compilePath = (source, topLevel, base) ->
   fs.stat source, (err, stats) ->
     throw err if err and err.code isnt 'ENOENT'
     if err?.code is 'ENOENT'
-      if topLevel and source[-7..] isnt '.coffee'
+      if topLevel and source[-7..] not in coffee_exts
         source = sources[sources.indexOf(source)] = "#{source}.coffee"
         return compilePath source, topLevel, base
       if topLevel
@@ -105,7 +106,7 @@
         sourceCode[index..index] = files.map -> null
         files.forEach (file) ->
           compilePath (path.join source, file), no, base
-    else if topLevel or path.extname(source) is '.coffee'
+    else if topLevel or path.extname(source) in coffee_exts
       watch source, base if opts.watch
       fs.readFile source, (err, code) ->
         throw err if err and err.code isnt 'ENOENT'


Add fill defaults button to solutions treema node in level editor

--- app/views/editor/component/ThangComponentConfigView.coffee
+++ app/views/editor/component/ThangComponentConfigView.coffee
@@ -73,6 +73,7 @@
         'acceleration': nodes.AccelerationNode
         'thang-type': nodes.ThangTypeNode
         'item-thang-type': nodes.ItemThangTypeNode
+        'solutions': SolutionsNode

     @editThangTreema = @$el.find('.treema').treema treemaOptions
     @editThangTreema.build()
@@ -94,3 +95,30 @@

 class ComponentConfigNode extends TreemaObjectNode
   nodeDescription: 'Component Property'
+
+class SolutionsNode extends TreemaArrayNode
+  buildValueForDisplay: (valEl, data) ->
+    btn = $('<button class="btn btn-default btn-xs">Fill defaults</button>')
+    btn.on('click', @onClickFillDefaults)
+    valEl.append(btn)
+
+  onClickFillDefaults: (e) =>
+    e.preventDefault()
+    sources = {}
+    if source = @parent.data.source
+      sources.javascript = source
+
+    sources = { javascript: @parent.data.source }
+    _.extend sources, @parent.data.languages or {}
+    solutions = _.clone(@data)
+    for language in _.keys(sources)
+      source = sources[language]
+      solution = _.findWhere(solutions, {language: language})
+      continue if solution
+      solutions.push({
+        source: source
+        language: language
+        passes: true
+      })
+
+    @set('/', solutions)


Add errors class to integration when errors are present

--- app/assets/javascripts/admin/views/home/integration.js.coffee
+++ app/assets/javascripts/admin/views/home/integration.js.coffee
@@ -17,6 +17,8 @@

     if @model.is_custom()
       @$el.addClass 'custom'
+    if @model.get('errors')
+      @$el.addClass 'errors'
     if @model.is_pending()
       @$el.addClass 'pending'
     @$el.addClass 'integration'


Corrige routing no IE

Corrige routing no IE

O IE9 (pelo menos) tem window.history, mas não tem window.history.pushState,
então damos fallback para recarregar a página.

--- app/assets/javascripts/angular_app/services/routing.js.coffee
+++ app/assets/javascripts/angular_app/services/routing.js.coffee
@@ -32,7 +32,7 @@
     updateRoute: (entity, year) ->
       newUrl = generateUrl(entity, year)
       if window.location.pathname != newUrl
-        if window.history && (!entity || !inRootPage())
+        if window.history && window.history.pushState && (!entity || !inRootPage())
           window.history.pushState({}, '', newUrl)
         else
           window.location.pathname = newUrl


updating news batman controller

updating news batman controller

--- app/assets/javascripts/ems/controllers/news_controller.coffee
+++ app/assets/javascripts/ems/controllers/news_controller.coffee
@@ -1,106 +1,119 @@
 class Ems.NewsController extends Batman.Controller

-    news: null
-    channels: null
-    suggestTags: new Batman.Set
-    allTags: null
-    selectedChannels: []
-    tags: new Batman.Set
+  news: null
+  channels: null
+  suggestTags: new Batman.Set
+  allTags: null
+  selectedChannels: []
+  tags: new Batman.Set

-    index: (params) ->
+  index: (params) ->
+    @set 'categorySlug', params.category
+    filters = {'category_slug':params.category}
+    Ems.News.load {'filters':filters}, (err, news) =>
+      throw err if err
+      @set 'news', Ems.News.get('loaded')
+
+  show: (params) ->

-    show: (params) ->
+  # New action, setup all objects needed by the template.
+  new: (params) ->
+    @set 'news', new Ems.News
+    # give the article the correct category
+    # @todo we need to be able to retrieve the category by its slug from the server rather than going round the houses
+    # like its currently done
+    @set 'category', Ems.Category.find parseInt(params.categoryId), (err) =>
+      @redirect '/404' if err?.status is 404
+      throw err if err
+
+      @set 'channels', new Batman.Set
+      @observe 'category', (category, oldCategory)=>
+        @set 'news.category', newVal
+        @set 'channels', @get 'category.channels'
+
+
+      # # indicator to let us know if we got a valid category slug
+      # found = false
+      # # iterate through returned category and check if the result returned includes one with our slug
+      # for cat in cats
+      #   if(cat.get('slug') == params.category)
+      #     found = true
+      #     @get('article').set('category', cat)
+      #     @set 'channels', @get 'article.category.channels'
+      # # WHOOPS, we dont seems to have a valid slug or atleast there is no category on the server with this slug
+      # @redirect '/404' unless found

-    # New action, setup all objects needed by the template.
-    new: (params) ->
-      @set 'news', new Ems.News
-      # give the news the correct category
-      # @todo we need to be able to retrieve the category by its slug from the server rather than going round the houses
-      # like its currently done
-      Ems.Category.load (err, cats) =>
-        throw err if err
-        # indicator to let us know if we got a valid category slug
-        found = false
-        # iterate through returned category and check if the result returned includes one with our slug
-        for cat in cats
-          if(cat.get('slug') == params.category)
-            found = true
-            @get('news').set('category', cat)
-            @set 'channels', @get 'news.category.channels'
-        # WHOOPS, we dont seems to have a valid slug or atleast there is no category on the server with this slug
-        @redirect '/404' unless found
+  # Lets go and persist the new article on the server
+  create: (params) ->
+    @get('news').save (err) =>
+      if err
+        throw err unless err instanceof Batman.ErrorsSet
+      else
+        Ems.flashSuccess "News #{@get('news.name')} created successfully!"

-    # Lets go and persist the new news on the server
-    create: (params) ->
-      @get('news').save (err) =>
-        if err
-          throw err unless err instanceof Batman.ErrorsSet
-        else
-          Ems.flashSuccess "News #{@get('news.name')} created successfully!"
+  # edit action - performs all queries to retrieve the object and all relation from the server for the object id we've
+  # been given in params
+  edit: (params) ->
+    @set 'news', Ems.News.find parseInt(params.id), (err) =>
+      @redirect '/404' if err?.status == 404
+      throw err if err
+    @get('news.category').fetch (err, category) =>
+      throw err if err
+      console?.log category
+      @set 'channels', category.get 'channels'
+    # We need to wait a while for the tags to be loaded
+    setTimeout(=>
+      @set 'tags', @get('news.tags')
+    , 100)
+
+    setTimeout(=>
+          channels = @get 'news.channels'
+          if channels
+            @get('selectedChannels').push channel.id for channel in channels.toArray()
+        , 100)

-    # edit action - performs all queries to retrieve the object and all relation from the server for the object id we've
-    # been given in params
-    edit: (params) ->
-      @set 'news', Ems.News.find parseInt(params.id), (err) =>
-        @redirect '/404' if err?.status == 404
-        throw err if err
-      @get('news.category').fetch (err, category) =>
-        throw err if err
-        @set 'channels', category.get 'channels'
-      # We need to wait a while for the tags to be loaded
+  update: ->
+    @get('news').save (err) =>
+      if err
+        throw err unless err instanceof Batman.ErrorsSet
+      else
+        Ems.flashSuccess "News #{@get('news.name')} updated successfully!"
+        @redirect '/articles'
+
+  # function to handle the selecting and deselecting of categories
+  toggleChannel: (node, event) ->
+    # get all channels available for the current category
+    channels = @get 'channels'
+    newChannels = new Batman.Set
+    # populate new channels with selected channels
+    for c in node when c.nodeType is 1 and c.selected is true
+      channel = channels.indexedByUnique('id').get(parseInt(c.value))
+      if channel
+        newChannels.add channel
+    # replace old channels with new channels
+    @set 'news.channels', newChannels
+
+  # Search tags function. This function loads all tags into a collection and uses it to search through the collection to
+  # find tags that are simillar to the letters typed
+  suggestTags: (node, event) ->
+    if node.value.length > 0
+      if not @get 'allTags'
+        Ems.Tag.load (err, tags) =>
+          throw err if err
+          @set 'allTags', Ems.Tag.get 'loaded'
       setTimeout(=>
-        @set 'tags', @get('news.tags')
-      , 100)
-
-      setTimeout(=>
-        channels = @get 'news.channels'
-        if channels
-          @get('selectedChannels').push channel.id for channel in channels.toArray()
-      , 100)
+        suggestTags = new Batman.Set
+        tags = @get('allTags')
+        for tag in tags.toArray() when tag.get('title').indexOf(node.value) >= 0
+          suggestTags.add tag
+        @set 'suggestTags', suggestTags
+      ,100)

-    update: ->
-      @get('news').save (err) =>
-        if err
-          throw err unless err instanceof Batman.ErrorsSet
-        else
-          Ems.flashSuccess "News #{@get('news.name')} updated successfully!"
-          @redirect '/newss'
+  addTag: (node, value) ->
+    tag = @get('allTags').indexedByUnique('id').get(parseInt(node.id))
+    @get('news.tags').add(tag)

-    # function to handle the selecting and deselecting of categories
-    toggleChannel: (node, event) ->
-      # get all channels available for the current category
-      channels = @get 'channels'
-      newChannels = new Batman.Set
-      # populate new channels with selected channels
-      for c in node when c.nodeType is 1 and c.selected is true
-        channel = channels.indexedByUnique('id').get(parseInt(c.value))
-        if channel
-          newChannels.add channel
-      # replace old channels with new channels
-      @set 'news.channels', newChannels
-
-    # Search tags function. This function loads all tags into a collection and uses it to search through the collection to
-    # find tags that are simillar to the letters typed
-    suggestTags: (node, event) ->
-      if node.value.length > 0
-        if not @get 'allTags'
-          Ems.Tag.load (err, tags) =>
-            throw err if err
-            @set 'allTags', Ems.Tag.get 'loaded'
-        setTimeout(=>
-          suggestTags = new Batman.Set
-          tags = @get('allTags')
-          for tag in tags.toArray() when tag.get('title').indexOf(node.value) >= 0
-            suggestTags.add tag
-          @set 'suggestTags', suggestTags
-        ,100)
-
-    addTag: (node, value) ->
-      tag = @get('allTags').indexedByUnique('id').get(parseInt(node.id))
-      @get('news.tags').add(tag)
-
-    removeTag: (node, value) ->
-      tag = @get('news.tags').indexedByUnique('id').get(parseInt(node.id))
-      @get('news.tags').remove(tag)
-  +  removeTag: (node, value) ->
+    tag = @get('news.tags').indexedByUnique('id').get(parseInt(node.id))
+    @get('news.tags').remove(tag)


Update volume

Update volume

--- lib/AudioPlayer.coffee
+++ lib/AudioPlayer.coffee
@@ -16,7 +16,7 @@
     @_worker = new AudioWorker(STD_LIB + compiledSource)
     @_audioSource = @globalAudioContext.createScriptProcessor(constants.AUDIO_BUFFER_SIZE, 0, 2)
     @_audioSource.onaudioprocess = (event) =>
-      volume = 0.4
+      volume = 0.25
       left  = event.outputBuffer.getChannelData(0)
       right = event.outputBuffer.getChannelData(1)
       nextBuffer = @_worker.pop()


:bug: [editor-linter] Fix invalid function call

--- lib/editor-linter.coffee
+++ lib/editor-linter.coffee
@@ -36,7 +36,7 @@

   destroy: ->
     @emitter.emit('did-destroy')
-    @deactivate()
+    @dispose()

   dispose: ->
     @subscriptions.dispose()


set minHeight for inline results

set minHeight for inline results

--- lib/editor/result.coffee
+++ lib/editor/result.coffee
@@ -59,7 +59,8 @@
       when 'inline'
         @view.classList.add 'inline'
         @disposables.add atom.config.observe 'editor.lineHeight', (h) =>
-          @view.style.top = -h + 'em';
+          @view.style.top       = -h + 'em'
+          @view.style.minHeight =  h + 'em'
       when 'block'  then @view.classList.add 'under'
     @view.addEventListener 'mousewheel', (e) =>
       if (@view.offsetHeight < @view.scrollHeight  ||


revise slide animation speed

revise slide animation speed

--- app/controllers/index.coffee
+++ app/controllers/index.coffee
@@ -60,9 +60,9 @@
 addAnnotations = (array) ->
   for data in array
     if data.shopFlg is "true"
-      imagePath = "iphone/bottle.png"
+      imagePath = "bottle.png"
     else
-      imagePath = "iphone/tumblrIcon.png"
+      imagePath = "tmulblr.png"

     annotation = Alloy.Globals.Map.createAnnotation
       latitude: data.latitude
@@ -104,7 +104,7 @@
   animation = Titanium.UI.createAnimation()
   animation.left = leftPosition
   animation.transform = transform
-  animation.duration = 500
+  animation.duration = 250
   $.mapview.animate(animation)


fix(provider): remove suffix

fix(provider): remove suffix

Using the suffix 'Provider' is superfluous
Angular already applies the suffix

Closes #36

--- lib/formatOptions.coffee
+++ lib/formatOptions.coffee
@@ -18,7 +18,6 @@
 			format: 'camelCase'
 		provider:
 			format: 'camelCase'
-			suffix: 'Provider'
 		service:
 			format: 'camelCase'
 			suffix: 'Service'


use getBufferPosition, instead of calling both (getBufferRow, getBufferColumn)

--- lib/atom-ternjs.coffee
+++ lib/atom-ternjs.coffee
@@ -43,8 +43,9 @@

     prefix = cursor.getCurrentWordPrefix()
     if prefix[prefix.length - 1] is '.' or force is yes
-      row = cursor.getBufferRow()
-      col = cursor.getBufferColumn()
+      position = cursor.getBufferPosition()
+      row = position.row
+      col = position.column
       client.completions(editor.getUri(),
         line: row
         ch: col


apply last review comment

apply last review comment

--- src/components/common/transactions-add/transactions-add.component.coffee
+++ src/components/common/transactions-add/transactions-add.component.coffee
@@ -32,8 +32,7 @@
         recurring: false
         interval: 4
         validateInterval: ->
-          if (angular.isUndefined(this.interval) || this.interval == null || this.interval < 1)
-            this.interval = 1
+          this.interval = 1 unless this.interval? || this.interval > 0
         rule: ctrl.schedulableRules.find (rule) -> rule.value == 'WeeklyRule'
         endType: 'occurrencies'
         occurrencies: 12


Update es-ES.coffee (#5726)

Update es-ES.coffee (#5726)

* Update es-ES.coffee

* Update es-ES.coffee

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

--- app/locale/es-ES.coco.coffee
+++ app/locale/es-ES.coco.coffee
@@ -1,7 +1,7 @@
 module.exports = nativeDescription: "español (ES)", englishDescription: "Spanish (Spain)", translation:

   new_home:
-#    title: "CodeCombat - Coding games to learn Python and JavaScript"
+    title: "CodeCombat - Juegos de Programación para aprender Python y JavaScript"
 #    meta_keywords: "CodeCombat, python, javascript, Coding Games"
 #    meta_description: "Learn typed code through a programming game. Learn Python, JavaScript, and HTML as you solve puzzles and learn to make your own coding games and websites."
 #    meta_og_url: "https://codecombat.com"
@@ -14,7 +14,7 @@
 #    built_for_teachers_subblurb2: "Learners construct mazes and use basic input handling to code their own games that can be shared with friends and family."
 #    built_for_teachers_subtitle3: "Web Development"
 #    built_for_teachers_subblurb3: "Using HTML, CSS, and jQuery, learners flex their creative muscles to program their own webpages with a custom URL to share with their classmates."
-#    century_skills_title: "21st Century Skills"
+    century_skills_title: "Habilidades del siglo 21"
 #    century_skills_blurb1: "Students Don't Just Level Up Their Hero, They Level Up Themselves"
 #    century_skills_quote1: "You mess up…so then you think about all of the possible ways to fix it, and then try again. I wouldn't be able to get here without trying hard."
 #    century_skills_subtitle1: "Critical Thinking"
@@ -156,8 +156,6 @@
     view_progress: "Ver mi progreso"
     go_to_courses: "Ir a mis cursos"
     want_coco: "¿Quieres CodeCombat en tu escuela?"
-#    educator: "Educator"
-#    student: "Student"
 #    our_coding_programs: "Our Coding Programs"
 #    codecombat: "CodeCombat"
 #    ozaria: "Ozaria"
@@ -167,9 +165,9 @@
 #    try_ozaria: "Try Ozaria"

   nav:
-#    educators: "Educators"
-#    follow_us: "Follow Us"
-#    general: "General"
+    educators: "Maestros"
+    follow_us: "Síguenos"
+    general: "General"
     map: "Mapa"
     play: "Jugar" # The top nav bar entry where players choose which levels to play
     community: "Comunidad"
@@ -184,12 +182,12 @@
     legal: "Legalidad"
     privacy: "Privacidad"
     about: "Sobre nosotros"
-#    impact: "Impact"
+    impact: "Impacto"
     contact: "Contacta"
     twitter_follow: "Síguenos en Twitter"
     my_classrooms: "Mis Clases"
     my_courses: "Mis Cursos"
-#    my_teachers: "My Teachers"
+    my_teachers: "Mis Maestros"
     careers: "Carreras"
     facebook: "Facebook"
     twitter: "Twitter"
@@ -202,19 +200,19 @@
     open_source: "Código abierto (GitHub)"
     support: "Soporte"
     faqs: "Preguntas frecuentes"
-#    copyright_prefix: "Copyright"
-#    copyright_suffix: "All Rights Reserved."
+    copyright_prefix: "Copyright"
+    copyright_suffix: "Todos los derechos reservados."
     help_pref: "¿Necesitas ayuda? ¡Email"
     help_suff: "y nos pondremos en contacto!"
     resource_hub: "Centro de recursos"
-#    apcsp: "AP CS Principles"
-#    parent: "Parents"
+    apcsp: "Principios AP CS"
+    parent: "Padres"
 #    browser_recommendation: "For the best experience we recommend using the latest version of Chrome. Download the browser here!"

   modal:
     close: "Cerrar"
     okay: "Ok"
-#    cancel: "Cancel"
+    cancel: "Cancelar"

   not_found:
     page_not_found: "Página no encontrada"
@@ -277,7 +275,7 @@
     campaign_multiplayer_description: "... en las que tu código se enfrentará al de otros jugadores."
     brain_pop_done: "¡Has vencido a los Ogros con código! ¡Ganaste!"
     brain_pop_challenge: "Retarte a jugar otra vez usando un lenguaje de programación diferente!"
-#    replay: "Replay"
+    replay: "Repetir"
     back_to_classroom: "Regresa a la clase"
     teacher_button: "Para maestros"
     get_more_codecombat: "Obtener más CodeCombat"
@@ -354,7 +352,7 @@
 #    accounts_merge_confirmation: "There is an account associated with the email from this Google account. Would you like to merge these accounts?"

   signup:
-#    complete_subscription: "Complete Subscription"
+    complete_subscription: "Suscripción completa"
     create_student_header: "Crear Cuenta de Estudiante"
     create_teacher_header: "Crear Cuenta de Maestro"
     create_individual_header: "Crear Cuenta Individual"
@@ -364,7 +362,7 @@
     creating: "Creando cuenta..."
     sign_up: "Registrarse"
     log_in: "Iniciar sesión con contraseña"
-#    login: "Login"
+    login: "Iniciar sesión"
     required: "Tienes que estar registrado antes de poder seguir por aquí."
     login_switch: "¿Ya tienes una cuenta?"
     optional: "opcional"
@@ -452,20 +450,20 @@
 #    default_title: "CodeCombat - Coding games to learn Python and JavaScript"
 #    default_meta_description: "Learn typed code through a programming game. Learn Python, JavaScript, and HTML as you solve puzzles and learn to make your own coding games and websites."
     back: "Volver" # When used as an action verb, like "Navigate backward"
-#    coming_soon: "Coming soon!"
+    coming_soon: "¡Próximamente!"
     continue: "Continuar" # When used as an action verb, like "Continue forward"
-#    next: "Next"
-#    default_code: "Default Code"
+    next: "Siguiente"
+    default_code: "Código por defecto"
     loading: "Cargando..."
-#    overview: "Overview"
-#    processing: "Processing..."
-#    solution: "Solution"
-#    table_of_contents: "Table of Contents"
-#    intro: "Intro"
+    overview: "Vista global"
+    processing: "Procesando..."
+    solution: "Solución"
+    table_of_contents: "Tabla de Contenidos"
+    intro: "Intro"
     saving: "Guardando..."
     sending: "Enviando..."
     send: "Enviar"
-#    sent: "Sent"
+    sent: "Enviado"
     cancel: "Cancelar"
     save: "Guardar"
     publish: "Publicar"
@@ -482,9 +480,9 @@
     submit_changes: "Enviar Cambios"
     save_changes: "Guardar cambios"
     required_field: "Campo requerido" # {change}
-#    submit: "Submit"
-#    replay: "Replay"
-#    complete: "Complete"
+    submit: "Enviar"
+    replay: "Repetir"
+    complete: "Completar"

   general:
     and: "y"
@@ -497,10 +495,10 @@
     rejected: "Rechazado"
     withdrawn: "Retirado"
     accept: "Aceptar"
-#    accept_and_save: "Accept&Save"
+    accept_and_save: "Aceptar&Guardar"
     reject: "Rechazar"
     withdraw: "Retirar"
-#    submitter: "Submitter"
+    submitter: "Remitente"
     submitted: "Enviado"
     commit_msg: "Mensaje de Asignación o Commit"
     version_history: "Historial de versión"
@@ -592,8 +590,8 @@
 #    combo_not_all_concepts_used: "You used __complete__ out of the __total__ concepts possible to solve the challenge. Try to get all __total__ concepts next time!"
 #    start_challenge: "Start Challenge"
     next_game: "Siguiente juego"
-#    languages: "Languages"
-#    programming_language: "Programming language"
+    languages: "Lenguajes"
+    programming_language: "Lenguaje de programación"
     show_menu: "Mostrar menú del juego"
     home: "Inicio" # Not used any more, will be removed soon.
     level: "Nivel" # Like "Level: Dungeons of Kithgard"
@@ -618,7 +616,7 @@
     reload_really: "¿Estás seguro que quieres reiniciar el nivel?"
     reload_confirm: "Recargarlo todo"
 #    restart_really: "Are you sure you want to restart the level? You'll loose all the code you've written."
-#    restart_confirm: "Yes, Restart"
+    restart_confirm: "Sí, Reiniciar"
 #    test_level: "Test Level"
     victory: "Victoria"
     victory_title_prefix: "¡"
@@ -636,21 +634,21 @@
     victory_experience_gained: "XP Conseguida"
     victory_gems_gained: "Gemas Conseguidas"
     victory_new_item: "Nuevo artículo"
-#    victory_new_hero: "New Hero"
+    victory_new_hero: "Nuevo heroe"
     victory_viking_code_school: "Jolines, el nivel que acabas de pasar era difícil! Si todavía no eres un desarrollador de software, deberías serlo. Acabas de conseguir una aceptación por vía rápida con la Escuela Vikinga de Có, donde tú puedes llevar tus habilidades al siguiente nivel y convertirte en un desarrollador web profesional en 14 semanas."
     victory_become_a_viking: "Convertirse en un vikingo"
     victory_no_progress_for_teachers: "El progreso no se guarda para los profesores. Pero, puedes añadir una cuenta de estudiante a tu clase para ti."
     tome_cast_button_run: "Correr"
     tome_cast_button_running: "Corriendo"
     tome_cast_button_ran: "Corrido"
-#    tome_cast_button_update: "Update"
+    tome_cast_button_update: "Actualizar"
     tome_submit_button: "Mandar"
     tome_reload_method: "Recargar código original para este método" # {change}
     tome_available_spells: "Hechizos disponibles"
     tome_your_skills: "Tus Habilidades"
-#    hints: "Hints"
-#    videos: "Videos"
-#    hints_title: "Hint {{number}}"
+    hints: "Consejos"
+    videos: "Videos"
+    hints_title: "Consejo {{number}}"
     code_saved: "código Salvado"
     skip_tutorial: "Saltar (esc)"
     keyboard_shortcuts: "Atajos de teclado"
@@ -734,44 +732,44 @@
     tip_good_idea: "La mejor manera para tener una buena idea es tener muchas ideas. - Linus Pauling"
 #    tip_programming_not_about_computers: "Computer Science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra"
     tip_mulan: "Si crees que puedes, entonces podrás. - Mulan"
-#    project_complete: "Project Complete!"
+    project_complete: "¡Proyecto completo!"
 #    share_this_project: "Share this project with friends or family:"
 #    ready_to_share: "Ready to publish your project?"
 #    click_publish: "Click \"Publish\" to make it appear in the class gallery, then check out what your classmates built! You can come back and continue to work on this project. Any further changes will automatically be saved and shared with your classmates."
 #    already_published_prefix: "Your changes have been published to the class gallery."
 #    already_published_suffix: "Keep experimenting and making this project even better, or see what the rest of your class has built! Your changes will automatically be saved and shared with your classmates."
-#    view_gallery: "View Gallery"
+    view_gallery: "Ver galería"
 #    project_published_noty: "Your level has been published!"
-#    keep_editing: "Keep Editing"
-#    learn_new_concepts: "Learn new concepts"
+    keep_editing: "Sigue editando"
+    learn_new_concepts: "Aprende nuevos conceptos"
 #    watch_a_video: "Watch a video on __concept_name__"
-#    concept_unlocked: "Concept Unlocked"
+    concept_unlocked: "Concepto desbloqueado"
 #    use_at_least_one_concept: "Use at least one concept: "
-#    command_bank: "Command Bank"
-#    learning_goals: "Learning Goals"
-#    start: "Start"
+    command_bank: "Banco de comandos"
+    learning_goals: "Metas de aprendizaje"
+    start: "Iniciar"
 #    vega_character: "Vega Character"
-#    click_to_continue: "Click to Continue"
-
-#  apis:
-#    methods: "Methods"
-#    events: "Events"
-#    handlers: "Handlers"
-#    properties: "Properties"
-#    snippets: "Snippets"
-#    spawnable: "Spawnable"
-#    html: "HTML"
+    click_to_continue: "Click para continuar"
+
+  apis:
+    methods: "Métodos"
+    events: "Eventos"
+    handlers: "Manipuladores"
+    properties: "Propiedades"
+    snippets: "Fragmentos"
+    spawnable: "Generable"
+    html: "HTML"
 #    math: "Math"
 #    array: "Array"
-#    object: "Object"
-#    string: "String"
-#    function: "Function"
-#    vector: "Vector"
+    object: "Objeto"
+    string: "Cadena de texto"
+    function: "Función"
+    vector: "Vector"
 #    date: "Date"
-#    jquery: "jQuery"
-#    json: "JSON"
+    jquery: "jQuery"
+    json: "JSON"
 #    number: "Number"
-#    webjavascript: "JavaScript"
+    webjavascript: "JavaScript"

 #  amazon_hoc:
 #    title: "Keep Learning with Amazon!"
@@ -835,13 +833,13 @@
     day: "Hoy"
     week: "Esta semana"
     all: "Siempre"
-#    latest: "Latest"
+    latest: "Último"
     time: "Tiempo"
     damage_taken: "Daño recibido"
     damage_dealt: "Daño causado"
     difficulty: "Dificultad"
     gold_collected: "Oro conseguido"
-#    survival_time: "Survived"
+    survival_time: "Sobrevivió"
 #    defeated: "Enemies Defeated"
 #    code_length: "Lines of Code"
 #    score_display: "__scoreType__: __score__"
@@ -857,9 +855,9 @@
     restricted: "(restringido en este nivel)"
     equip: "Equipar"
     unequip: "Desequipar"
-#    warrior_only: "Warrior Only"
-#    ranger_only: "Ranger Only"
-#    wizard_only: "Wizard Only"
+    warrior_only: "Solo guerrero"
+    ranger_only: "Solo guardabosques"
+    wizard_only: "Solo mago"

   buy_gems:
     few_gems: "Unas pocas joyas"
@@ -874,7 +872,7 @@
     recovered: "Las gemas compradas con anterioridad han sido recuperadas. Por favor, actualiza la página."
     price: "x{{gems}} / mes"
 #    buy_premium: "Buy Premium"
-#    purchase: "Purchase"
+    purchase: "Compra"
 #    purchased: "Purchased"

 #  subscribe_for_gems:
@@ -902,7 +900,7 @@
     sorry_to_see_you_go: "¡Lamentamos verte marchar! Por favor, haznos saber que pudimos haacer mejor."
     unsubscribe_feedback_placeholder: "Oh, ¿Qué hemos hecho?"
     stripe_description: "Suscripción mensual"
-#    buy_now: "Buy Now"
+    buy_now: "Comprar ahora"
     subscription_required_to_play: "Necesitas una suscripción para jugar este nivel."
     unlock_help_videos: "Suscríbete para desbloquear todos los videotutoriales."
     personal_sub: "Suscripciones personales" # Accounts Subscription View below
@@ -911,7 +909,7 @@
     will_be_cancelled: "Será cancelado el"
     currently_free: "Actualmente tienes una suscripción gratuita"
     currently_free_until: "Actualmente tienes una suscripción hasta el"
-#    free_subscription: "Free subscription"
+    free_subscription: "Suscripción gratuita"
     was_free_until: "Tenías una suscripción gratuita hasta el"
     managed_subs: "Suscripciones administradas"
     subscribing: "Suscribiendo..."
@@ -1022,12 +1020,12 @@
     regeneration: "Regeneración"
     range: "Alcance" # As in "attack or visual range"
     blocks: "Bloqueo" # As in "this shield blocks this much damage"
-#    backstab: "Backstab" # As in "this dagger does this much backstab damage"
+    backstab: "Puñalada" # As in "this dagger does this much backstab damage"
     skills: "Habilidades"
-#    attack_1: "Deals"
+    attack_1: "Ofertas"
 #    attack_2: "of listed"
 #    attack_3: "weapon damage."
-#    health_1: "Gains"
+    health_1: "Ganancias"
 #    health_2: "of listed"
 #    health_3: "armor health."
     speed_1: "Se mueve a"
@@ -1036,12 +1034,12 @@
     level_to_unlock: "Nivel para desbloquear:" # Label for which level you have to beat to unlock a particular hero (click a locked hero in the store to see)
     restricted_to_certain_heroes: "Solo ciertos héroes pueden jugar este nivel."

-#  char_customization_modal:
-#    heading: "Customize Your Hero"
-#    body: "Body"
-#    name_label: "Hero's Name"
-#    hair_label: "Hair Color"
-#    skin_label: "Skin Color"
+  char_customization_modal:
+    heading: "Personalizar tu héroe"
+    body: "Cuerpo"
+    name_label: "Nombre del héroe"
+    hair_label: "Color de pelo"
+    skin_label: "Color de piel"

   skill_docs:
 #    function: "function" # skill types
@@ -1080,8 +1078,8 @@
   options:
     general_options: "Opciones Generales" # Check out the Options tab in the Game Menu while playing a level
     volume_label: "Volumen"
-    music_label: "Musica"
-    music_description: "Musica de fondo on/off."
+    music_label: "Música"
+    music_description: "Música de fondo on/off."
     editor_config_title: "Configuración del editor"
     editor_config_livecompletion_label: "Autocompletado en vivo"
     editor_config_livecompletion_description: "Muestra sugerencias de autocompletado mientras se escribe."
@@ -1098,10 +1096,10 @@
 #    learn_more: "Learn More"
 #    main_title: "If you want to learn to program, you need to write (a lot of) code."
 #    main_description: "At CodeCombat, our job is to make sure you're doing that with a smile on your face."
-#    mission_link: "Mission"
-#    team_link: "Team"
-#    story_link: "Story"
-#    press_link: "Press"
+    mission_link: "Misión"
+    team_link: "Equipo"
+    story_link: "Historia"
+    press_link: "Prensa"
     mission_title: "Nuestra misión: lograr que la programación esté disponible para todos los alumnos de la Tierra."
     mission_description_1: "Programar es hacer magia. Es la habilidad de crear cosas desde la imaginación. Iniciamos CodeCombat para que los alumnos experimenten en sus dedos la magia al escribir código.."
     mission_description_2: "Ademas resulta, que esto permite aprender más rápido. MUCHO más rápido. Es como mantener una conversación en lugar de leer un manual. Queremos llevar esa conversación a todas las escuelas y a todos los alumnos, porque todos deben tener la oportunidad de aprender la magia de la programación."


Fix PYTHONPATH

Fix PYTHONPATH

--- lib/linter-pylama.coffee
+++ lib/linter-pylama.coffee
@@ -75,7 +75,7 @@
     return @lintOnFly_

-  initPythonPath: (cwd) ->
+  initEnv: (cwd) ->
     pythonPath = if process.env['PYTHONPATH'] then process.env.PYTHONPATH else ''
     pythonPath = pythonPath.split path.delimiter
     pythonPath = pythonPath.filter(Boolean)
@@ -88,6 +88,7 @@
       pythonPath.push process_path

     process.env.PYTHONPATH = pythonPath.join path.delimiter
+    process.env

   initPylama: =>
@@ -148,6 +149,7 @@
     if not originFileName
       originFileName = fileName
     curDir = path.dirname originFileName
+    env = @initEnv curDir
     args = @initArgs curDir
     args.push fileName
     console.log "#{@pylamaPath} #{args}" if do atom.inDevMode
@@ -155,11 +157,11 @@
       fileName: originFileName
       command: @pylamaPath
       args: args
-      options: {cwd: curDir}
+      options: {cwd: curDir, env: env, stream: 'stdout', ignoreExitCode: true}

   lintFile: (lintInfo, textEditor) ->
-    helpers.exec(lintInfo.command, lintInfo.args, {stream: 'stdout', ignoreExitCode: true, cwd: lintInfo.options.cwb}).then (output) ->
+    helpers.exec(lintInfo.command, lintInfo.args, lintInfo.options).then (output) ->
       console.log output if do atom.inDevMode
       helpers.parse(output, regex).map (message) ->
         code = "#{message.type}#{message.filePath}"
@@ -191,7 +193,6 @@
   lint: (textEditor) =>
     if not @pylamaPath
       return []
-    @initPythonPath path.dirname do textEditor.getPath
     if @lintOnFly_
       return @lintOnFly textEditor
     @lintOnSave textEditor


Add tests for templateJSON property.

Add tests for templateJSON property.

--- test/javascripts/models/manuscript_manager_template_test.js.coffee
+++ test/javascripts/models/manuscript_manager_template_test.js.coffee
@@ -9,6 +9,7 @@
     @testThing = 5
     template =
       name: 'A name'
+      id: 1
       paper_type: 'A type'
       template:
         phases: [phase]
@@ -31,3 +32,15 @@

 test "#init sets the template property to null", ->
   equal testTemplate.get('template'), null
+
+
+test "#templateJSON serializes the template's state.", ->
+  testData = {
+    id: 1,
+    name: 'A name',
+    paper_type: 'A type'
+    template: phases: [ {name: 'First Phase', task_types: ['ATask', 'AnotherTask']}]
+  }
+  deepEqual testTemplate.get('templateJSON'), testData
+
+


Fix State when config.address_requires_state=true

When config.address_requires_state = false, no dropdown for State
is shown on the Address form. When config.address_requires_state =
true, the dropdown is shown.

Whether the input in the dropdown is required is then controlled
by the setting of @country.states_required = true/false.

However, there was a Javascript check which would make the State
on the form permanently required as soon as any country which
required states was chosen in the Country dropdown.

This change properly marks the field as required or optional as
the Country dropdown changes, and it shows or hides the "required"
symbol appropriately.

--- frontend/app/assets/javascripts/spree/frontend/checkout/address.js.coffee
+++ frontend/app/assets/javascripts/spree/frontend/checkout/address.js.coffee
@@ -43,8 +43,13 @@
         stateSelect.prop('disabled', false).show()
         stateInput.hide().prop 'disabled', true
         statePara.show()
-        stateSpanRequired.show()
-        stateSelect.addClass('required') if statesRequired
+        if statesRequired
+          stateSelect.addClass('required')
+          stateSpanRequired.show()
+        else
+          stateSelect.removeClass('required')
+          stateSpanRequired.hide()
+        end
         stateSelect.removeClass('hidden')
         stateInput.removeClass('required')
       else


Notification bugfix

Notification bugfix

--- lib/notifications.coffee
+++ lib/notifications.coffee
@@ -285,10 +285,10 @@
     for notification in messageUpdates
       notification.msg = Messages.findOne notification.message
     ## Some messages may have been superdeleted by now; don't email about them.
-    messageUpdates = (notification for notification in notifications when notification.msg?)
+    messageUpdates = (notification for notification in messageUpdates when notification.msg?)
     ## Don't notify about empty messages (e.g. initial creation without
     ## follow-up) -- wait for content.  xxx should check if diff is version 1!
-    messageUpdates = (notification for notification in notifications when not messageEmpty notification.msg)
+    messageUpdates = (notification for notification in messageUpdates when not messageEmpty notification.msg)
     return if messageUpdates.length == 0

     html = ''


fix unit-test al-value

fix unit-test al-value

--- test/test_dirs.coffee
+++ test/test_dirs.coffee
@@ -197,9 +197,10 @@
 	$test.close()

-Test('al-input on/off').run ($test, alight) ->
+Test('al-value on/off').run ($test, alight) ->
 	if typeof(CustomEvent) isnt 'function'
-		console.warn 'skip al-input on/off'
+		$test.close()
+		console.warn 'skip al-value on/off'
 		return

 	$test.start 3


Correctly indent after one-line dictionary

Was incorrectly being parsed as the beginning of a function.

--- lib/python-indent.coffee
+++ lib/python-indent.coffee
@@ -135,6 +135,9 @@

         # true if we should have a hanging indent, false otherwise
         shouldHang = false
+
+        # this is the last defined function row
+        lastLastFunctionRow = lastFunctionRow

         for col in [0 .. line.length - 1] by 1
             c = line[col]
@@ -183,6 +186,14 @@
                     # or a new line, so that means the current character is not whitespace and
                     # not an opening bracket, so shouldHang needs to get set to false.
                     shouldHang = false
+
+                    # Similar to above, we've already skipped all irrelevant characters,
+                    # so if we saw a colon earlier in this line, then we would have
+                    # incorrectly thought it was the end of a function definition when
+                    # it was actually a dictionary being defined, reset the lastFunctionRow
+                    # variable to whatever it was when we started parsing this line.
+                    lastFunctionRow = lastLastFunctionRow
+
                     if c == ':'
                         lastFunctionRow = row
                     else if c in '})]'


Change octicons for panel menu

Change octicons for panel menu

--- lib/settings-view.coffee
+++ lib/settings-view.coffee
@@ -60,8 +60,8 @@
     @addCorePanel 'Keybindings', 'keyboard', -> new KeybindingsPanel
     @addCorePanel 'Packages', 'package', => new InstalledPackagesPanel(@packageManager)
     @addCorePanel 'Themes', 'paintcan', => new ThemesPanel(@packageManager)
-    @addCorePanel 'Install', 'cloud-download', => new InstallPanel(@packageManager)
-    @addCorePanel 'Updates', 'squirrel', => new UpdatesPanel(@packageManager)
+    @addCorePanel 'Updates', 'cloud-download', => new UpdatesPanel(@packageManager)
+    @addCorePanel 'Install', 'plus', => new InstallPanel(@packageManager)

     @addPackagePanel(pack) for pack in @getPackages()
     @showPanel(@panelToShow) if @panelToShow


YELL THE PORT NAME PLEASE

YELL THE PORT NAME PLEASE

--- configs.coffee
+++ configs.coffee
@@ -23,7 +23,7 @@
 		configs.cache = true
 		configs.mongoURL = process.env.MONGOLAB_URI
 		configs.url = "http://www.vault.tk"
-		configs.port = process.env.port || "80"
+		configs.port = process.env.PORT || "80"
 		configs.host = 'www.vault.tk'
 		configs.clef =
 			app_id: process.env.CLEF_APP_ID


Correct FindLabels.getLabels semantics

Correct FindLabels.getLabels semantics

Latex's input and include commands determine the file to read based on
the main file of the document.
"getLabels" was incorrectly determining paths to inputed/included files
based on the current file.

--- lib/find-labels.coffee
+++ lib/find-labels.coffee
@@ -4,24 +4,24 @@

 module.exports =
 FindLabels =
-  getLabelsByText: (text, file = "") ->
+  getLabelsByText: (text, baseFile = "") ->
     labelRex = /\\(?:th)?label{([^}]+)}/g
     matches = []
     while (match = labelRex.exec(text))
       matches.push {label: match[1]}
-    return matches unless file?
+    return matches unless baseFile?
     inputRex = /\\(input|include){([^}]+)}/g
     while (match = inputRex.exec(text))
-      matches = matches.concat(@getLabels(@getAbsolutePath(file, match[2])))
+      matches = matches.concat(@getLabels(@getAbsolutePath(baseFile, match[2]), baseFile))
     matches

-  getLabels: (file) ->
+  getLabels: (file, baseFile) ->
     #if file is not there try add possible extensions
     if not fsPlus.isFileSync(file)
       file = fsPlus.resolveExtension(file, ['tex'])
     return [] unless fsPlus.isFileSync(file)
     text = fs.readFileSync(file).toString()
-    @getLabelsByText(text, file)
+    @getLabelsByText(text, baseFile)

   getAbsolutePath: (file, relativePath) ->
     if (ind = file.lastIndexOf(path.sep)) isnt file.length


add placeholder to transcript search input

--- src/javascripts/extensions/transcript/search.coffee
+++ src/javascripts/extensions/transcript/search.coffee
@@ -117,7 +117,7 @@
         {currentIndex}/{resultCount}
         <button class="search-result-next"></button>

-      <input type="text" class="search-input">
+      <input type="text" class="search-input" placeholder="Search in transcript">
       <button class="search-clear" pp-show="query">×</button>
     """
 module.exports = TranscriptSearch


Remove debug comment

Remove debug comment

--- lib/sync-settings.coffee
+++ lib/sync-settings.coffee
@@ -28,7 +28,6 @@
         type: 'string'

   activate: ->
-    # for debug
     GitHubApi ?= require 'github'
     PackageManager ?= require './package-manager'
     atom.commands.add 'atom-workspace', "sync-settings:backup", => @backup()


:art:

:art:

--- lib/tag-generator.coffee
+++ lib/tag-generator.coffee
@@ -59,8 +59,7 @@
       for line in lines.split('\n')
         if tag = @parseTagLine(line)
           tags[tag.position.row] ?= tag
-    stderr = (lines) ->
-      return
+    stderr = ->
     exit = ->
       tags = (tag for row, tag of tags)
       deferred.resolve(tags)


camelCase

camelCase

--- src/packages/editor-stats/src/editor-stats-view.coffee
+++ src/packages/editor-stats/src/editor-stats-view.coffee
@@ -35,7 +35,7 @@
   @serialize: ->
     @instance.serialize()

-  eventlog: [],
+  eventLog: [],

   initialize: (@rootView, @eventLog = {}) ->
     super
@@ -45,10 +45,10 @@

     date = new Date(startDate)
     future = new Date(date.getTime() + (36e5 * hours))
-    @eventlog[time(date)] = 0
+    @eventLog[time(date)] = 0

     while date < future
-      @eventlog[time(date)] = 0
+      @eventLog[time(date)] = 0

     @rootView.on 'keydown', @track
     @rootView.on 'mouseup', @track
@@ -58,7 +58,7 @@
     h = @.height()
     [pt, pl, pb, pr] = [15,0,0,0]

-    data = d3.entries @eventlog
+    data = d3.entries @eventLog

     x.rangeRoundBands [0, w - pl - pr], 0.2
     y.range [h, 0]
@@ -90,7 +90,7 @@
       .attr('class', 'bar')

     update = =>
-      newdata = d3.entries @eventlog
+      newdata = d3.entries @eventLog
       max  = d3.max newdata, (d) -> d.value

       y.domain [0, max]
@@ -106,9 +106,9 @@
   track: =>
     date = new Date
     times = time date
-    @eventlog[times] ||= 0
-    @eventlog[times] += 1
-    @eventlog.shift() if @eventlog.length > (hours * 60)
+    @eventLog[times] ||= 0
+    @eventLog[times] += 1
+    @eventLog.shift() if @eventLog.length > (hours * 60)

   toggle: ->
     if @hasParent()


Format GitChanges

Format GitChanges

--- lib/git-changes.coffee
+++ lib/git-changes.coffee
@@ -1,94 +1,99 @@
-Git = require 'nodegit'
+Git          = require 'nodegit'
 ChildProcess = require 'child_process'
-os = require 'os'
-fse = require 'fs-extra'
-Path = require 'path'
-exec = ChildProcess.exec
-
-normalizeOptions = (options, Ctor) ->
-  instance = (if options instanceof Ctor then options else new Ctor())
-  return null  unless options
-  Object.keys(options).forEach (key) ->
-    instance[key] = options[key]
-    return
-
-  instance
+os           = require 'os'
+fse          = require 'fs-extra'
+Path         = require 'path'
+_            = require 'underscore-contrib'
+exec         = ChildProcess.exec

 module.exports =
 class GitChanges
-  changes: {}
   statuses: {}

   constructor: ->
-    @tmpDir = os.tmpDir()
+    @tmpDir   = os.tmpDir()
     @repoPath = atom.project.getPaths()[0]
+
+  statusCodes: ->
+    Git.Status.STATUS

   getBranch: ->
     Git.Repository.open(@repoPath).then (repo) =>
       repo.getBranch('HEAD')

   getPatch: (path, state) ->
-    @stagedPromise.then (diffs) ->
-      for patch in diffs[state].patches()
-        return patch if patch.newFile().path() == path
-
-      gatherDiffs()
-      @getPatch(path, state)
+    @diffsPromise.then (diffs) ->
+      _.find diffs[state].patches(), (patch) ->
+        patch.newFile().path() == path

   gatherDiffs: ->
-    @stagedPromise = Git.Repository.open(@repoPath).then (repo) =>
-      repo.openIndex().then (index) =>
-        new Promise (resolve, reject) =>
-          setImmediate =>
-            opts = {
-              flags: Git.Diff.OPTION.SHOW_UNTRACKED_CONTENT
-            }
-            Git.Diff.indexToWorkdir(repo, index, opts).then (unstagedDiffs) ->
-              repo.getHeadCommit().then (commit) ->
-                commit.getTree().then (tree) ->
-                  Git.Diff.treeToIndex(repo, tree, index, opts).then (stagedDiffs) ->
-                    resolve
-                      staged: stagedDiffs
-                      unstaged: unstagedDiffs
+    data = {}
+    opts =
+      flags: Git.Diff.OPTION.SHOW_UNTRACKED_CONTENT
+
+    @diffsPromise = Git.Repository.open(@repoPath).then (repo) ->
+      data.repo = repo
+      data.repo.openIndex()
+    .then (index) ->
+      data.index = index
+      Git.Diff.indexToWorkdir(data.repo, data.index, opts)
+    .then (unstagedDiffs) ->
+      data.unstagedDiffs = unstagedDiffs
+      data.repo.getHeadCommit()
+    .then (commit) ->
+      commit.getTree()
+    .then (tree) ->
+      Git.Diff.treeToIndex(data.repo, tree, data.index, opts)
+    .then (stagedDiffs) ->
+      diffs =
+        staged:   stagedDiffs
+        unstaged: data.unstagedDiffs

   getStatuses: ->
     @gatherDiffs()
-    Git.Repository.open(@repoPath).then (repo) =>
-      repo.getStatus().then (statuses) =>
-        for status in statuses
-          @statuses[status.path()] = status
+    Git.Repository.open(@repoPath)
+    .then (repo) ->
+      repo.getStatus()
+    .then (statuses) =>
+      for status in statuses
+        @statuses[status.path()] = status
+      statuses

-        statuses
+  getComparisonBranch: (names, branchName) ->
+    origin = "refs/remotes/origin/#{branchName}"
+    if names.indexOf(origin) >= 0
+      origin
+    else if branchName != "master"
+      "master"
+    else
+      null

   getLatestUnpushed: ->
-    Git.Repository.open(@repoPath).then (repo) ->
-      repo.getCurrentBranch().then (branch) ->
-        branchName = branch.name().replace('refs/heads/','')
-        walker = repo.createRevWalk()
-        walker.pushHead()
-
-        repo.getReferenceNames().then (names) ->
-          compareBranch = if names.indexOf("refs/remotes/origin/#{branchName}") >= 0
-            "origin/#{branchName}"
-          else if branchName != "master"
-            "master"
-          else
-            null
-
-          promise = new Promise (resolve, reject) =>
-            if compareBranch
-              repo.getBranchCommit(compareBranch).then (compare) =>
-                walker.hide(compare)
-                resolve()
-            else
-              resolve()
-
-          promise.then ->
-            walker.next().then (oid) ->
-              if oid
-                repo.getCommit(oid)
-              else
-                null
+    data = {}
+    Git.Repository.open(@repoPath)
+    .then (repo) =>
+      data.repo = repo
+      repo.getCurrentBranch()
+    .then (branch) =>
+      data.branch     = branch
+      data.branchName = branch.name().replace('refs/heads/','')
+      data.walker     = data.repo.createRevWalk()
+      data.walker.pushHead()
+      data.repo.getReferenceNames()
+    .then (names) =>
+      data.compareBranch = @getComparisonBranch(names, data.branchName)
+      new Promise (resolve, reject) =>
+        if data.compareBranch
+          data.repo.getBranchCommit(data.compareBranch)
+          .then (compare) =>
+            data.walker.hide(compare)
+            resolve()
+        else
+          resolve()
+    .then =>
+      data.walker.next()
+    .then (oid) =>
+      if oid then data.repo.getCommit(oid) else null

   undoLastCommit: ->
     new Promise (resolve, reject) =>
@@ -99,16 +104,18 @@
     @stageAllPaths([path])

   stageAllPaths: (paths) ->
-    Git.Repository.open(@repoPath).then (repo) =>
-      repo.openIndex().then (index) =>
-        for path in paths
-          status = @statuses[path]
-          if status.statusBit() & Git.Status.STATUS.WT_DELETED
-            index.removeByPath(path)
-          else
-            index.addByPath(path)
+    Git.Repository.open(@repoPath)
+    .then (repo) =>
+      repo.openIndex()
+    .then (index) =>
+      for path in paths
+        status = @statuses[path]
+        if status.statusBit() & Git.Status.STATUS.WT_DELETED
+          index.removeByPath(path)
+        else
+          index.addByPath(path)

-        index.write()
+      index.write()

   unstagePath: (path) ->
     @unstageAllPaths([path])
@@ -116,32 +123,47 @@
   unstageAllPaths: (paths) ->
     new Promise (resolve, reject) =>
       if paths.length
-        ChildProcess.exec "git reset HEAD #{paths.join(' ')}", {cwd: @repoPath}, =>
-          setImmediate -> resolve()
-      else
-        resolve()
+        command = "git reset HEAD #{paths.join(' ')}"
+        ChildProcess.execSync command, {cwd: @repoPath}
+
+      resolve()

   wordwrap: (str) ->
     return str unless str.length
     str.match(/.{1,80}(\s|$)|\S+?(\s|$)/g).join("\n")

   commit: (message) ->
-    Git.Repository.open(@repoPath).then (repo) =>
-      repo.openIndex().then (index) =>
-        index.writeTree().then (indexTree) =>
-          repo.getHeadCommit().then (parent) =>
-            author = Git.Signature.default(repo)
-            return repo.createCommit("HEAD", author, author, @wordwrap(message), indexTree, [parent])
+    data = {}
+    Git.Repository.open(@repoPath)
+    .then (repo) =>
+      data.repo = repo
+      repo.openIndex()
+    .then (index) =>
+      data.index = index
+      index.writeTree()
+    .then (indexTree) =>
+      data.indexTree = indexTree
+      data.repo.getHeadCommit()
+    .then (parent) =>
+      author = Git.Signature.default(data.repo)
+      return data.repo.createCommit("HEAD",
+        author,
+        author,
+        @wordwrap(message),
+        data.indexTree,
+        [parent])

   stagePatch: (patch, action) =>
-    reverse = if action == 'unstage' then '--reverse ' else ''
+    time = new Date().getTime()
+    file = Path.join(@tmpDir, "atom-file-patch-#{time}.patch")
+    path = @repoPath

-    new Promise (resolve, reject) =>
-      date = new Date
-      time = date.getTime()
+    command = "git apply --unidiff-zero --whitespace=nowarn --cached "
+    command += "--reverse " if action == 'unstage'
+    command += file

-      file = Path.join(@tmpDir, "atom-file-patch-#{time}.patch")
-
-      fse.writeFile file, patch, (e) =>
-        ChildProcess.exec "git apply --unidiff-zero --whitespace=nowarn --cached #{reverse}#{file}", {cwd: @repoPath}, =>
+    new Promise (resolve, reject) ->
+      fse.writeFile file, patch, (e) ->
+        ChildProcess.exec command, {cwd: path}, (e) ->
+          console.log(e)
           setImmediate -> resolve()


mp4: Remove test code

mp4: Remove test code

--- mp4.coffee
+++ mp4.coffee
@@ -1717,43 +1717,6 @@
 class CTOOBox extends GenericDataBox

-# test
-if process.argv.length < 3
-  console.log "Error: specify an mp4 filename"
-  return 1
-
-mp4file = new MP4File process.argv[2]
-lastAudioReceivedTime = null
-lastAudioActualTime = null
-mp4file.on 'audio_data', (data, pts) ->
-  console.log "received audio_data: pts=#{pts} time=#{pts / 90000}"
-  currentTime = getCurrentTime()
-  if lastAudioReceivedTime?
-    receivedDiff = mp4file.currentPlayTime - lastAudioReceivedTime
-    actualDiff = currentTime - lastAudioActualTime
-    timeDiff = receivedDiff - actualDiff
-    if Math.abs(timeDiff) >= 0.1
-      throw new Error "ERROR: too much audio time difference: lastAudioReceivedTime=#{lastAudioReceivedTime} playTime=#{mp4file.currentPlayTime} lastAudioActualTime=#{lastAudioActualTime} currentTime=#{currentTime} received=#{receivedDiff} actual=#{actualDiff} diff=#{timeDiff}"
-  lastAudioReceivedTime = mp4file.currentPlayTime
-  lastAudioActualTime = currentTime
-
-lastVideoReceivedTime = null
-lastVideoActualTime = null
-mp4file.on 'video_data', (data, pts) ->
-  console.log "received video_data: pts=#{pts} time=#{pts / 90000}"
-  currentTime = getCurrentTime()
-  if lastVideoReceivedTime?
-    receivedDiff = mp4file.currentPlayTime - lastVideoReceivedTime
-    actualDiff = currentTime - lastVideoActualTime
-    timeDiff = receivedDiff - actualDiff
-    if Math.abs(timeDiff) >= 0.1
-      throw new Error "ERROR: too much video time difference: lastVideoReceivedTime=#{lastVideoReceivedTime} playTime=#{mp4file.currentPlayTime} lastVideoActualTime=#{lastVideoActualTime} currentTime=#{currentTime} received=#{receivedDiff} actual=#{actualDiff} diff=#{timeDiff}"
-  lastVideoReceivedTime = mp4file.currentPlayTime
-  lastVideoActualTime = currentTime
-
-mp4file.parse()
-mp4file.play()
-
 api =
   MP4File: MP4File


fix builds

fix builds

--- lib/parsers/gsc.coffee
+++ lib/parsers/gsc.coffee
@@ -70,8 +70,8 @@
 fetchPage = (code) ->
   fetched = p.defer()

+  pageQueue.queue ->
     request "#{baseUri}/allprd-#{code}.htm"
-  pageQueue.queue ->
     .then (doc) ->
       $ = cheerio.load doc


strip thousands separator in tfa prices

strip thousands separator in tfa prices

--- lib/parsers/tfa.coffee
+++ lib/parsers/tfa.coffee
@@ -96,7 +96,7 @@
     # search through remaining tokens for a potential USD price
     price = null
     for rawPrice in text.slice(1)
-      parsedPrice = rawPrice.replace /[a-z\(\)\s\$]/gi, ''
+      parsedPrice = rawPrice.replace /[a-z\(\)\s\$\,]/gi, ''
       continue unless parsedPrice.indexOf('.') > -1 and parseFloat(parsedPrice)
       price = parseFloat(parsedPrice)
       break if price isnt null


Fix issues with pinned tabs that get a new title

--- lib/pinned-tabs.coffee
+++ lib/pinned-tabs.coffee
@@ -146,6 +146,13 @@
       pane.moveItem item, pinnedTabs.length
       tab.classList.add 'pinned'

+      # Watch for filename changes and update the state accordingly
+      oldId = @getItemID(item)
+      item.onDidChangeTitle =>
+          return if not @state.data[pane.id].includes oldId # Prevent tabs that are no longer pinned from being repinned
+          @state.data[pane.id] = @state.data[pane.id].filter (id) => id isnt oldId
+          @state.data[pane.id].push @getItemID(item) if not @state.data[pane.id].includes @getItemID(item)
+
   # Misc
   closeUnpinnedTabs: ->
     activePane = document.querySelector '.pane.active'


Add a template body to GitHub issues

Add a template body to GitHub issues

--- lib/script-view.coffee
+++ lib/script-view.coffee
@@ -174,17 +174,9 @@
       buildArgsArray = grammarMap[codeContext.lang][codeContext.argType].args

     catch error
-      urlSafeArgType = "#{codeContext.argType}".replace(' ', '')
-      urlSafeLang = "#{codeContext.lang}".replace(' ', '')
-      err = $$ ->
-        @p class: 'block', "#{codeContext.argType} runner not available for #{codeContext.lang}."
-        @p class: 'block', =>
-          @text 'If it should exist, add an '
-          @a href: "https://github.com/rgbkrk/atom-script/issues/\
-            new?title=Add%20#{urlSafeArgType}%20support%20for%20#{urlSafeLang}", 'issue on GitHub'
-          @text ', or send your own pull request.'
-
+      err = @createIssuesLink codeContext
       @handleError err
+
       return false

     # Update header to show the lang and file name
@@ -201,6 +193,23 @@

     # Return setup information
     return commandContext
+
+  createIssuesLink: (codeContext) ->
+    title = "Add #{codeContext.argType} support for #{codeContext.lang}"
+    body = """
+           ##### Platform: `#{process.platform}`
+           ---
+           """
+    encodedURI = encodeURI("https://github.com/rgbkrk/atom-script/issues/new?title=#{title}&body=#{body}")
+    # NOTE: Replace "#" after regular encoding so we don't double escape it.
+    encodedURI = encodedURI.replace(/#/g, '%23')
+
+    $$ ->
+      @p class: 'block', "#{codeContext.argType} runner not available for #{codeContext.lang}."
+      @p class: 'block', =>
+        @text 'If it should exist, add an '
+        @a href: encodedURI, 'issue on GitHub'
+        @text ', or send your own pull request.'

   handleError: (err) ->
     # Display error and kill process


ComputeProvider::Koding: ensureTopDomainExistence in machine.postCreate of Koding Provider

--- workers/social/lib/social/models/computeproviders/koding.coffee
+++ workers/social/lib/social/models/computeproviders/koding.coffee
@@ -129,6 +129,15 @@
           callback null, {
             meta, label, credential: client.r.user.username
           }
+
+
+  @postCreate = (client, options, callback)->
+
+    { r: { account } } = client
+    { machine } = options
+
+    JDomainAlias = require '../domainalias'
+    JDomainAlias.ensureTopDomainExistence account, machine._id, callback

   @update = (client, options, callback)->


Alerts Deletion - not working yet

Alerts Deletion - not working yet

--- muleview/coffee/app/view/AlertsEditor.coffee
+++ muleview/coffee/app/view/AlertsEditor.coffee
@@ -101,16 +101,21 @@
       btn.setVisible(Ext.Array.contains(btn.showInMode, mode))

   doUpdate: ->
-    url = Muleview.Mule.getAlertCommandUrl(Muleview.currentKey, Muleview.currentRetention)
+    Ext.MessageBox.confirm "Delete alerts",
+      "Are you sure you wish to delete all alerts for this graph?",
+      =>
+        @doMuleAction ("PUT")
+
+  doMuleAction: (method) ->
     @submit(
-      url: url
-      method: "PUT"
+      url: Muleview.Mule.getAlertCommandUrl(Muleview.currentKey, Muleview.currentRetention)
+      method: method
       success: ->
         Muleview.Graphs.createGraphs()
       )

   doDelete: ->
-    console.log("MuleChart.coffee\\ 148: <HERE>");
+    @doMuleAction("DELETE")

   doCreate: ->
     @getForm().clearInvalid()


sign out from panoptes session

sign out from panoptes session

use server side cors allow and ensure cookies are sent to leverage devise signout methods.

--- app/stores/user-store.coffee
+++ app/stores/user-store.coffee
@@ -85,6 +85,14 @@
   onSignOut: ->
     @_removeToken()
     @getUser()
+    fetch(client.host + '/users/sign_out', {
+      credentials: 'include',
+      method: 'DELETE',
+      headers: {
+        'Accept': 'application/json',
+        'Content-Type': 'application/json'
+      },
+    })

   _tokenExists: ->
     extractToken(window.location.hash) || localStorage.getItem('bearer_token')


Remove exspresso origin

Remove exspresso origin

--- d16acdn.coffee
+++ d16acdn.coffee
@@ -40,12 +40,13 @@
 #
 versions.set 'origin servers', [
   {url: 'http://d16a.aws.af.cm', id: 'd16a'}
-  {url: 'http://exspresso.aws.af.cm', id: 'exspresso'}
+#  {url: 'http://exspresso.aws.af.cm', id: 'exspresso'}
 ]

 #
 # Sync:
 #
+###
 versions.set 'sync', true

 redis = JSON.parse(process.env.VCAP_SERVICES)['redis-2.2'][0]
@@ -54,6 +55,7 @@
   host: redis.credentials.host
   port: redis.credentials.port
   auth: redis.credentials.password
+###

 #


task lists in quest.note are clickable

task lists in quest.note are clickable

--- www/src/views/quest/big.coffee
+++ www/src/views/quest/big.coffee
@@ -22,6 +22,18 @@
             mouseenter: (e) -> @subview(".likes-subview").showButton()
             mouseleave: (e) -> @subview(".likes-subview").hideButton()

+        _textSubview: (field) ->
+            sv = new Markdown
+                realm: @model.get("realm")
+                text: @model.get(field)
+                editable: @model.isOwned()
+            sv.on "change", =>
+                @model.set field, sv.getText()
+                sv.startSyncing()
+                @model.save().always ->
+                    sv.stopSyncing()
+            return sv
+
         subviews:
             ".likes-subview": ->
                 new Like(
@@ -32,21 +44,8 @@
                 new Textarea
                     realm: @model.get("realm")
                     placeholder: "Quest description"
-            ".quest-big-description-sv": ->
-                sv = new Markdown
-                    realm: @model.get("realm")
-                    text: @model.get("description")
-                    editable: @model.isOwned()
-                sv.on "change", =>
-                    @model.set "description", sv.getText()
-                    sv.startSyncing()
-                    @model.save().always ->
-                        sv.stopSyncing()
-                return sv
-            ".quest-big-note-sv": ->
-                new Markdown
-                    realm: @model.get("realm")
-                    text: @model.get("note")
+            ".quest-big-description-sv": -> @_textSubview "description"
+            ".quest-big-note-sv": -> @_textSubview "note"

         initialize: ->
             super


Fixes test

Fixes test

--- mobile/apps/articles/test/client/editorial_signup.coffee
+++ mobile/apps/articles/test/client/editorial_signup.coffee
@@ -13,8 +13,7 @@
       sinon.stub($, 'ajax')
       Backbone.$ = $
       @$el = $('
<div class="article-container" data-id="123"

')
-      @EditorialSignupView = benv.requireWithJadeify resolve(__dirname, '../../client/editorial_signup'), ['editorialSignupLushTemplate']
-      @cycleImages = sinon.stub @EditorialSignupView::, 'cycleImages'
+      @EditorialSignupView = benv.requireWithJadeify resolve(__dirname, '../../client/editorial_signup'), []
       sinon.stub @EditorialSignupView::, 'trackSignup'
       @ctaBarView = sinon.stub().returns
         render: sinon.stub().returns { $el: '

' }
@@ -57,7 +56,6 @@
           { src: 'image2.jpg' },
           { src: 'image3.jpg' },
         ]
-      $.ajax.args[1][0].success()
       _.defer =>
         $(@$el).children("articles-es-cta__container").css('display').should.containEql 'none'
         $(@$el).children('.articles-es-cta__social').css('display').should.containEql 'block'


fix room settings

fix room settings

--- packages/rocketchat-ui/views/app/room.coffee
+++ packages/rocketchat-ui/views/app/room.coffee
@@ -323,8 +323,8 @@
 		, 10

 	"click .flex-tab .user-image > button" : (e, instance) ->
-		#RocketChat.TabBar.openFlex()
-		#instance.setUserDetail @username
+		RocketChat.TabBar.openFlex()
+		instance.setUserDetail @username

 	'click .user-card-message': (e, instance) ->
 		roomData = Session.get('roomData' + this._arguments[1].rid)
@@ -337,8 +337,8 @@

 		if roomData.t in ['c', 'p', 'd']
 			instance.setUserDetail this._arguments[1].u.username
-			window.location.replace("https://stage.ubegin.com/discover/people/"+this._arguments[1].u.username)
-		#RocketChat.TabBar.setTemplate 'membersList'
+			#window.location.replace("https://stage.ubegin.com/discover/people/"+this._arguments[1].u.username)
+			RocketChat.TabBar.setTemplate 'membersList'

 	'scroll .wrapper': _.throttle (e, instance) ->
 		if RoomHistoryManager.isLoading(@_id) is false and (RoomHistoryManager.hasMore(@_id) is true or RoomHistoryManager.hasMoreNext(@_id) is true)
@@ -389,7 +389,7 @@
 			if RocketChat.Layout.isEmbedded()
 				return fireGlobalEvent('click-mention-link', { path: FlowRouter.path('channel', {name: channel}), channel: channel })

-			FlowRouter.go 'channel', { name: channel }, FlowRouter.current().queryParams
+			FlowRouter.go 'channel', {name: channel}
 			return

 		if RocketChat.Layout.isEmbedded()
@@ -399,9 +399,7 @@
 			return

 		RocketChat.TabBar.setTemplate 'membersList'
-		window.location.replace("https://stage.ubegin.com/discover/people/"+$(e.currentTarget).data('username'))
-		alert($(e.currentTarget).data('username'))
-		#instance.setUserDetail $(e.currentTarget).data('username')
+		instance.setUserDetail $(e.currentTarget).data('username')

 		RocketChat.TabBar.openFlex()


naming problem

naming problem

--- node_modules_koding/kite-amqp/lib/kite-amqp/index.coffee
+++ node_modules_koding/kite-amqp/lib/kite-amqp/index.coffee
@@ -145,9 +145,9 @@
     @mergen.on "error", (err)->
       console.log("Error ",err)

-    subscribeToChannelNames = [@getChannelNameForAll(), @getChannelNameForGenericName(), @getChannelNameForKite()]
-
-    for chan in subscribeToChannelNames
+    channelNames = [@getChannelNameForAll(), @getChannelNameForGenericName(), @getChannelNameForKite()]
+
+    for chan in channelNames
       @mergen.subscribe chan

     @mergen.on "message", (channel, message)=>
@@ -157,9 +157,7 @@
     # we have 3 channels to subscribe on startup,
     # we have to wait for all before we emit ready
     @mergen.on "subscribe", (channel, count)->
-      subscribeToChannelNames = _.without(subscribeToChannelNames, channel)
-      console.log ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> connected to channel", channel, subscribeToChannelNames
-
+      channelNames = _.without(subscribeToChannelNames, channel)

     startQueueChecker = ()=>
       startQueueCheckerInterval = setInterval ()=>


Components: SidebarStackSection: Minor indentation changes

--- client/app/lib/components/sidebarstacksection/index.coffee
+++ client/app/lib/components/sidebarstacksection/index.coffee
@@ -10,8 +10,8 @@
 module.exports = class SidebarStackSection extends React.Component

   @defaultProps =
-    selectedId                  : null
-    stack                       : immutable.Map()
+    selectedId  : null
+    stack       : immutable.Map()

   constructor: ->


Unset default shortcuts for splitting panels

--- .config/keymap.cson
+++ .config/keymap.cson
@@ -30,6 +30,10 @@
 	'cmd-alt-w':	'window:toggle-invisibles'
 	'shift-cmd-W':	'editor:toggle-soft-wrap'
 	'cmd-alt-0':	'window:reset-font-size'
+	'cmd-k up':		'unset!'
+	'cmd-k right':	'unset!'
+	'cmd-k left':	'unset!'
+	'cmd-k down':	'unset!'

 # Navigation


record user goal history for users in split

--- user-goals/user-goals.coffee
+++ user-goals/user-goals.coffee
@@ -184,11 +184,18 @@
       @goal = goalSlider.val()
       @el.find("#slider-val").text(@goal + " Classification#{@sCheck(@goal)}")

+  recordGoalHistory: ->
+    history = User.current?.preferences?.kelp?.goal_history || {}
+    history["#{new Date()}"] = @goal
+    User?.current?.setPreference "goal_history", history
+
   setUserGoal: =>
     @content.html("
Goal set for #{@goal} Classification#{@sCheck(@goal)}
")

     User?.current?.setPreference "goal_set", "true"
     User?.current?.setPreference "goal", @goal
+    @recordGoalHistory()
+
     @setLastSessionCount(0)

     setTimeout =>


Protect against week context in top level expression

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1139,7 +1139,7 @@
     malformed ctx, expression, "#{dependencyName} is not defined"
     undefined
   else
-    (irDefinition expression.tea, compiled)
+    (irDefinition expression.tea, compiled, null, yes)

 topLevel = (ctx, form) ->
   if (terms = _validTerms form).length % 2 == 0
@@ -2412,13 +2412,13 @@
       walked.js = ast.js
       walked

-irDefinition = (type, expression, id) ->
-  {ir: irDefinitionTranslate, type, expression, id}
+irDefinition = (type, expression, id, bare) ->
+  {ir: irDefinitionTranslate, type, expression, id, bare}

 # TODO: This must always wrap a function, because if the expression
 #       is not a function then it can't need type class dictionaries
 #       ^.___ not necessarily, we could have a tuple of functions or similar
-irDefinitionTranslate = (ctx, {type, expression, id}) ->
+irDefinitionTranslate = (ctx, {type, expression, id, bare}) ->
   finalType = substitute ctx.substitution, type
   allConstraints = (addConstraintsFrom ctx, {id, type}, finalType).constraints
   reducedConstraints =
@@ -2426,6 +2426,9 @@
     #   constraintsFromCanonicalType ctx, declaredType, finalType
     # else
       reduceConstraints ctx, allConstraints
+  if bare and _notEmpty reducedConstraints
+    malformed ctx, expression, "Ambiguous class constraints: #{map safePrintType, reducedConstraints}"
+    return "null";
   ctx.updateClassParams()
   # TODO: what about the class dictionaries order?
   counter = {}
@@ -5467,7 +5470,7 @@
   "(first (concat {{1} {2} {3}}))", 1

   'mixing constructor classes with fundeps'
-  """
+  concatTest = """
   Mappable (class [wrapper]
     map (fn [what onto]
       (: (Fn (Fn a b) (wrapper a) (wrapper b)))))
@@ -5510,15 +5513,32 @@

   concat-map (fn [what over]
     (concat (map what over)))
+  """
+  """(size (concat-map (fn [x] {1}) {1 2 3}))""", 3
+
+  'overloaded subfunctions'
+  """
+  #{concatTest}

   concat-suffix (fn [suffix what]
     (fold join-suffix empty what)
     join-suffix (fn [x joined]
       (concat {joined suffix x})))
   """
-  """(size (concat-suffix {1} (concat-map (fn [x] {{1}}) {1 2 3})))""", 6
-
-  """recursive overloaded functions"""
+  "(size (concat-suffix {1} (concat-map (fn [x] {{1}}) {1 2 3})))", 6
+
+  'overloaded subterms'
+  """
+  #{concatTest}
+
+  concat-suffix (fn [suffix what]
+    (fold join-suffix e what)
+    join-suffix (fn [x joined]
+      (concat {joined suffix x})))
+  """
+  "(size (concat-suffix {1} (concat-map (fn [x] {{1}}) {1 2 3})))", 6
+
+  'recursive overloaded functions'
   """
   Show (class [a]
     show (fn [x] (: (Fn a String))))
@@ -5539,7 +5559,7 @@
   """
   "(== x (y True))", yes

-  "ffi function"
+  'ffi function'
   """
     upper-case (fn [x]
       (: (Fn String String))
@@ -5547,15 +5567,15 @@
   """
   """(upper-case "Hello")""", "HELLO"

-  "ffi expression"
+  'ffi expression'
   """"""
   """(.toUpperCase "x")""", "X"

-  "ffi access"
+  'ffi access'
   """"""
   "Math.PI", Math.PI

-  "ffi access on global"
+  'ffi access on global'
   """"""
   "global.Math.PI", Math.PI


Get rid of more old counter logic

Get rid of more old counter logic

--- vendor/assets/javascripts/brainstem/data-loader.coffee
+++ vendor/assets/javascripts/brainstem/data-loader.coffee
@@ -162,10 +162,11 @@
               only: associationIds
               include: nextLevel
               error: @loadOptions.error
-              success: (_collection, layers = 1) =>
+              success: =>
                 c += 1
+
                 if c == expectedServerRequests
-                  options.success() #if options.success?
+                  options.success()

             cl = new Brainstem.CollectionLoader(storageManager: @storageManager)
             cl.loadCollection(opts)


add an acceptance test for flush with queue processing

--- test/acceptance/coffee/DeletingAProjectTests.coffee
+++ test/acceptance/coffee/DeletingAProjectTests.coffee
@@ -97,7 +97,41 @@
 		it "should flush each doc in project history", ->
 			MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true

-	describe "with the background=true parameter from realtime", ->
+	describe "with the background=true parameter from realtime and no request to flush the queue", ->
+		before (done) ->
+			sinon.spy MockWebApi, "setDocument"
+			sinon.spy MockTrackChangesApi, "flushDoc"
+			sinon.spy MockProjectHistoryApi, "flushProject"
+
+			async.series @docs.map((doc) =>
+				(callback) =>
+					DocUpdaterClient.preloadDoc @project_id, doc.id, callback
+			), (error) =>
+				throw error if error?
+				setTimeout () =>
+					DocUpdaterClient.deleteProjectOnShutdown @project_id, (error, res, body) =>
+						@statusCode = res.statusCode
+						done()
+				, 200
+
+		after ->
+			MockWebApi.setDocument.restore()
+			MockTrackChangesApi.flushDoc.restore()
+			MockProjectHistoryApi.flushProject.restore()
+
+		it "should return a 204 status code", ->
+			@statusCode.should.equal 204
+
+		it "should not send any documents to the web api", ->
+			MockWebApi.setDocument.called.should.equal false
+
+		it "should not flush any docs in track changes", ->
+			MockTrackChangesApi.flushDoc.called.should.equal false
+
+		it "should not flush to project history", ->
+			MockProjectHistoryApi.flushProject.called.should.equal false
+
+	describe "with the background=true parameter from realtime and a request to flush the queue", ->
 		before (done) ->
 			sinon.spy MockWebApi, "setDocument"
 			sinon.spy MockTrackChangesApi, "flushDoc"


Sidebar: Removed newItemsCounter from ActivityLink itself.

--- client/landing/app/MainApp/navigation/navigationactivitylink.coffee
+++ client/landing/app/MainApp/navigation/navigationactivitylink.coffee
@@ -8,12 +8,10 @@

     appManager = KD.getSingleton "appManager"

-    @newActivityCount = 0
-
     @count = new KDCustomHTMLView
       tagName   : "span"
       cssClass  : "main-nav-icon transparent"
-      partial   : "#{@newActivityCount}"
+      partial   : ""
       click     : =>
         @setActivityLinkToDefaultState()
         appManager.tell "Activity", "unhideNewItems"
@@ -39,16 +37,14 @@
       @setActivityLinkToDefaultState()

   updateNewItemsCount: (itemCount) ->
-    newItemsCount = itemCount or= @newActivityCount
-    return if newItemsCount is 0
+    return if itemCount is 0
+    @count.updatePartial itemCount
     @count.show()
     @icon.hide()
-    @count.updatePartial newItemsCount

   setActivityLinkToDefaultState: ->
     @icon.show()
     @count.hide()
-    @newActivityCount = 0

   viewAppended:->
     @setTemplate @pistachio()


Output: make deletable button non-flat

Output: make deletable button non-flat

--- src/elements/Output/Output.coffee
+++ src/elements/Output/Output.coffee
@@ -92,7 +92,6 @@
 			@addClass("cui-output--deletable")
 			@__deleteBtn = new Button
 				icon: "remove"
-				appearance: "flat"
 				onClick: =>
 					@setValue(null, no_trigger: false)
 			@append(@__deleteBtn)


toLowerCase the mnfr

toLowerCase the mnfr

--- index.coffee
+++ index.coffee
@@ -67,7 +67,8 @@
     serialport.list (err, ports) =>
       portName = null
       ports.forEach (port) =>
-        portName = port.comName if port.manufacturer.indexOf('Arduino') != -1
+        manufacturer = port.manufacturer.toLowerCase()
+        portName = port.comName if manufacturer.indexOf('arduino') != -1
         debug 'port:', port.comName
         debug 'id: ', port.pnpId
         debug 'manufacturer:', port.manufacturer


disable simple api logging

disable simple api logging

--- index.coffee
+++ index.coffee
@@ -17,7 +17,7 @@

 session = session
 	secret: configs.secret_key
-	cookie:
+	cookie:
 		maxAge: 365 * 24 * 60 * 60 * 1000

 kickoff = () ->
@@ -32,7 +32,7 @@
 				port: configs.port
 				before: prepareAPIRequest
 				fallback: apiFallback
-				logLevel: 0
+				logLevel: 5

 			oldRespond = v0.responses.respond
 			v0.responses.respond = (res, message, statusCode) ->
@@ -192,12 +192,12 @@
 	try
 		urlParts = url.parse req.url, true
 		code = urlParts.query.code
-		form =
+		form =
 			app_id: configs.clef.app_id
 			app_secret: configs.clef.app_secret
 			code: code

-		request.post
+		request.post
 			url: 'https://clef.io/api/v1/authorize'
 			form: form
 		, (err, resp, body) ->
@@ -218,7 +218,7 @@
 								v0.responses.notAuth res
 							else
 								Users = mongoose.model "Users"
-
+
 								Users.getByIdentifier userInfo.info.id, (err, existingUser) ->
 									if err
 										v0.responses.internalError res, "Error finding your user.  This probably isn't your fault.  Try again."


Dropped general library description.

Dropped general library description.

--- index.coffee
+++ index.coffee
@@ -1,19 +1,3 @@
-###
-General library conventions:
-
-- Properties and methods with a leading underscore are private. None is exposed
-publicly, but sometimes you might inevitably find them while retrieving objects.
-They shouldn't be modified.
-
-- Most insertion, deletion and fetch methods are called `add something`, `remove
-something` and `get something`, where it makes sense. These methods also return
-the item added/removed/gotten, unless stated otherwise.
-
-- The property/method names are all chosen for their readability, expressiveness
-and consistency across the library. Most of the times you can guess them.
-
-Happy coding! Feel free to drop your suggestions on the issues page, thank you!
-###
 module.exports =
     Graph: require './Graph'
     Heap: require './Heap'


we need bodyparser only once

we need bodyparser only once

--- index.coffee
+++ index.coffee
@@ -160,7 +160,6 @@
   app = express()
   app.use express.logger('dev')
   app.use express.favicon()
-  app.use express.bodyParser()
   app.use express.cookieParser()
   app.use express.cookieSession(secret: options?.secret)
   app.use passport.initialize()


error handling

error handling

--- index.coffee
+++ index.coffee
@@ -51,6 +51,14 @@
 app.use (req, res, next) ->
   proxy.web req, res, { target: ARTSY_URL }

+# Display similar errors
+app.use (err, req, res, next) ->
+  if err.status
+    body = if _.isEmpty(b = err.response.body) then err.response.text else b
+    res.status(err.status).send(body)
+  else
+    next err
+
 # Fetch & hoist an xapp token
 request
   .post("#{ARTSY_URL}/api/tokens/xapp_token")


Input 'this' now returns input node

Input 'this' now returns input node

--- input.coffee
+++ input.coffee
@@ -73,7 +73,10 @@
 			v

 	@get = (input, prop) ->
-		Input.getVal input.self, prop
+		if prop is 'this'
+			input.node
+		else
+			Input.getVal input.self, prop

 	@getStoragesArray = do (arr = []) -> (file) ->
 		assert.instanceOf file, File


Searching again will reset to page 1

Searching again will reset to page 1

--- SingularityUI/app/components/taskSearch/TaskSearch.cjsx
+++ SingularityUI/app/components/taskSearch/TaskSearch.cjsx
@@ -34,6 +34,7 @@
         @setState
             showForm: false
             queryParams: @state.form
+            pageNumber: 1 # If you narrow down your search you most likely want to go back to page 1

     # Annoying that we need a new function for each property.
     # Unfortuantely using a curried function doesn't seem to work.


:space_invader::thumbsup: Updated in browser at strd6.github.io/editor

--- pixie.cson
+++ pixie.cson
@@ -3,7 +3,7 @@
 remoteDependencies: [
   "//code.jquery.com/jquery-1.10.1.min.js"
   "//cdnjs.cloudflare.com/ajax/libs/coffee-script/1.6.3/coffee-script.min.js"
-  "http://strd6.github.io/tempest/javascripts/envweb-v0.4.7.js"
+  "https://pixipaint.net/envweb-v0.4.7.js"
 ]
 dependencies:
   appcache: "STRd6/appcache:v0.1.0"


Fix broken test due to UI changes since last successful run

--- tests/features/step_definitions/incident_steps.coffee
+++ tests/features/step_definitions/incident_steps.coffee
@@ -57,7 +57,7 @@

     @When /^I add the first suggested incident$/, ->
       # SuggestedIncidentsModal
-      @client.waitForVisible('#suggested-locations-form p.annotated-content')
+      @client.waitForVisible('.suggested-annotated-content')
       if @client.isVisible('div.warn')
         text = @client.getText('div.warn')
         assert.equal(text.trim(), 'No incidents could be automatically extracted from the document.')
@@ -65,7 +65,7 @@
         return true
       if @client.isVisible('span.annotation.annotation-text')
         scrollWithinModal(@client,
-            '#suggestedIncidentsModal div.suggested-incidents-wrapper',
+            '#suggested-locations-form',
             'span.annotation.annotation-text', -200)
         @client.clickWhenVisible('span.annotation.annotation-text')
         # SuggestedIncidentModal


Display categories after reload.

Display categories after reload.

--- app/assets/javascripts/application/app_router.js.coffee
+++ app/assets/javascripts/application/app_router.js.coffee
@@ -27,6 +27,7 @@
     @appController.displayPodsAndUpdateScope(parseInt(idx), filter, sort_by)
   reload: ->
     @appController.loadPods()
+    @navigate('/', true)
   pageview: (page) ->
     if window.ga
       window.ga 'send', 'pageview', page


Index categories.

Index categories.

--- app/assets/javascripts/application/pods_store.js.coffee
+++ app/assets/javascripts/application/pods_store.js.coffee
@@ -11,6 +11,8 @@
         keyPath: 'stars'
       },{
         keyPath: 'pushed_at'
+      },{
+        keyPath: 'category'
       }]
     @db = new ydn.db.Storage 'pods', stores: [podsSchema]
   update: (new_records) ->


Use terrain map type on JS map module

Use terrain map type on JS map module

--- app/assets/javascripts/neighborly/modules/map.js.coffee
+++ app/assets/javascripts/neighborly/modules/map.js.coffee
@@ -7,7 +7,8 @@
     mapCanvasSelector = '.map-canvas' if typeof mapCanvasSelector is 'undefined'
     mapCanvas = $(mapCanvasSelector)[0]
     mapOptions =
-      zoom: 11
+      zoom: 14
       center: new google.maps.LatLng($('.address-coordinates').data('latitude'), $('.address-coordinates').data('longitude'))
       disableDefaultUI: true
+      mapTypeId: 'terrain'
     map = new google.maps.Map(mapCanvas, mapOptions)


hotfix: remove log

hotfix: remove log

--- assets/javascripts/backbone/view/extension/store.coffee
+++ assets/javascripts/backbone/view/extension/store.coffee
@@ -124,7 +124,6 @@
     @infinite = options.infinite
     if @infinite?
       @options = _.extend(@options, @defaults.infinite, @infinite)
-      console.log @options

   on: ->
     @off() if @handlers?