Added in callback to get, train, quota, for sentiment

--- lib/sentiment.coffee
+++ lib/sentiment.coffee
@@ -8,7 +8,7 @@
 	######
 	core = require('./core')(api_key)

-	get = (text) ->
+	get = (text, callback) ->
 		core.callApi(
 			'sentiment',
 			'review',
@@ -21,7 +21,7 @@
 					callback({code:status, msg: err})
 		)

-	train = (text, mood) ->
+	train = (text, mood, callback) ->
 		core.callApi(
 			'sentiment',
 			'train',
@@ -34,7 +34,7 @@
 					callback({code:status, msg: err})
 		)

-	quota = () ->
+	quota = (callback) ->
 		core.callApi(
 			'sentiment',
 			'quota',


remove compile cloud

remove compile cloud

--- lib/spark-dev.coffee
+++ lib/spark-dev.coffee
@@ -18,19 +18,14 @@
       callback: 'spark-dev:flash-cloud'
       tooltip: 'Compile and upload code using cloud'
       iconset: 'ion'
-    @compileButton = @toolBar.addButton
-      icon: 'checkmark-circled'
-      callback: 'spark-dev:compile-cloud'
-      tooltip: 'Compile and show errors if any'
-      iconset: 'ion'

     @toolBar.addSpacer()

     @toolBar.addButton
       icon: 'document-text'
       callback: ->
-        require('shell').openExternal('http://docs.spark.io/')
-      tooltip: 'Opens reference at docs.spark.io'
+        require('shell').openExternal('https://github.com/nodemcu/nodemcu-firmware/wiki')
+      tooltip: 'Opens NodeMCU Document'
       iconset: 'ion'
     @coreButton = @toolBar.addButton
       icon: 'pinpoint'


app.data fix/note

app.data fix/note

--- app/ng/app.data.coffee
+++ app/ng/app.data.coffee
@@ -41,4 +41,4 @@
     TranzitUser.updateUser(password, params)
       .error (error) -> AppEvents.event EventNames.RemoteCallError, error

-  return @+  return @ # only need one per module!


don't need to return this explicitly

don't need to return this explicitly

--- src/models/channel.coffee
+++ src/models/channel.coffee
@@ -26,6 +26,5 @@
     message = new Message(@, msg)
     @messages.shift() if @messages.length > 50
     @messages.push(message)
-    message

 module.exports = Channel


Add key attribute to components

Add key attribute to components

--- src/navigation/index.cjsx
+++ src/navigation/index.cjsx
@@ -40,8 +40,8 @@
     {view} = @context

     brand = [
-      Concept Coach
-      <CourseNameBase className='hidden-sm hidden-xs' course={course}/>
+      Concept Coach
+      <CourseNameBase key = 'course-name' className='hidden-sm hidden-xs' course={course}/>
     ]

     courseItems = [


Chain anything with a url.

Chain anything with a url.

Allows things like file.readBinary().

--- src/replacer.coffee
+++ src/replacer.coffee
@@ -42,6 +42,7 @@
     # If the URL matches one of the "Object" types (repo, user, comment)
     # then provide all of the same methods as `octo.repo(...)` would have on it
     url = acc.url
+    Chainer(@_request, url, null, null, acc) if url
     for key, re of OBJECT_MATCHER
       if re.test(url)
         context = TREE_OPTIONS


re-enable sourcemaps

re-enable sourcemaps

--- src/browserify_bundle.coffee
+++ src/browserify_bundle.coffee
@@ -16,8 +16,7 @@
 module.exports = browserifyBundle = ({src, dest}, opts={}) ->
   assetConfig = require path.join(process.cwd(), 'Assetfile')

-  console.warn('WARNING: sourcemaps in goodeggs-assets-cli have been disabled because they broke.')
-  opts.sourcemaps = false
+  opts.sourcemaps ?= true

   args = _.defaults {}, opts.browserifyArgs,
     debug: opts.sourcemaps


Make height sufficient enough to fit the word 'Households'

--- app/assets/javascripts/d3/mekko.coffee
+++ app/assets/javascripts/d3/mekko.coffee
@@ -88,7 +88,7 @@
       legend_columns = if @carrier_list.length > 9 then 3 else 2
       legend_rows = @carrier_list.length / legend_columns
       legend_height = legend_rows * @legend_cell_height
-      @label_height = 80 # rotated labels
+      @label_height = 85 # rotated labels
       @label_margin = 25

       @series_height  = @height - legend_height - @label_height - @label_margin


Fix wrong require for javascript.

Fix wrong require for javascript.

--- app/assets/javascripts/front.js.coffee
+++ app/assets/javascripts/front.js.coffee
@@ -1,9 +1,9 @@
 #= require jquery
-#= require jquery_ujs
+#= require jquery-ujs
 #= require common
 #= require front/cufon-yui
 #= require front/Aller.font
 #= require front/slides.min.jquery
 #= require front/front

-#= require_self+#= require_self


Calculate sold item sum

Calculate sold item sum

--- app/assets/javascripts/items.js.coffee
+++ app/assets/javascripts/items.js.coffee
@@ -1,3 +1,7 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
+$ ->
+  $('.sell').click ->
+    sum = 0
+    $('.sell:checked').each ->
+      price = parseFloat $(@).closest('tr').find('.price').html()
+      sum += price
+    $('.sum').html(sum)


Fix javascript error with deleting messages in issue or merge request

Elements searched for by jQuery no longer existed in the DOM.
Javascript was also unnecessarily complex, for using jQuery
Fixes #8109

--- app/assets/javascripts/notes.js.coffee
+++ app/assets/javascripts/notes.js.coffee
@@ -355,7 +355,7 @@
     $('.note[id="' + note_id + '"]').each ->
       note = $(this)
       notes = note.closest(".notes")
-      count = notes.closest(".notes_holder").find(".discussion-notes-count")
+      count = notes.closest(".issuable-details").find(".notes-tab .badge")

       # check if this is the last note for this line
       if notes.find(".note").length is 1
@@ -365,9 +365,10 @@

         # for diff lines
         notes.closest("tr").remove()
-      else
-        # update notes count
-        count.get(0).lastChild.nodeValue = " #{notes.children().length - 1}"
+
+      # update notes count
+      oldNum = parseInt(count.text())
+      count.text(oldNum - 1)

       note.remove()


OX-70 gui for dataset chooser

OX-70 gui for dataset chooser

--- app/assets/javascripts/view/gui.coffee
+++ app/assets/javascripts/view/gui.coffee
@@ -25,6 +25,18 @@
                 upload : @uploadNML
                 download : => window.open(jsRoutes.controllers.admin.NMLIO.downloadList().url,
                                           "_blank", "width=700,height=400,location=no,menubar=no")
+
+                resume : false
+                dataset : null
+                changeDataset : ->
+
+                  request(
+                    method : "POST"
+                    url : "experiment"
+                    data :
+                      dataset : @settings.dataset
+                      resume : @settings.resume
+                  ).done -> window.location.refresh()

                 position : initPos[0] + ", " + initPos[1] + ", " + initPos[2]
                 lockZoom: data.lockZoom
@@ -60,6 +72,19 @@
                           .name("Upload NML")
     (fFile.add @settings, "download")
                           .name("Download NML")
+
+    fExperiment = @gui.addFolder("Experiment")
+    request(
+      url : "/datasets"
+    ).done (datasets) =>
+
+      (fExperiment.add @settings, "resume")
+                            .name("Resume Experiment")
+      (fExperiment.add @settings, "dataset", datasets)
+                            .name("Datasets")
+      (fExperiment.add @settings, "changeDataset")
+                            .name("Apply")
+

     fPosition = @gui.addFolder("Position")
     (fPosition.add @settings, "position")
@@ -276,4 +301,9 @@
     @settings.activeNodeID = @model.Route.lastActiveNodeId
     @settings.activeTreeID = @model.Route.getActiveTreeId()
     @activeNodeIdController.updateDisplay()
-    @activeTreeIdController.updateDisplay()+    @activeTreeIdController.updateDisplay()
+
+  # Helper method to combine common update methods
+  update : ->
+    @updateNodeAndTreeIds()
+    @updateRadius()


Improve javaScript activeadmin

Improve javaScript activeadmin

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -1,13 +1,17 @@
 #= require jquery
 #= require jquery_ujs
+#= require foundation
 #= require rails.validations
 #= require rails.validations.simple_form
 #= require rails.validations.simple_form.fix
-#= require rails.validations.turbolinks
 #= require turbolinks
 #= require nprogress
 #= require nprogress-turbolinks
 #= require jquery.autosize
 #= require globals/_functions
 #= require tools/mapbox
-#= require tools/nprogress+#= require tools/nprogress
+
+$(document).on 'ready page:load page:restore', ->
+  $(document).foundation()
+  $('.autosize').autosize()


rm app/coffeescripts/object/assign.coffee

refs: CNVS-37358

Nothing uses this and now that we polyfill for
Object.assign in ie-11-polyfill this will just
Be there in all the browsers we support

Test plan:
Specs should pass

Change-Id: I9c1fce3ba895fd2e0d86203e61b6c3bc622a1e66
Reviewed-on: https://gerrit.instructure.com/114381
Tested-by: Jenkins
Reviewed-by: brian kirkby <9a8a656cc2d0f066b1a373934e1a6a0652844ecd@instructure.com>
Product-Review: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>
QA-Review: Ryan Shaw <ea3cd978650417470535f3a4725b6b5042a6ab59@instructure.com>

--- app/coffeescripts/object/assign.coffee
+++ app/coffeescripts/object/assign.coffee
@@ -1,38 +0,0 @@
-#
-# Copyright (C) 2015 - present Instructure, Inc.
-#
-# This file is part of Canvas.
-#
-# Canvas is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Affero General Public License as published by the Free
-# Software Foundation, version 3 of the License.
-#
-# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Affero General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-
-define ->
-  ToObject = (val) ->
-    if val == null
-      throw new TypeError('Object.assign cannot be called with null or undefined')
-    Object val
-
-  'use strict'
-  ObjectAssign = Object.assign or (target, source) ->
-    from = undefined
-    keys = undefined
-    to = ToObject(target)
-    s = 1
-    while s < arguments.length
-      from = arguments[s]
-      keys = Object.keys(Object(from))
-      i = 0
-      while i < keys.length
-        to[keys[i]] = from[keys[i]]
-        i++
-      s++
-    to


Re-enabled top team graph interactivity.

--- picoCTF-web/web/coffee/progression_graphs.coffee
+++ picoCTF-web/web/coffee/progression_graphs.coffee
@@ -16,7 +16,7 @@
   },
   pointSize: 3,
   areaOpacity: 0.0,
-  enableInteractivity: false
+  enableInteractivity: true
 }

 teamGraphOptions = {


Fix exception with drop zone

Fix exception with drop zone

--- app/frontend/javascripts/app.js.coffee
+++ app/frontend/javascripts/app.js.coffee
@@ -3,7 +3,6 @@
 App.Visualization = require './visualization.js'
 App.Story         = require './story.js'
 App.Trix          = require 'script!trix'
-
 Dropzone          = require 'dropzone'

 $(document).ready ->
@@ -32,52 +31,53 @@
   $('#relations_select_all').change (e) ->
     $('.table tbody input[type=checkbox]').prop 'checked', $(this).prop('checked')

+  # Dropzones
+  if $('#dropzone-preview-template').size() > 0
+    Dropzone.options.chapterDropzone =
+      autoProcessQueue: false
+      uploadMultiple: false
+      clickable: false
+      maxFiles: 1
+      acceptedFiles: 'image/*'
+      paramName: 'chapter[image]'
+      previewsContainer: '.media-left'
+      previewTemplate: document.getElementById('dropzone-preview-template').innerHTML
+      init: ->
+        theDropzone = this
+        @element.querySelector('input[type=submit]').addEventListener 'click', (e) ->
+          e.preventDefault()
+          e.stopPropagation()
+          if theDropzone.getQueuedFiles().length > 0
+            theDropzone.processQueue()
+          else
+            e.srcElement.parentElement.submit()
+          return
+        mockFile =
+          name: '__mockfile__'
+          size: 0
+        imageUrl = $('.media-left').attr('data-image')
+        if imageUrl
+          @emit 'addedfile', mockFile
+          @emit 'thumbnail', mockFile, imageUrl
+          @emit 'complete', mockFile
+          @files.push mockFile
+        @on 'addedfile', ->
+          $('#placeholder').hide()
+          first_file = @files[0]
+          if first_file.name == '__mockfile__' and first_file.size == 0
+            @removeFile first_file
+          return
+        @on 'maxfilesexceeded', (file) ->
+          @removeAllFiles()
+          @addFile file
+          return
+        @on 'success', (file, response) ->
+          window.location = response.location
+          return
+        return
+
   # Add file input feedback
   # based on http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/
   $(document).on 'change', '.btn-file :file', () ->
       label     = $(this).val().replace(/\\/g, '/').replace(/.*\//, '')
-      $(this).parent().siblings('.btn-file-output').html label
-
-  # Dropzones
-  Dropzone.options.chapterDropzone =
-    autoProcessQueue: false
-    uploadMultiple: false
-    clickable: false
-    maxFiles: 1
-    acceptedFiles: 'image/*'
-    paramName: 'chapter[image]'
-    previewsContainer: '.media-left'
-    previewTemplate: document.getElementById('dropzone-preview-template').innerHTML
-    init: ->
-      theDropzone = this
-      @element.querySelector('input[type=submit]').addEventListener 'click', (e) ->
-        e.preventDefault()
-        e.stopPropagation()
-        if theDropzone.getQueuedFiles().length > 0
-          theDropzone.processQueue()
-        else
-          e.srcElement.parentElement.submit()
-        return
-      mockFile =
-        name: '__mockfile__'
-        size: 0
-      imageUrl = $('.media-left').attr('data-image')
-      if imageUrl
-        @emit 'addedfile', mockFile
-        @emit 'thumbnail', mockFile, imageUrl
-        @emit 'complete', mockFile
-        @files.push mockFile
-      @on 'addedfile', ->
-        $('#placeholder').hide()
-        first_file = @files[0]
-        if first_file.name == '__mockfile__' and first_file.size == 0
-          @removeFile first_file
-        return
-      @on 'maxfilesexceeded', (file) ->
-        @removeAllFiles()
-        @addFile file
-        return
-      @on 'success', (file, response) ->
-        window.location = response.location
-        return
-      return+      $(this).parent().siblings('.btn-file-output').html label


The previous two commits close #187, close #226

--- extension/packages/commands.coffee
+++ extension/packages/commands.coffee
@@ -243,7 +243,7 @@

 # Switch into find mode
 command_find = (vim, storage) ->
-  vim.enterMode('find')
+  vim.enterMode('find', { highlight: false })

 # Switch into find mode with highlighting
 command_find_hl = (vim, storage) ->


Another Fix

Another Fix

--- modules/player/commands.coffee
+++ modules/player/commands.coffee
@@ -186,7 +186,7 @@
         msg.reply l.gen(l.player.multiRemove, n)
       else
         # Delete single item
-        unless itm.requestedBy is msg.author.id or @permissions.isDJ msg.member
+        unless itm.requestedBy.id is msg.author.id or @permissions.isDJ msg.member
           return msg.channel.send l.player.onlyRemoveOwn
         { item } = player.queue.remove(index, msg.member)
         msg.channel.sendMessage l.player.hud.removed,


Creating editor for images.

Creating editor for images.

--- src/main/webapp/admin/app/controllers/galleries.coffee
+++ src/main/webapp/admin/app/controllers/galleries.coffee
@@ -14,8 +14,8 @@
 		initialize: ->
 			super
 			tabs = [
-				{ a: "#", label: "Meta", page: new EditGalleryView({ model: @model }) },
-				{ a: "#", label: "Images", page: new GalleryImagesView({ model: @model }) }
+				{ a: "#", label: "Meta", page: new GalleryInfoEditor({ model: @model }) },
+				{ a: "#", label: "Images", page: new GalleryImagesEditor({ model: @model }) }
 			]
 			@tabs_controller = new TabsController
 				tabs: tabs
@@ -25,7 +25,7 @@
 			@$(".editor").empty().append(el)

-	class EditGalleryView extends CoffeeBar.TemplateController
+	class GalleryInfoEditor extends CoffeeBar.TemplateController
 		events:
 			"click .btn-ok": "do_submit"
 			"click .btn-cancel": "do_cancel"
@@ -71,7 +71,7 @@

 			false

-	class GalleryImagesView extends CoffeeBar.TemplateController
+	class GalleryImagesEditor extends CoffeeBar.TemplateController
 		template: jade["gallery/edit_images.jade"]

 		initialize: ->
@@ -84,7 +84,7 @@
 				collection: @image_collection
 				child_control: (model) ->
 					console.log "foo"
-					new ImageItem({ model: model })
+					new ImageListItem({ model: model })

 		on_render: ->
 			el = @collection_controller.render().el
@@ -92,7 +92,7 @@
 			@$(".images").empty().append(el)

-	class ImageItem extends CoffeeBar.TemplateController
+	class ImageListItem extends CoffeeBar.TemplateController
 		template: jade["gallery/image.jade"]

@@ -106,13 +106,13 @@

 			@collection_controller = new CollectionController
 				collection: app.galleries
-				child_control: (model) -> new GalleryItem({ model: model })
+				child_control: (model) -> new GalleryListItem({ model: model })

 		on_render: ->
 			el = @collection_controller.render().el
 			@$(".galleries").empty().append(el)

-	class GalleryItem extends CoffeeBar.TemplateController
+	class GalleryListItem extends CoffeeBar.TemplateController
 		template: jade["gallery/item.jade"]
 		events:
 			"click a.btn-delete": "do_delete"


Let Danny do CSS magic when the invitations are sent.

Once we hit send, add the class .animation-fadeout and then wait two
seconds to delete the div.

--- js/inner/build.coffee
+++ js/inner/build.coffee
@@ -367,7 +367,8 @@
     @invites = @komp =>
       if not @invite_sent() and not @previous_successful_build() and @outcome() == "success" and VM.project()
         new CI.inner.BuildInvite VM.project().users(), () =>
-          @invite_sent(true)
+          $(".first-green").addClass("animation-fadeout")
+          window.setTimeout (() => @invite_sent(true)), 2000

   feature_enabled: (feature_name) =>
     @feature_flags()[feature_name]
@@ -407,7 +408,7 @@
       estimate_is_not_too_low = current_build_millis < estimated_millis * 1.5
       estimate_is_positive = estimated_millis > 0

-      return estimate_is_positive and estimate_is_not_too_low
+      return estimate_is_positive and esXbtimate_is_not_too_low

     if @previous_successful_build()?
       estimated_millis = @previous_successful_build().build_time_millis


Use jQuery to replace data-ids rather than regex.

--- vendor/assets/javascripts/control.js.coffee
+++ vendor/assets/javascripts/control.js.coffee
@@ -1,6 +1,4 @@
 class TokenTextArea
-  TOKEN_REGEX: /[^<]+<\/span>/i
-  ID_REGEX: /data-id="[0-9]+"/i
   WORD_REGEX: /[a-z]+$/i

   SUCCESS_COLOR: '#64b80b;'
@@ -219,10 +217,12 @@

     # Replace tokens with #id#.
     equation = @fixHtmlTags(@input.html())
-    while (token = equation.match(@TOKEN_REGEX)) != null
-      idReg = token[0].match(@ID_REGEX)
-      id = idReg[0].replace('data-id="', '').replace('"', '')
-      equation = equation.replace(@TOKEN_REGEX, ' #' + id + '# ')
+
+    # Turn equation into jQuery object and replace each token with its data-id.
+    equation = $('
' + equation + '
')
+    equation.children('.token').each ->
+      $(this).replaceWith('#' + $(this).data('id') + '#')
+    equation = equation.text()

     # Check with server to find if expression is valid.
     if @options.onChange


Revert "force usage of jQuery 2 from jquery-rails"

--- app/assets/javascripts/active_admin/base.js.coffee
+++ app/assets/javascripts/active_admin/base.js.coffee
@@ -1,4 +1,4 @@
-#= require jquery2
+#= require jquery
 #= require ./jquery_ui
 #= require jquery_ujs
 #= require_self


Fix hypnen replace

Fix hypnen replace

--- app/assets/javascripts/anaconda_uploader.js.coffee
+++ app/assets/javascripts/anaconda_uploader.js.coffee
@@ -239,8 +239,9 @@
     # DLog "will now fill form #{@upload_complete_form_to_fill}"

     DLog "#{@resource}_#{@attribute}_file_path"
-    hyphenated_resource  = @resource.replace("_", "-")
-    hyphenated_attribute = @attribute.replace("_", "-")
+    hyphenated_resource  = @resource.replace(/_/g, "-")
+    hyphenated_attribute = @attribute.replace(/_/g, "-")
+    DLog "input[data-#{hyphenated_resource}-#{hyphenated_attribute}-file-path]"

     $( @element_id ).siblings( "input[data-#{hyphenated_resource}-#{hyphenated_attribute}-file-path]" ).val( @key.replace("${filename}", @file.name) )
     $( @element_id ).siblings( "input[data-#{hyphenated_resource}-#{hyphenated_attribute}-filename]" ).val( @file.name )


Change js depending of window with

Change js depending of window with


Add new tool to tools.js

Add new tool to tools.js

Update tools.js to include new syndicated version of debt advice locator
face to face.

--- app/assets/javascripts/syndication/tools.js.coffee
+++ app/assets/javascripts/syndication/tools.js.coffee
@@ -285,6 +285,13 @@
         path: "cy/tools/canfyddwr-cyngor-ar-ddyledion"
       title: "Debt advice locator"

+    debt_advice_locator_f2f:
+      en:
+        path: "en/tools/debt-advice-locator/f2f"
+      cy:
+        path: "cy/tools/canfyddwr-cyngor-ar-ddyledion/f2f"
+      title: "Debt advice locator - face to face"
+
     car_cost_tool:
       en:
         path: "en/tools/car-costs-calculator"


fix qti question bank selection

fix qti question bank selection

test plan:
* import a qti file into a course and select a question
 bank to import
* should import into the correct bank

closes #CNVS-1965

Change-Id: I4f4647cedf28b931225986b757688c8794dfa1d4
Reviewed-on: https://gerrit.instructure.com/37321
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
Product-Review: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
QA-Review: Clare Strong <40d6bb3ed7fef516c73274131d5a837c16de74fd@instructure.com>

--- app/coffeescripts/bundles/content_migration.coffee
+++ app/coffeescripts/bundles/content_migration.coffee
@@ -200,7 +200,9 @@
                                    fileSizeLimit: ENV.UPLOAD_LIMIT

             overwriteAssessmentContent: new OverwriteAssessmentContentView(model: ConverterViewControl.getModel())
-            questionBank:        new QuestionBankView(questionBanks: ENV.QUESTION_BANKS)
+            questionBank:        new QuestionBankView(questionBanks: ENV.QUESTION_BANKS, model: ConverterViewControl.getModel())
+
+

   registerExternalTool = (et) ->


remove date transformation from registration

closes CNVS-19332
refs CNVS-15543

I can't find any date fields related to the self registration process,
so I'm declaring this code dead and removing rather than
accessibilifying it.

TEST PLAN:
 1) tests should pass
 2) self-registration should not break

Change-Id: Ic9b49ddec4a581bad529698b9f202560eeaa68ab
Reviewed-on: https://gerrit.instructure.com/56676
Tested-by: Jenkins
Reviewed-by: Cody Cutrer <c4fe2b1d90ef8f2548c8aeabfa633434316f0305@instructure.com>
QA-Review: Jeremy Putnam <b030d6d6f199f844ec424882be473c2ab9adc93b@instructure.com>
Product-Review: Ethan Vizitei <73eeb0b2f65d05a906adf3b21ee1f9f5a2aa3c1c@instructure.com>

--- app/coffeescripts/registration/signupDialog.coffee
+++ app/coffeescripts/registration/signupDialog.coffee
@@ -42,8 +42,6 @@
       path: path
     )
     $node.html html
-    $node.find('.date-field').datetime_field()
-
     $node.find('.signup_link').click preventDefault ->
       $node.dialog('close')
       signupDialog($(this).data('template'), $(this).prop('title'))


engine_selector

--- src/engine_save_state.coffee
+++ src/engine_save_state.coffee
@@ -47,7 +47,7 @@

   @name loadState
-  @methodOf Engine.SaveState#
+  @methodOf Engine#
   @param [newState] The game state to load.
   ###
   loadState: (newState) ->
@@ -73,7 +73,7 @@

   @name reload
-  @methodOf Engine.SaveState#
+  @methodOf Engine#
   ###
   reload: ->
     oldObjects = I.objects


Remove unused property

Remove unused property

--- assets/javascripts/views/content/entry_page.coffee
+++ assets/javascripts/views/content/entry_page.coffee
@@ -1,6 +1,5 @@
 class app.views.EntryPage extends app.View
   @className: '_page'
-  @loadingClass: '_page-loading'

   @events:
     click: 'onClick'


Update positions when needed

Update positions when needed

--- client/landing/app/CommonViews/remotesmodal.coffee
+++ client/landing/app/CommonViews/remotesmodal.coffee
@@ -45,6 +45,7 @@
                 callback      : (state)=>
                   if state then @savePasswordWarning.show()
                   else @savePasswordWarning.hide()
+                  @setPositions()
             buttons           :
               "Create & Mount":
                 style         : "modal-clean-green"
@@ -117,10 +118,12 @@
     @modalTabs.panes[0].on "KDTabPaneInactive", =>
       @hideMessages()
       @savePasswordWarning.hide()
+      @setPositions()

     @modalTabs.panes[0].on "KDTabPaneActive", =>
       @hideMessages()
       @savePasswordWarning.show() if newRemoteForm.inputs.storepass.getValue()
+      @setPositions()

     @statusText1 = new KDView
       cssClass  : "status-hint fl"


Tests: Collaboration: Enabled endSessionFromStatusBar and endSessionFromChat tests.

--- client/test/lib/collaboration/collaboration.coffee
+++ client/test/lib/collaboration/collaboration.coffee
@@ -14,8 +14,6 @@

   endSessionFromStatusBar: (browser) ->

-    return browser.end()
-
     collaborationHelpers.startSession(browser)
     collaborationHelpers.endSessionFromStatusBar(browser)
     browser.end()
@@ -23,8 +21,6 @@

   endSessionFromChat: (browser) ->

-    return browser.end()
-
     collaborationHelpers.startSession(browser)
     collaborationHelpers.endSessionFromChat(browser)
     browser.end()


call function on myself instead of redirecting function which is removed

--- core/app/backbone/views/auto_completes_view.coffee
+++ core/app/backbone/views/auto_completes_view.coffee
@@ -21,7 +21,7 @@
     return key

   setActiveAutoComplete:  (key)->
-    this.options.mainView.deActivateCurrent()
+    @deActivateCurrent()
     key = this.fixKeyModulo(key)

     @list[key].trigger('activate');


Removed no longer needed helper

Removed no longer needed helper

--- core/app/backbone/views/facts/top_fact_view.coffee
+++ core/app/backbone/views/facts/top_fact_view.coffee
@@ -6,9 +6,6 @@
   regions:
     factVoteTableRegion: '.js-fact-vote-table-region'

-  templateHelpers: =>
-    showDelete: @model.can_destroy()
-
   onRender: ->
     if Factlink.Global.can_haz.opinions_of_users_and_comments
       @factVoteTableRegion.show new ReactView


Add img in kdock panel

Add img in kdock panel

--- views/components/main/parts/kdock-panel.cjsx
+++ views/components/main/parts/kdock-panel.cjsx
@@ -1,6 +1,9 @@
 {ROOT, layout, _, $, $$, React, ReactBootstrap} = window
 {resolveTime, success, warn} = window
 {Panel, Table, OverlayTrigger, Tooltip} = ReactBootstrap
+
+getMaterialImage = (idx) ->
+  return "#{ROOT}/assets/img/material/0#{idx}.png"

 KdockPanel = React.createClass
   getInitialState: ->
@@ -142,14 +145,24 @@

               <OverlayTrigger placement='left' overlay={
                   <Tooltip>
-                    油 {@state.docks[i].material[0]} 弹 {@state.docks[i].material[1]}

-                    钢 {@state.docks[i].material[2]} 铝 {@state.docks[i].material[3]}

-                    资材 {@state.docks[i].material[4]}
+                     {@state.docks[i].material[0]}  {@state.docks[i].material[2]}

+                     {@state.docks[i].material[1]}  {@state.docks[i].material[3]}

+                     {@state.docks[i].material[4]}
                   </Tooltip>
                 }>
-                {@state.docks[i].name}
+                {
+                  if @state.docks[i].material[0] >= 1500 && @state.docks[i].material[1] >= 1500 && @state.docks[i].material[2] >= 2000 || @state.docks[i].material[3] >= 1000
+                    {@state.docks[i].name}
+                  else
+                    {@state.docks[i].name}
+                }
               </OverlayTrigger>
-              {resolveTime @state.docks[i].countdown}
+              {
+                if @state.docks[i].material[0] >= 1500 && @state.docks[i].material[1] >= 1500 && @state.docks[i].material[2] >= 2000 || @state.docks[i].material[3] >= 1000
+                  {resolveTime @state.docks[i].countdown}
+                else
+                  {resolveTime @state.docks[i].countdown}
+              }

         }


SocialWorker: JLocation: replace sinkrow with async

--- workers/social/lib/social/models/location/index.coffee
+++ workers/social/lib/social/models/location/index.coffee
@@ -1,5 +1,6 @@
+async       = require 'async'
 KodingError = require '../../error'
-{ Model, secure, daisy, signature } = require 'bongo'
+{ Model, secure, signature } = require 'bongo'

 module.exports = class JLocation extends Model

@@ -59,12 +60,12 @@
     collection.distinct 'countryCode', {}, (err, countryCodes) =>
       return callback err  if err

-      countries = countryCodes.map (countryCode) => =>
+      countries = countryCodes.map (countryCode) => (next) =>

         collection.distinct 'stateCode', { countryCode }, (err, stateCodes) =>
           return callback err  if err

-          states = stateCodes.filter(Boolean).map (stateCode) => =>
+          states = stateCodes.filter(Boolean).map (stateCode) => (nextState) =>

             @one { stateCode, countryCode }, (err, location) ->

@@ -73,15 +74,11 @@
                 stateCode   : location.stateCode
                 state       : location.state

-              state.save (err) -> states.next err
+              state.save nextState

-          states.push -> countries.next()
+          async.seris states, -> next()

-          daisy states
-
-      countries.push -> callback null
-
-      daisy countries
+      async.series countries, -> callback null

   @importAll = secure (client, callback) ->


Social: send right ipaddress to recurly

Social: send right ipaddress to recurly

--- workers/social/lib/social/models/payment/method.coffee
+++ workers/social/lib/social/models/payment/method.coffee
@@ -121,7 +121,7 @@
         JSession.one clientId: client.sessionToken, (err, session) =>
           return callback err  if err

-          ipAddress = session.clientIPAddress or '(Unknown IP address)'
+          ipAddress = session.clientIP or '(Unknown IP address)'

           firstName ?= formData.cardFirstName
           lastName ?= formData.cardLastName


Allow anonymous requests from the API lib (fix #38)

--- www/js/lib/api.coffee
+++ www/js/lib/api.coffee
@@ -20,10 +20,15 @@
   # including the required OAuth and version arguments.
   # All requests are sent over HTTPS.
   request = (url, args = {}) ->
-    data = {
-      oauth_token: window.GLOBALS.TOKEN
-      v: window.GLOBALS.API_DATE
-    }
+    if window.GLOBALS.TOKEN
+      data = {
+        oauth_token: window.GLOBALS.TOKEN
+        v: window.GLOBALS.API_DATE
+      }
+    else
+      data = {
+        v: window.GLOBALS.API_DATE
+      }

     _.extend data, args.data if args.data


Use File#slice to stream file uploads from disk.

--- web/lib/coffeescripts/transfer.coffee
+++ web/lib/coffeescripts/transfer.coffee
@@ -5,7 +5,7 @@
     @to       = options.to
     @progress = options.progress
     @complete = options.complete
-    @chunks   = new Chunks(@file)
+    @chunks   = new Chunks @file
     @opened   = false
     @closed   = false
     @sid      = @session.uniqueId()
@@ -29,12 +29,10 @@
     """)
     $('file', node).attr 'name', @file.name

-    callback = (result) =>
+    @session.sendIQ node.get(0), (result) =>
       methods = $('si feature x field[var="stream-method"] value', result)
       ok = (true for m in methods when $(m).text() == 'http://jabber.org/protocol/ibb').length > 0
       this.open() if ok
-
-    @session.sendIQ node.get(0), callback

   open: ->
     node = $("""
@@ -42,30 +40,30 @@
         <open xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" block-size="4096"/>
       </iq>
     """)
-    callback = (result) =>
+    @session.sendIQ node.get(0), (result) =>
       if this.ok result
         @opened = true
-        @chunks.start => this.sendChunk()
-    @session.sendIQ node.get(0), callback
+        this.sendChunk()

   sendChunk: ->
     return if @closed
-    unless chunk = @chunks.chunk()
-      this.close()
-      return
+    @chunks.chunk (chunk) =>
+      unless chunk
+        this.close()
+        return

-    node = $("""
-      <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
-        <data xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" seq="#{@seq++}">#{chunk}</data>
-      </iq>
-    """)
-    @seq = 0 if @seq > 65535
-    callback = (result) =>
-      return unless this.ok result
-      pct = Math.ceil ++@sent / @chunks.total * 100
-      this.progress pct
-      this.sendChunk()
-    @session.sendIQ node.get(0), callback
+      node = $("""
+        <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
+          <data xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" seq="#{@seq++}">#{chunk}</data>
+        </iq>
+      """)
+      @seq = 0 if @seq > 65535
+
+      @session.sendIQ node.get(0), (result) =>
+        return unless this.ok result
+        pct = Math.ceil ++@sent / @chunks.total * 100
+        this.progress pct
+        this.sendChunk()

   close: ->
     return if @closed
@@ -87,17 +85,22 @@
   ok: (result) -> $(result).attr('type') == 'result'

   class Chunks
+    CHUNK_SIZE = 3 / 4 * 4096
+
     constructor: (@file) ->
-      @chunks = []
-      @total  = 0
+      @total = Math.ceil @file.size / CHUNK_SIZE
+      @slice = @file.slice || @file.webkitSlice || @file.mozSlice
+      @pos   = 0

-    chunk: -> @chunks.shift()
-
-    start: (callback) ->
-      reader = new FileReader()
-      reader.onload = (event) =>
-        data = btoa event.target.result
-        @chunks = (chunk for chunk in data.split /(.{1,4096})/ when chunk)
-        @total = @chunks.length
-        callback()
-      reader.readAsBinaryString @file
+    chunk: (callback) ->
+      start = @pos
+      end   = @pos + CHUNK_SIZE
+      @pos  = end
+      if start > @file.size
+        callback null
+      else
+        chunk = @slice.call @file, start, end
+        reader = new FileReader()
+        reader.onload = (event) ->
+          callback btoa event.target.result
+        reader.readAsBinaryString chunk


Update news.coffee

Update news.coffee

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

 export default allNews = () ->
     return news([
-        newsItem("Занятие 24 октября, скорее всего, будет перенесено", String.raw"""
-            Занятие 24 октября в ВШЭ, скорее всего, будет перенесено, ориентировочно начало в 11.00-12.00. Точная информация будет в пятницу-субботу, следите за объявлениями.
+        newsItem("Занятие 24 октября пройдет с 11.00 до 14.00", String.raw"""
+            Занятие 24 октября в ВШЭ пройдет с 11.00 до 14.00.
         """),
         newsItem("Командная олимпиада", String.raw"""
             Добавлена информация про командную олимпиаду


Make authentication take at least one second, to prevent revealing whether a username exists based on timing

--- server/packages/user/login.coffee
+++ server/packages/user/login.coffee
@@ -1,28 +1,62 @@
+
+Promise = require 'bluebird'

 errors = require 'errors'

 {threshold} = require 'limits'

 exports.$endpoint = ->
-
+
 	limiter:
 		message: "You are logging in too much."
 		threshold: threshold(3).every(30).seconds()

 	receiver: (req, fn) ->

-		switch req.body.method
+		{passport} = req
+
+		loginPromise = switch req.body.method

 			when 'local'

-				(req.passport.authenticate 'local', (error, user, info) ->
-					return fn error if error?
-					return fn errors.instantiate 'login' unless user
+				deferred = Promise.defer()
+
+				passport.authenticate('local', deferred.callback)(
+					req, res = {}, fn
+				)
+
+				Promise.settle([

-					req.login user, (error) ->
-						return fn error if error?
-						user.redactFor(user).nodeify fn
-
-				) req, res = {}
+					deferred.promise.bind({}).spread((@user, info) ->
+						throw errors.instantiate 'login' unless @user
+
+						(Promise.promisify req.login, req) @user
+
+					).then(->
+
+						@user.redactFor @user
+					)
+
+# If no user is found, the rejection will happen a lot sooner than if one is;
+# password hashing must be done in the latter case. We'll create an artificial
+# floor of 1 second to make it harder for an attacker to tell if a valid
+# username was used.
+
+					new Promise (resolve, reject) -> setTimeout resolve, 1000
+
+				]).then ([userPromiseInspector]) ->
+
+					if userPromiseInspector.isFulfilled()
+						userPromiseInspector.value()
+					else
+						throw userPromiseInspector.error()
+
+# TODO: Using nodeify here crashes the app. It may be a bluebird bug.
+
+#		loginPromise.nodeify fn
+		loginPromise.then(
+			(result) -> fn null, result
+			(error) -> fn error
+		)

 exports.$errorType = (require 'client/modules/packages/user/login').$errorType


Adding cohorts should work for legacy courses.

Legacy courses are not submitted, but we still need to enable adding them to cohorts.

--- app/assets/javascripts/components/overview/details.cjsx
+++ app/assets/javascripts/components/overview/details.cjsx
@@ -140,7 +140,7 @@
         </fieldset>

           Cohorts: {cohorts}
-          <CohortButton {...@props} show={@props.editable && @props.current_user.admin && @props.course.submitted} />
+          <CohortButton {...@props} show={@props.editable && @props.current_user.admin && (@props.course.submitted || @props.course.legacy) } />

           Tags: {tags}


fixing javascript reference to message field instead of body field

--- app/assets/javascripts/github_issues/application.coffee
+++ app/assets/javascripts/github_issues/application.coffee
@@ -8,7 +8,7 @@

   clearForm: ->
     $('#github_issues_issue_title').val('')
-    $('#github_issues_issue_message').val('')
+    $('#github_issues_issue_body').val('')
     $('#new_github_issue_form > .errorExplanation').remove()

   submitForm: ->


Закомментированные кнопки в конфигурации тулбара сделаны опциональными

--- app/assets/javascripts/sitemplate_wysihat_cfg.js.coffee
+++ app/assets/javascripts/sitemplate_wysihat_cfg.js.coffee
@@ -334,40 +334,6 @@
         editor.handler.saveState()
         editor.handler.cfg.options.insertImageHandler(editor)
     }
-    ###
-    inline_left: {
-      name: 'inline_left',
-      label: '<i class="icon-pull-left"/>',
-      init: (button) ->
-        button.
-          attr('rel', 'tooltip').
-          attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.inline.left).
-          tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
-          addClass('btn btn-small')
-        group = button.prevAll('.btn-group:first')
-        button.appendTo group
-      handler: (editor) ->
-        window.SITEMPLATE.lib.wysihat.helpers.toggle_class.handler(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 0)
-      query: (editor) ->
-        window.SITEMPLATE.lib.wysihat.helpers.toggle_class.query(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 0)
-    }
-    inline_right: {
-      name: 'inline_right',
-      label: '<i class="icon-pull-right"/>',
-      init: (button) ->
-        button.
-          attr('rel', 'tooltip').
-          attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.inline.right).
-          tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
-          addClass('btn btn-small')
-        group = button.prevAll('.btn-group:first')
-        button.appendTo group
-      handler: (editor) ->
-        window.SITEMPLATE.lib.wysihat.helpers.toggle_class.handler(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 1)
-      query: (editor) ->
-        window.SITEMPLATE.lib.wysihat.helpers.toggle_class.query(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 1)
-    }
-    ###
     link: {
       name: 'link',
       label: '<i class="icon-link"/>',
@@ -383,37 +349,6 @@
         editor.handler.saveState()
         editor.handler.cfg.options.linkHandler(editor)
     }
-    ###
-    html: {
-      name: 'html',
-      label: '<i class="icon-html"/>',
-      init: (button) ->
-        button.
-          attr('rel', 'tooltip').
-          attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.html).
-          tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
-          addClass('btn btn-small')
-        group = $('<div/>').addClass('btn-group').insertBefore(button)
-        button.appendTo group
-      handler: (editor) ->
-        editor.handler.saveState()
-        editor.handler.cfg.options.insertHTMLHandler(editor)
-    }
-    ###
-    # save: {
-    #   name: 'save',
-    #   label: '<i class="icon-ok icon-white"/>',
-    #   init: (button) ->
-    #     button.
-    #       attr('rel', 'tooltip').
-    #       attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.save).
-    #       tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
-    #       addClass('btn btn-success')
-    #     group = $('<div/>').addClass('btn-group').insertBefore(button)
-    #     button.appendTo group
-    #   handler: (editor) ->
-    #     editor.handler.cfg.options.saveHandler(editor)
-    # }
   }
   options:
     insertImageHandler: (editor) ->
@@ -459,4 +394,67 @@
       $('.wym_paste_container').remove()
       html

-
+    buttons:
+      inline_left: {
+        name: 'inline_left',
+        label: '<i class="icon-pull-left"/>',
+        init: (button) ->
+          button.
+            attr('rel', 'tooltip').
+            attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.inline.left).
+            tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
+            addClass('btn btn-small')
+          group = button.prevAll('.btn-group:first')
+          button.appendTo group
+        handler: (editor) ->
+          window.SITEMPLATE.lib.wysihat.helpers.toggle_class.handler(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 0)
+        query: (editor) ->
+          window.SITEMPLATE.lib.wysihat.helpers.toggle_class.query(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 0)
+      }
+      inline_right: {
+        name: 'inline_right',
+        label: '<i class="icon-pull-right"/>',
+        init: (button) ->
+          button.
+            attr('rel', 'tooltip').
+            attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.inline.right).
+            tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
+            addClass('btn btn-small')
+          group = button.prevAll('.btn-group:first')
+          button.appendTo group
+        handler: (editor) ->
+          window.SITEMPLATE.lib.wysihat.helpers.toggle_class.handler(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 1)
+        query: (editor) ->
+          window.SITEMPLATE.lib.wysihat.helpers.toggle_class.query(editor, window.SITEMPLATE.lib.wysihat.cfg.INLINE_CLASSES, 1)
+      }
+      html: {
+        name: 'html',
+        label: '<i class="icon-html"/>',
+        init: (button) ->
+          button.
+            attr('rel', 'tooltip').
+            attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.html).
+            tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
+            addClass('btn btn-small')
+          group = $('<div/>').addClass('btn-group').insertBefore(button)
+          button.appendTo group
+        handler: (editor) ->
+          editor.handler.saveState()
+          editor.handler.cfg.options.insertHTMLHandler(editor)
+      }
+      save: {
+        name: 'save',
+        label: '<i class="icon-ok icon-white"/>',
+        init: (button) ->
+          button.
+            attr('rel', 'tooltip').
+            attr('data-original-title', window.SITEMPLATE.lib.wysihat.local.getLocale().toolbar.save).
+            tooltip(window.SITEMPLATE.lib.wysihat.cfg.TOOLTIP_OPTIONS).
+            addClass('btn btn-success')
+          group = $('<div/>').addClass('btn-group').insertBefore(button)
+          button.appendTo group
+        handler: (editor) ->
+          editor.handler.cfg.options.saveHandler(editor)
+      }
+
+


Fix Coffee compile error - comment // vs #

--- picoCTF-web/web/coffee/classroom.coffee
+++ picoCTF-web/web/coffee/classroom.coffee
@@ -24,7 +24,7 @@
       apiNotify resp
     else
       # problems = _.filter resp.data.problems, (problem) -> !problem.disabled
-      problems = resp.data; // non-admin API only returns non-disabled problems as top level data array
+      problems = resp.data; # non-admin API only returns non-disabled problems as top level data array
       data = [["Username", "First Name", "Last Name"].concat(_.map(problems, (problem) -> problem.name), ["Total"])]
       _.each teams, ((team) ->
         member = team.members[0]


Update template2.coffee

Update template2.coffee

--- packages/meteor-template2/src/template2.coffee
+++ packages/meteor-template2/src/template2.coffee
@@ -71,6 +71,7 @@
 # Init actions
 Blaze.TemplateInstance.prototype.actions = (actions) ->
   # not implemented yet
+  return @

 Blaze.TemplateInstance.prototype.helpers = (helpers) ->
   @view.template.helpers bindAllToTemplateInstance(helpers)


Sprites: gave some padding to avoid collision on retina images

--- node_modules_koding/koding-sprites/lib/koding-sprites/sprites.coffee
+++ node_modules_koding/koding-sprites/lib/koding-sprites/sprites.coffee
@@ -23,7 +23,7 @@
       generateSprites
         src           : ["#{ path }/*.png"]
         spritePath    : joinPath options.destPath, "#{ spriteName }.sprite.png"
-        layoutOptions : { padding: 1 }
+        layoutOptions : { padding: 10 }
         stylesheet    : createStylusHandler this, isRetina
     .then -> createStylusHelper this, options
     .nodeify callback


typo introduced in main.coffee some time ago

--- bokehjs/src/coffee/main.coffee
+++ bokehjs/src/coffee/main.coffee
@@ -10,7 +10,7 @@

   # common
   Bokeh.Collections       = require("common/base").Collections
-  Bokeh.Config            = require("common/base").Collections
+  Bokeh.Config            = require("common/base").Config
   Bokeh.GMapPlot          = require("common/gmap_plot")
   Bokeh.GridPlot          = require("common/grid_plot")
   Bokeh.HasParent         = require("common/has_parent")


Add a fixture helper for browser specs

Add a fixture helper for browser specs

--- specs/support/all/spec_helper.coffee
+++ specs/support/all/spec_helper.coffee
@@ -47,3 +47,15 @@

       it "should be #{value}", ->
         expect(this[source][property]).toBeClose(value)
+
+if document?
+  global.fixture = (fixtureHTML) ->
+    beforeEach ->
+      @fixture = document.createElement('div')
+      @fixture.id = 'fixture'
+      @fixture.innerHTML = fixtureHTML
+      document.body.appendChild(@fixture)
+
+    afterEach ->
+      document.body.removeChild(@fixture)
+      @fixture = null


Adds UI Prototyping Controller and associated action files

Route to controller only active in development
includes misc mathjax examples I used for equation builder

--- javascripts/widgets/ui_elements.coffee
+++ javascripts/widgets/ui_elements.coffee
@@ -1,9 +1,9 @@
 #= require almond_wrapper
 #= require lib
 #= require jquery
+#= require widgets/mathml

-
-ttm.define 'widgets/ui_elements', ['lib/class_mixer'], (class_mixer)->
+ttm.define 'widgets/ui_elements', ['lib/class_mixer', 'widgets/mathml'], (class_mixer, mathml_renderer)->
   class Button
     initialize: (@opts={})->
     render: (opts={})->
@@ -18,13 +18,42 @@
     initialize: (@opts={})->
     render: (opts={})->
       opts = _.extend({},@opts, opts)
-      figure = $("
#{opts.default || '0'}
")
-      opts.element.append figure
+      @figure = $("
#{opts.default || '0'}
")
+      opts.element.append @figure
+      @figure
+
+    update: (value)->
+      @figure.html(value)
   class_mixer(MathDisplay)
+
+  class MathMLDisplay
+    initialize: (@opts={})->
+      @mathml_renderer = @opts.mathml_renderer || mathml_renderer
+    render: (opts={})->
+      opts = _.extend({}, @opts, opts)
+      @figure = $("""
+

+          <math xmlns=\"http://www.w3.org/1998/Math/MathML\">
+                  <mrow><mn>0</mn></mrow>
+          </math>
+
""")
+      @math_element = @figure.find('math')
+      opts.element.append @figure
+      @figure
+
+    update: (mathml)->
+      #@math_element.html(mathml)
+
+      @mathml_renderer.render(@math_element[0])
+
+
+  class_mixer(MathMLDisplay)
+

   exports =
     button_builder: Button
     math_display_builder: MathDisplay
+    mathml_display_builder: MathMLDisplay

   return exports


Reversion and update -- fixes broken tests, bug

--- javascripts/widgets/ui_elements.coffee
+++ javascripts/widgets/ui_elements.coffee
@@ -1,8 +1,9 @@
 #= require almond_wrapper
 #= require lib
 #= require jquery
+#= require widgets/mathml

-ttm.define 'widgets/ui_elements', ['lib/class_mixer'], (class_mixer)->
+ttm.define 'widgets/ui_elements', ['lib/class_mixer', 'widgets/mathml'], (class_mixer, mathml_renderer)->
   class Button
     initialize: (@opts={})->
     render: (opts={})->
@@ -38,9 +39,6 @@
       opts.element.append @figure
       @figure

-    default: ->
-      @wrappedMathTag("")
-
     wrappedMathTag: (content)->
       """
       <math xmlns=\"http://www.w3.org/1998/Math/MathML\">
@@ -49,10 +47,7 @@
       """

     update: (mathml)->
-      mathml_in_tag = @wrappedMathTag(mathml)
-      elem = MathJax.Hub.getAllJax(@figure[0])[0]
-      if elem
-        MathJax.Hub.Queue(["Text", elem, mathml_in_tag])
+      @mathml_renderer.render(@figure, @wrappedMathTag(mathml))

   class_mixer(MathMLDisplay)


keymanager

keymanager

--- content/keymanager.coffee
+++ content/keymanager.coffee
@@ -1,7 +1,7 @@
 debug = require('./debug.coffee')

 class KeyManager
-  init: Zotero.Promise.coroutine ->
+  init: Zotero.Promise.coroutine(->
     debug('KeyManager.init()')
     @query = {
       field: {}
@@ -24,7 +24,7 @@
       where attachment.linkMode = #{Zotero.Attachments.LINK_MODE_LINKED_URL}
     """

-    nokey = """
+    items = """
       with citekey as (#{@query.citekeys})
       select item.itemID
       from items item
@@ -32,11 +32,41 @@
       where citekey.parentItemID is null
     """

-    nokeys = yield Zotero.DB.queryAsync(nokey)
-    for item in (nokeys || [])
+    items = yield Zotero.DB.queryAsync(items)
+    for item in (items || [])
       Zotero.debug("No citation key: #{item.itemID}")
+      ## TODO: generate new key here
+
+    ## TODO: Possibly only do these scans when extensions.zotero.translators.better-bibtex.scanCitekeys is set, then reset it
+
+    ## TODO: find items with more than one citekey and delete all but one
+
+    ## TODO: scan for 'bibtex:...' keys and move them to attachments
+
+    @observerID = Zotero.Notifier.registerObserver(@, ['item'], 'BetterBibTeX.KeyManager', 100)

     debug('KeyManager.init() done')
     return
+  )

+  notify: Zotero.Promise.coroutine((action, type, ids, extraData) ->
+    debug('KeyManager.notify', {action, type, ids, extraData})
+
+    ## test for field updates https://groups.google.com/d/msg/zotero-dev/naAxXIbpDhU/7rM-5IKGBQAJ
+    ids = (id for id in ids when !extraData[id].BetterBibTeX)
+    debug('KeyManager.notify', {ids})
+
+    for item in yield Zotero.Items.getAsync(ids)
+      continue if item.isAttachment() || item.isNote()
+      # continue if item.getField('extra')
+      debug('KeyManager.notify: change extra', item.id)
+
+      ## generate citation key if not pinned, store in attachment not extra
+      item.setField('extra', 'updated')
+      yield item.saveTx({
+        notifierData: { BetterBibTeX: true }
+      })
+
+    return
+  )
 module.exports = new KeyManager()


Activity: PrivateMessage autocomplete timeout reduced to 10 secs

--- client/Social/Activity/views/privatemessage/form.coffee
+++ client/Social/Activity/views/privatemessage/form.coffee
@@ -61,7 +61,7 @@
       # the data source callback is not error-first style,
       # so just pass the callback to .then():
       .then callback
-      .timeout 15e3
+      .timeout 1e4
       .catch Promise.TimeoutError, callback.bind this, []


account/shortcuts: add more constants :rooster:

--- client/account/lib/views/accounteditshortcutsrow.coffee
+++ client/account/lib/views/accounteditshortcutsrow.coffee
@@ -3,21 +3,6 @@
 facade = require('./accounteditshortcutsfacade')
 EventType = require './accounteditshortcutseventtype'
 globals = require 'globals'
-
-# Class name to set for currently recording item.
-ENABLED_CLASS_NAME = 'enabled'
-
-# Class name to set for currently recording item.
-ACTIVE_CLASS_NAME = 'active'
-
-# Class name to set for duplicate/colliding items.
-DUP_CLASS_NAME = 'collides'
-
-# The maximum description string length.
-DESCRIPTION_TRUNC_LEN = 30
-
-# The separator pattern to truncate to.
-DESCRIPTION_TRUNC_SEP = ' '

 # On Mac we display corresponding unicode chars for the following keys.
 # See: http://macbiblioblog.blogspot.nl/2005/05/special-key-symbols.html
@@ -46,7 +31,7 @@
 # Determines the text conversion method to use when displaying bindings.
 convertCase = _.capitalize

-# Generates a compiled template function.
+# Generates a compiled template function for rendering bindings.
 renderBinding =
   _.template '<% _.forEach(keys, function (key) { %><%= key %><% }) %>'

@@ -65,6 +50,30 @@
 module.exports =

 class AccountEditShortcutsRow extends kd.View
+
+  # Class name for columns.
+  COL_CLASS_NAME = 'col'
+
+  # Class name to set for currently recording item.
+  ENABLED_CLASS_NAME = 'enabled'
+
+  # Class name to set for currently recording item.
+  ACTIVE_CLASS_NAME = 'active'
+
+  # Class name to set for duplicate/colliding items.
+  DUP_CLASS_NAME = 'collides'
+
+  # The maximum description string length.
+  DESCRIPTION_TRUNC_LEN = 30
+
+  # The separator pattern to truncate to.
+  DESCRIPTION_TRUNC_SEP = ' '
+
+  CLICK = 'click'
+
+  CLASS_NAME = 'row'
+
+  TOGGLE_PARTIAL = '
'

   constructor: (options, data) ->

@@ -77,7 +86,7 @@
     @_dup = options.dup
     delete options.dup

-    super _.extend cssClass: 'row', options
+    super _.extend cssClass: CLASS_NAME, options

     if @_dup then @setClass DUP_CLASS_NAME

@@ -85,23 +94,22 @@
   viewAppended: ->

     toggle = new kd.View
-      cssClass : 'col'
-      tagName  : 'div'
-      partial: '
'
+      cssClass : COL_CLASS_NAME
+      partial  : TOGGLE_PARTIAL

     if @model.enabled then toggle.setClass ENABLED_CLASS_NAME

     descriptionText = _.escape @model.description

     description = new kd.View
-      cssClass : 'col'
+      cssClass : COL_CLASS_NAME
       partial  : _.trunc descriptionText, separator: DESCRIPTION_TRUNC_SEP, length: DESCRIPTION_TRUNC_LEN

     if descriptionText.length > DESCRIPTION_TRUNC_LEN
       description.domElement.attr 'title', descriptionText

     binding = new kd.View
-      cssClass : 'col'
+      cssClass : COL_CLASS_NAME
       partial  : presentBinding @_binding

     # Handles checkbox clicks.
@@ -171,16 +179,16 @@
     destroyHandler = =>
       @off EventType.Facade.CHANGED, changeHandler
       @off EventType.Facade.DUP, dupHandler
-      @off 'click', clickHandler
-      toggle.off  'click', toggleClickHandler
+      @off CLICK, clickHandler
+      toggle.off CLICK, toggleClickHandler
       _.each EventType.Item, (type) =>
         @off type, @_handlers[type]
         @_handlers[type] = null
       @_handlers = null

     # Add handlers for dom events.
-    @on 'click', clickHandler
-    toggle.on 'click', toggleClickHandler
+    @on CLICK, clickHandler
+    toggle.on CLICK, toggleClickHandler

     # Add handlers for facade events.
     @on EventType.Facade.CHANGED, changeHandler


CredentialListItem: verify credential

CredentialListItem: verify credential

--- client/admin/lib/views/stacks/credentiallistitem.coffee
+++ client/admin/lib/views/stacks/credentiallistitem.coffee
@@ -33,9 +33,11 @@
     @useButton.hide()  unless verified

     @verifyButton = new kd.ButtonView
-      callback : delegate.lazyBound 'verify', this
       cssClass : 'solid compact outline'
       title    : 'VERIFY'
+      callback : @bound 'verifyCredential'
+
+    @verifyButton.hide()  if verified

     @messageView = new kd.CustomHTMLView
       cssClass : 'message'
@@ -63,6 +65,28 @@
     @messageView.setTooltip title: reason  if reason

+  verifyCredential: ->
+
+    credential = @getData()
+
+    if credential.verified
+      @setVerified yes
+      return
+
+    @verifyButton.disable()
+    @messageView.unsetClass 'red green'
+    @messageView.updatePartial 'Verifying credential...'
+
+    @getDelegate()
+      .verify this
+      .then (response) =>
+        @setVerified response?[credential.publicKey]
+
+      .catch (err) =>
+        @setVerified no, err.message
+
+      .finally @verifyButton.bound 'enable'
+

   pistachio: ->
     """


[client][app][main][maincontroller] added validation into text box

--- client/app/MainApp/maincontroller/maincontroller.coffee
+++ client/app/MainApp/maincontroller/maincontroller.coffee
@@ -222,9 +222,11 @@
                   rules              :
                     required         : yes
                     minLength        : 2
+                    regExp           : /\d[A-Za-z]+/i
                   messages           :
                     required         : "Please enter a time period"
                     minLength        : "You must enter one pair"
+                    regExp           : "You must enter at least a number and a character e.g : 1y 1h"
                 iconOptions          :
                   tooltip            :
                     placement        : "right"


Reduce scroll delay by half

Reduce scroll delay by half

--- client/controllers/incidentReports/incidentTable.coffee
+++ client/controllers/incidentReports/incidentTable.coffee
@@ -1,7 +1,7 @@
 UserEvents = require '/imports/collections/userEvents.coffee'
 Incidents = require '/imports/collections/incidentReports.coffee'
 { notify } = require '/imports/ui/notification'
-SCROLL_WAIT_TIME = 500
+SCROLL_WAIT_TIME = 250

 _acceptedQuery = (accepted) ->
   query = {}


[front] [fix] Incorrect identation for continuation

--- lib/front/front.coffee
+++ lib/front/front.coffee
@@ -125,4 +125,4 @@
               # Send the message
               engineIOServer.clients[message[1].sid].send(JSON.stringify(message, true))

-          callback null, server+        callback null, server


Keep user state persistent on the client.

--- services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
+++ services/web/public/coffee/ide/review-panel/controllers/ReviewPanelController.coffee
@@ -594,9 +594,11 @@
 			if userId == ide.$scope.user.id
 				$scope.editor.wantTrackChanges = newValue

-		_setEveryoneTCState = (newValue) ->
+		_setEveryoneTCState = (newValue, isLocal = false) ->
 			$scope.reviewPanel.trackChangesOnForEveryone = newValue
-			$scope.reviewPanel.trackChangesState = {}
+			for userId, userState of $scope.reviewPanel.trackChangesState
+				userState.value = newValue
+				userState.syncState = if isLocal then UserTCSyncState.PENDING else UserTCSyncState.SYNCED
 			$scope.editor.wantTrackChanges = newValue

 		applyClientTrackChangesStateToServer = () ->
@@ -626,8 +628,7 @@
 				_setUserTCState($scope.project.owner._id, state[$scope.project.owner._id] ? false)

 		$scope.toggleTrackChangesForEveryone = (onForEveryone) ->
-			console.log onForEveryone
-			_setEveryoneTCState onForEveryone
+			_setEveryoneTCState onForEveryone, true
 			applyClientTrackChangesStateToServer()

 		window.toggleTrackChangesForUser = # DEBUG LINE


Simplify environment change token parsing slightly.

--- lib/token/env-change-token-parser.coffee
+++ lib/token/env-change-token-parser.coffee
@@ -1,6 +1,4 @@
 # s2.2.7.8
-
-EventEmitter = require('events').EventEmitter

 types =
   1:
@@ -34,7 +32,7 @@

   if type
     switch type.name
-      when 'DATABASE', 'LANGUAGE', 'CHARSET', 'PACKET_SIZE'
+      when 'DATABASE', 'LANGUAGE', 'CHARSET'
         newValue = buffer.readBVarchar()
         oldValue = buffer.readBVarchar()
       when 'SQL_COLLATION'
@@ -43,12 +41,11 @@

         valueLength = buffer.readUInt8()
         oldValue = buffer.readBuffer(valueLength)
+      when 'PACKET_SIZE'
+        newValue = parseInt(buffer.readBVarchar())
+        oldValue = parseInt(buffer.readBVarchar())
       else
         throw new Error("Unsupported ENVCHANGE type #{typeNumber} #{type.name} at offset #{buffer.position - 1}")
-
-    if type.name == 'PACKET_SIZE'
-      newValue = parseInt(newValue)
-      oldValue = parseInt(oldValue)
   else
     throw new Error("Unsupported ENVCHANGE type #{typeNumber} at offset #{buffer.position - 1}")


Speed up gradient hack

Speed up gradient hack

--- lib/autoprefixer/hacks/gradient.coffee
+++ lib/autoprefixer/hacks/gradient.coffee
@@ -21,9 +21,12 @@
   @names = ['linear-gradient', 'repeating-linear-gradient',
             'radial-gradient', 'repeating-radial-gradient']

+  @regexps = { }
+  for i in @names
+    @regexps[i] = new RegExp('(^|\\s|,)' + i + '\\(([^)]+)\\)', 'gi')
+
   constructor: (@name, @prefixes) ->
-    name    = utils.escapeRegexp(@name)
-    @regexp = new RegExp('(^|\\s|,)' + name + '\\(([^)]+)\\)', 'gi')
+    @regexp = Gradient.regexps[@name]

   # Change degrees for webkit prefix
   addPrefix: (prefix, string) ->


update position of drag handles when entire mark is dragged

--- app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
+++ app/assets/javascripts/components/mark/tools/text-row-tool/index.cjsx
@@ -90,6 +90,8 @@
   handleDrag: (e, d) ->
     @props.mark.x += d.x / @props.xScale
     @props.mark.y += d.y / @props.yScale
+    @props.mark.yUpper += d.y / @props.yScale
+    @props.mark.yLower += d.y / @props.yScale
     @props.onChange e

   handleUpperResize: (e, d) ->


Update user notes on text change

Update user notes on text change

--- desktop/apps/artsy_primer/personalize/client/views/price_range.coffee
+++ desktop/apps/artsy_primer/personalize/client/views/price_range.coffee
@@ -4,11 +4,19 @@
 template = -> require('../../templates/price_range.jade') arguments...

 module.exports = class PriceRangeView extends StepView
+
+  events:
+    'keyup #anything-else' : 'updateNotes'
+
   formatter: (val, index) ->
     if index is 0
       "#{formatMoney(val, { precision: 0 })}"
     else
       "#{formatMoney(val, { symbol: "", precision: 0 })}"
+
+  updateNotes: ->
+    val = @$('#anything-else').val()
+    @user.set notes: val

   onSetSlider: (_, __, [min, max]) =>
     @user.set price_range_min: min, price_range_max: max


group dashboard: wip image upload

group dashboard: wip image upload

--- client/landing/app/Applications/Groups.kdapplication/Views/generalsettingsview.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/generalsettingsview.coffee
@@ -13,7 +13,10 @@
       isNewGroup = yes
     isPrivateGroup = 'private' is group.privacy

-    _updateGroupHandler =(group, formData)->
+    _updateGroupHandler =(group, formData)=>
+      log formData
+      formData.avatar = @customUrl if @customUrl
+      log formData
       group.modify formData, (err)->
         if err
           new KDNotificationView
@@ -47,10 +50,16 @@
       fields:
         "Avatar"              :
           label             : "Avatar"
-          itemClass         : KDImageUploadSingleView
-          name              : "avatar"
-          limit             : 1
-          preview           : 'thumbs'
+          cssClass        : 'avatar'
+          limit           : 1
+          preview         : "thumbs"
+          extensions      : null
+          fileMaxSize     : 2048
+          totalMaxSize    : 2048
+          fieldName       : "thumbnails"
+          convertToBlob   : yes
+          title           : ""
+          itemClass         : KDImageUploadView
           actions         : {
             big    :
               [
@@ -133,15 +142,20 @@
     @settingsForm = new KDFormViewWithFields formOptions, @getData()

     avatarUploadView = @settingsForm.inputs["Avatar"]
-
     avatarUploadView.on 'FileReadComplete', ({file, progressEvent})->
+      log 'read'
       avatarUploadView.$('.kdfileuploadarea').css
         backgroundImage : "url(#{file.data})"
       avatarUploadView.$('span').addClass 'hidden'

-    avatarUploadView.on 'FileUploadComplete', (files)->
-      for {filename, resource} in files
-        console.log {filename, resource}
+    avatarUploadView.on 'FileUploadComplete', (res)=>
+      log 'upload',res
+      if res.length and res[0].resource
+        @customUrl = res[0].resource
+
+    # avatarUploadView.on 'FileUploadComplete', (files)->
+    #   for {filename, resource} in files
+    #     console.log {filename, resource}


Move control code to backend.

Move control code to backend.

--- client/landing/app/Applications/Groups.kdapplication/Views/paymentsettingsview.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/paymentsettingsview.coffee
@@ -129,9 +129,7 @@

   updateBillingInfo:(group)->
     @getBillingInfo group, (err, data)=>
-      firstTime = no
       if err or not data
-        firstTime = yes
         data = {}

       paymentController = KD.getSingleton "paymentController"
@@ -142,8 +140,6 @@
           else
             @getBillingInfo group
             onSuccess result
-            if firstTime
-              # TODO: Add credit to all users!

   getBillingInfo:(group, callback=->)->
     group.getBillingInfo (err, billing)=>


changed deals.js to append options in right order

--- app/assets/javascripts/deals.js.coffee
+++ app/assets/javascripts/deals.js.coffee
@@ -36,10 +36,9 @@
       $('#deal_offerings_buyers option[value="Company:'+newCompanyId+'"]').remove()

       # add remaining
-      # TODO add in correct order
-      investorsCurrent = investors.find("option")
       investorsOriginal.each ->
-        unless this in investorsCurrent || this.value is "Company:#{newCompanyId}"
+        this.remove
+        unless this.value is "Company:#{newCompanyId}"
           investors.append(this)
       investors.trigger("liszt:updated")


Remove tab_icon code. Not required with font-awesome.

--- app/assets/javascripts/lists.js.coffee
+++ app/assets/javascripts/lists.js.coffee
@@ -74,12 +74,4 @@
         when "opportunities" then "fa-money"
         when "team" then "fa-globe"

-    # When mouseover on li, change asset icons to delete buttons
-    $("#personal_lists li").live "mouseover", ->
-      img_el = $(this).find('.delete_on_hover img')
-      img_el.attr('src', "/assets/delete.png")
-    $("#personal_lists li").live "mouseout", ->
-      img_el = $(this).find('.delete_on_hover img')
-      img_el.attr('src', "/assets/tab_icons/" + img_el.data('controller') + "_active.png")
-
 ) jQuery


First pass at getting wheel working again.

- Renders properly with any sized data (and changing size data)
- Tooltips function now

TODO
- selecting slices
- add in animations to make transitions smoother ?

--- app/components/aster-plot-chart.coffee
+++ app/components/aster-plot-chart.coffee
@@ -14,73 +14,6 @@
       .attr("transform", "translate(#{width/2 + @get('padding')}, #{height/2 + @get('padding')})")
     g.append('g').classed('outer', true)
     g.append('g').classed('inner', true)
-    # data = @get('data')
-
-    #
-    # outerRadius = d3.min([width, height])/2
-    # radius = outerRadius *.80
-    # innerRadius = .17* radius
-    #
-    # radiusScale = d3.scale.linear()
-    #   .domain([0,6])
-    #   .range([innerRadius, radius])
-    #   .clamp(true)
-    # opacityScale = d3.scale.linear()
-    #   .domain([0,6])
-    #   .range([.2, 1])
-    # pie = d3.layout.pie()
-    #   .padAngle(.03)
-    #   .sort(null)
-    #   .value((d) -> d.weight)
-    #
-    # arc = d3.svg.arc()
-    #   .innerRadius(innerRadius)
-    #   .outerRadius((d) -> radiusScale(0))
-    #   .cornerRadius(5)
-    # outerArc = d3.svg.arc()
-    #   .innerRadius(outerRadius * .85)
-    #   .outerRadius(outerRadius)
-    #   .cornerRadius(5)
-    # g = svg.append("g")
-    #   .attr("transform", "translate(#{width/2 + @get('padding')}, #{height/2 + @get('padding')})")
-    # gEnter = g.append("g")
-    #   .selectAll("path")
-    #   .data(pie(data))
-    #   .enter()
-    # gEnter.append("path")
-    #   .attr("class", (d) -> "category#{d.data.name} category")
-    #   .classed("inner", true)
-    #   .attr("d", arc)
-    #   .attr("fill-opacity", (d) -> opacityScale(d.data.value))
-    #   .on("click", (d) =>
-    #     category = @get('patient.categoryDisplay').findBy('name', d.data.name)
-    #     svg.selectAll(".category").classed("active", false)
-    #     if (@get('selectedCategory') == (category))
-    #       @set('selectedCategory', null)
-    #     else
-    #       svg.selectAll(".category#{d.data.name}").classed("active", true)
-    #       @set('selectedCategory', category)
-    #   )
-    #
-    # gEnter.append("path")
-    #   .attr("class", (d) -> "category#{d.data.name} category outer")
-    #   .attr("d", outerArc)
-    #   .attr("fill-opacity", (d) -> opacityScale(d.data.value))
-    #
-    #   .on("click", (d) =>
-    #     category = @get('patient.categoryDisplay').findBy('name', d.data.name)
-    #     svg.selectAll(".category").classed("active", false)
-    #     if (@get('selectedCategory') == (category))
-    #       @set('selectedCategory', null)
-    #     else
-    #       svg.selectAll(".category#{d.data.name}").classed("active", true)
-    #       @set('selectedCategory', category)
-    #   )
-    #
-    #   .on("dblclick", (d) ->
-    #     rotateAngle = -d3.mean([d.startAngle, d.endAngle])*180/Math.PI
-    #     d3.select(this.parentNode).transition().duration(1000).attr("transform", -> "rotate(#{rotateAngle})")
-    #   )

   updateChart: (->
     svg = d3.select(@element).select("svg")
@@ -89,7 +22,7 @@
     width = height = @get('size') - 2 * @get('padding')
     tip = d3.tip()
       .attr('class', 'd3-tip')
-      .html((d) -> d.data.name)
+      .html((d) -> "#{d.data.name} - #{d.data.value}")
     svg.call(tip)
     outerRadius = d3.min([width, height])/2
     radius = outerRadius *.80
@@ -100,7 +33,7 @@
       .value((d) -> d.weight)
     radiusScale = d3.scale.linear()
       .domain([0,6])
-      .range([innerRadius, radius])
+      .range([innerRadius + 3*@padding, radius - 3*@padding])
       .clamp(true)
     opacityScale = d3.scale.linear()
       .domain([0,6])
@@ -110,13 +43,33 @@
       .innerRadius(innerRadius)
       .outerRadius((d) -> radiusScale(d.data?.value||0))
       .cornerRadius(5)
+
+    outerArc = d3.svg.arc()
+      .innerRadius(radius-3*@padding)
+      .outerRadius(radius)
+      .cornerRadius(5)
+    outerpath = svg.select('g').select(".outer")
+      .selectAll("path")
+      .data(pie(data))
+    outerpath.enter()
+      .append('path')
+    outerpath.exit()
+      .remove()
+
+    outerpath
+      .on('mouseover', tip.show)
+      .on('mouseout', tip.hide)
+      .attr("d", outerArc)
     pathingData = svg.select('g').select(".inner")
       .selectAll("path")
       .data(pie(data))
     pathingData.enter()
       .append('path')
-    console.log pie(@data)
+    pathingData.exit()
+      .remove()
     pathingData
+      .on('mouseover', tip.show)
+      .on('mouseout', tip.hide)
       .attr("d", arc)
       .attr("fill-opacity", (d) -> opacityScale(d.data.value))
       .on("click", (d) =>


Uses the correct variable names for this situation.

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -226,7 +226,7 @@

   $(document)
     .off 'click', 'aside .gutter-toggle'
-    .on 'click', 'aside .gutter-toggle', (e, manual) ->
+    .on 'click', 'aside .gutter-toggle', (e, triggered) ->
       e.preventDefault()
       $this = $(this)
       $thisIcon = $this.find 'i'
@@ -251,7 +251,7 @@
         $('.page-with-sidebar')
           .removeClass('right-sidebar-collapsed')
           .addClass('right-sidebar-expanded')
-      if not manual
+      if not triggered
         $.cookie("collapsed_gutter",
           $('.right-sidebar')
             .hasClass('right-sidebar-collapsed'), { path: '/' })


Modify year-end dates only for empty values

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -148,9 +148,11 @@

     # Auto fill the year for previous years
     $(".js-financial-year-changed-dates .js-fy-entries").each ->
-      parent_fy = $(this).parent().find(".js-fy-entries")
-      this_fy_year = fy_year - (parent_fy.size() - parent_fy.index($(this)) - 1)
-      $(this).find("input.js-fy-year").val(this_fy_year)
+      if $(this).find("input.js-fy-year").val() == ""
+        parent_fy = $(this).parent().find(".js-fy-entries")
+        this_year = fy_year - (parent_fy.size() - parent_fy.index($(this)) - 1)
+        $(this).find("input.js-fy-year").val(this_year)
+
     fy_latest_changed_input.find("input").attr("disabled", "disabled")
     $(".js-financial-year-changed-dates").attr("data-year", fy_year)


Fixes spinner when navigating back

Fixes spinner when navigating back

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -36,6 +36,10 @@
   $('[title]').tooltip('hide')
   $('.tooltip').remove()

+$(document).on 'page:restore', () ->
+  $('[data-barberpole]').removeClass('af-barberpole')
+  $('[title]').tooltip('hide')
+
 $(document).ready () ->
   $(document).ajaxStart () ->
     $('[data-barberpole]').addClass('af-barberpole')


Make sure we are looking inside dropdpown wrapper

--- app/assets/javascripts/gl_dropdown.js.coffee
+++ app/assets/javascripts/gl_dropdown.js.coffee
@@ -306,7 +306,7 @@
       if @dropdown.find(".dropdown-toggle-page").length
         selector = ".dropdown-page-one .dropdown-content li:first-child a"

-      $(selector).addClass 'is-focused'
+      @getElement(selector).addClass 'is-focused'

   rowClicked: (el) ->
     fieldName = @options.fieldName


fakes annotation lifecycle to prevent type error

--- app/assets/javascripts/interface_test.coffee
+++ app/assets/javascripts/interface_test.coffee
@@ -10,6 +10,9 @@
   skip: ->
     console.log 'skip this annotation document'

+  registerInterfaceInstance: (typeName, _) ->
+    console.log "registering interface: #{typeName}"
+
 class InterfaceTest
   _this = undefined

@@ -20,6 +23,7 @@

     # fake annotation_lifecycle functionallity
     window[$staging.data('interface-type-name')] = new AnnotationLifecycleFaker()
+    window.annotationLifecycle = new AnnotationLifecycleFaker()

     # render template with test payload & append to DOM
     mustacheParsedTemplate = Mustache.render(


Use Ember.computed

Use Ember.computed

--- app/assets/javascripts/models/user.js.coffee
+++ app/assets/javascripts/models/user.js.coffee
@@ -7,10 +7,10 @@
   person: DS.belongsTo('author')
   token: DS.attr('string')

-  isMe: (()->
-    @.get('id') == 'me'
-  ).property('id')
+  isMe: Ember.computed('id', ->
+    @get('id') == 'me'
+  )

-  isAdmin: (()->
+  isAdmin: Ember.computed('admin', ->
     @get('admin') == true
-  ).property('admin')
+  )


Added parens on a method call to fix errors when no keyboard or paddles.

--- app/assets/utensils/carousel/carousel.coffee
+++ app/assets/utensils/carousel/carousel.coffee
@@ -95,8 +95,8 @@

   addListeners: ->
-    @html.on "keydown.#{@namespace}", => @keyed arguments... if @keyboard
-    @paddles.on "click.#{@namespace}", => @paddled arguments... if @paddles.length
+    @html.on("keydown.#{@namespace}", => @keyed arguments...) if @keyboard
+    @paddles.on("click.#{@namespace}", => @paddled arguments...) if @paddles.length

   removeListeners: ->


Clustering works again

Clustering works again

--- app/scripts/alchemy/drawing/nodeUtils.coffee
+++ app/scripts/alchemy/drawing/nodeUtils.coffee
@@ -24,7 +24,7 @@
             node = alchemy._nodes[d.id]
             styles = node.renderedStyles

-            if @nodeColours d is not ''
+            if @nodeColours(d) is not ''
                 styles.fill = @nodeColours d

             str = JSON.stringify styles
@@ -32,7 +32,6 @@
             str = str.replace "{", ""
             str = str.replace "}", ""
             str = str.replace '"', ""
-            str

             str.split(",").join(";")
                .split("{").join("")


Fix showing correct response

Fix showing correct response

--- app/javascript/src/classes/pool.coffee
+++ app/javascript/src/classes/pool.coffee
@@ -53,13 +53,12 @@
       dataType: "json"

     .done (resp) ->
-      if resp.success
-        notice "Post added to pool"
-      else
-        notice "Error: #{resp.reason}"
+      notice "Post added to pool"

-    .fail ->
-      notice "Error: unknown error"
+    .fail (xhr) ->
+      reason = xhr.responseJSON?.reason ? 'unknown error'
+
+      notice "Error: #{reason}"

   remove_post: (post_id, pool_id) ->


Refresh current page after language change

--- app/scripts/directives/language.coffee
+++ app/scripts/directives/language.coffee
@@ -22,6 +22,7 @@
     @storage.setItem("selectedLanguage", @selectedLanguage)
     @languageDropdownVisible = false
     @gettext.currentLanguage = @selectedLanguage
+    @reloadPage()

   toggleDropDown: (ev) =>
     @languageDropdownVisible = not @languageDropdownVisible
@@ -35,6 +36,9 @@
       )
     )

+  reloadPage: ->
+    window.location.reload(true)
+
 angular.module('holmesApp')
   .directive('language', (gettextCatalog, $window) ->
     replace: true


Do not redirect to connected machine IDE route

Signed-off-by: Sonmez Kartal <d2d15c3d37396a5f2a09f8b42cf5f27d43a3fbde@koding.com>

--- client/app/lib/components/sidebarmachineslistitem/connectedmanagedmachinewidget.coffee
+++ client/app/lib/components/sidebarmachineslistitem/connectedmanagedmachinewidget.coffee
@@ -47,11 +47,6 @@
     router.handleRoute newPath  unless newPath is currentPath

-  componentWillMount: ->
-
-    kd.singletons.router.handleRoute "/IDE/#{@props.machine.get('slug')}"
-
-
   render: ->

     connectedMachine = @state.connectedManagedMachine.get @props.machine.get('_id')


implement 'build process' of checking themes on startup, parsing and inserting into DB

--- bootstrap-themer-server.coffee
+++ bootstrap-themer-server.coffee
@@ -1,5 +1,6 @@
 fs = Npm.require 'fs'
 less = Npm.require 'less'
+crypto = Npm.require 'crypto'

 assetPath = "#{__meteor_bootstrap__.serverDir}/assets/packages/tap_bootstrap-themer/lib/less/"
 bootstrapPath = assetPath+'bootstrap/'
@@ -15,8 +16,49 @@
   filename: rootFile

 ThemeCollection = new Meteor.Collection 'BootstrapThemer'
-
-# HELPERS
+Themes = new Meteor.Collection 'BootstrapThemerThemes'
+
+Meteor.startup ->
+  # check for new themes
+  newThemes = 0
+
+  # insert the vanilla bootstrap theme if there are none
+  if Themes.find().count() is 0
+    newThemes++
+    Themes.insert
+      _id: 'vanilla'
+      name: 'Vanilla Bootstrap'
+      defaults: {}
+      less: ''
+      checksum: crypto.createHash('md5').update('').digest("hex")
+      predefined: true
+
+  for themeName in fs.readdirSync themesPath
+    # only add folders
+    if fs.lstatSync(themesPath+themeName).isDirectory()
+      thisTheme = {name: themeName}
+      for file in fs.readdirSync themesPath+themeName
+        thisTheme[file] = fs.readFileSync("#{themesPath}#{themeName}/#{file}").toString()
+
+      checksum = crypto.createHash('md5').update(thisTheme['bootswatch.less'] + thisTheme['variables.less']).digest("hex")
+      # use a checksum to efficiently update only when theme has changed
+      unless Themes.findOne({_id: themeName, checksum: checksum})
+        newThemes++
+        # new/updated theme found, let's update it
+        parsedLessDefaults = {}
+        for line in thisTheme['variables.less'].split('\n') when line.indexOf("@") is 0
+          keyVar = line.trim().split(';')[0].split(':')
+          parsedLessDefaults["#{keyVar[0].trim()}"] = keyVar[1].trim()
+
+        Themes.upsert _id: themeName,
+          name: themeName
+          defaults: parsedLessDefaults
+          less: thisTheme['bootswatch.less']
+          checksum: checksum
+          predefined: true
+
+  if newThemes
+    console.log "tap:themer just installed/updated #{newThemes} themes! 😎"

 renderLess = (targetLess, addTheme) ->

@@ -90,6 +132,7 @@
     $set:
       availableThemes: themes

+# TODO remove getLessVars after managed_themes, do clientside

 getLessVars = (lessStr) ->
   # get the computed CSS, so colorpicker works


Fix form state on submitting with enter key

--- resources/assets/coffee/react/beatmap-discussions/new-reply.coffee
+++ resources/assets/coffee/react/beatmap-discussions/new-reply.coffee
@@ -161,7 +161,8 @@

     @postXhr?.abort()

-    action = event.currentTarget.dataset.action
+    # in case the event came from input box, do 'reply'.
+    action = event.currentTarget.dataset.action ? 'reply'
     @setState posting: action

     resolved = switch action


Add Atom analytics

Add Atom analytics

Tired of having to work around this automatically added change, and
exposing it should be harmless.

--- atom/config.cson
+++ atom/config.cson
@@ -2,6 +2,8 @@
   "atom-beautify":
     elm:
       beautify_on_save: true
+    general:
+      _analyticsUserId: "8c763e77-aa28-46fb-8b0e-cb1b727588bf"
   "atom-ctags": {}
   "autocomplete-plus":
     enableAutoActivation: false


Do not show cursor when text is selected in Atom

--- atom/config.cson
+++ atom/config.cson
@@ -80,6 +80,7 @@
     fontFamily: "Monaco"
     fontSize: 16
     invisibles: {}
+    showCursorOnSelection: false
     softTabs: false
     softWrap: true
     tabLength: 4


Atom: resort config.cson

Atom: resort config.cson

--- atom/config.cson
+++ atom/config.cson
@@ -1,31 +1,31 @@
 "*":
-  welcome:
-    showOnStartup: false
-  core:
-    excludeVcsIgnoredPaths: false
-  editor:
-    preferredLineLength: 120
-    showIndentGuide: true
-    showInvisibles: true
-    invisibles: {}
-  linter:
-    showHighlighting: false
-    showErrorTabFile: false
-    showErrorTabProject: false
-    showErrorPanel: false
-    underlineIssues: false
   "autocomplete-plus":
     confirmCompletion: "tab"
   autosave:
     enabled: true
+  core:
+    excludeVcsIgnoredPaths: false
+  editor:
+    invisibles: {}
+    preferredLineLength: 120
+    showIndentGuide: true
+    showInvisibles: true
   "file-icons":
     onChanges: true
   "git-projects":
     sortBy: "Latest modification date"
     maxDepth: 1
+  "highlight-selected":
+    hideHighlightOnSelectedWord: true
+    highlightBackground: true
+    onlyHighlightWholeWords: true
+  linter:
+    showErrorPanel: false
+    showErrorTabFile: false
+    showErrorTabProject: false
+    showHighlighting: false
+    underlineIssues: false
   tabs:
     enableVcsColoring: true
-  "highlight-selected":
-    onlyHighlightWholeWords: true
-    hideHighlightOnSelectedWord: true
-    highlightBackground: true
+  welcome:
+    showOnStartup: false


Fix deprecation warning in init.coffee

Fix deprecation warning in init.coffee

Warning text:

> This is now a view method. Call TextEditorElement::setScrollTop instead.

--- atom/init.coffee
+++ atom/init.coffee
@@ -110,7 +110,7 @@
     cursorPosition = textEditor.getCursorScreenPosition()
     pixelPositionForCursorPosition =
       textEditorElement.pixelPositionForScreenPosition(cursorPosition)
-    textEditor.setScrollTop(pixelPositionForCursorPosition.top)
+    textEditorElement.setScrollTop(pixelPositionForCursorPosition.top)

   # Approximate Vim's "zz" motion: Scroll the view such that the line containing
   # the cursor is vertically centered in the view.


add memory logger to track changes

add memory logger to track changes

--- services/track-changes/app.coffee
+++ services/track-changes/app.coffee
@@ -9,6 +9,7 @@
 Metrics = require "metrics-sharelatex"
 Metrics.initialize("track-changes")
 Metrics.mongodb.monitor(Path.resolve(__dirname + "/node_modules/mongojs/node_modules/mongodb"), logger)
+Metrics.memory.monitor(logger)

 child_process = require "child_process"


show issue and merge request's id in the project

--- src/scripts/gitlab.coffee
+++ src/scripts/gitlab.coffee
@@ -88,9 +88,9 @@
         else
           switch hook.object_kind
             when "issue"
-              robot.send user, "Issue #{bold(hook.object_attributes.id)}: #{hook.object_attributes.title} (#{hook.object_attributes.state})"
+              robot.send user, "Issue #{bold(hook.object_attributes.iid)}: #{hook.object_attributes.title} (#{hook.object_attributes.state})"
             when "merge_request"
-              robot.send user, "Merge Request #{bold(hook.object_attributes.id)}: #{hook.object_attributes.title} (#{hook.object_attributes.state}) between #{bold(hook.object_attributes.source_branch)} and #{bold(hook.object_attributes.target_branch)}"
+              robot.send user, "Merge Request #{bold(hook.object_attributes.iid)}: #{hook.object_attributes.title} (#{hook.object_attributes.state}) between #{bold(hook.object_attributes.source_branch)} and #{bold(hook.object_attributes.target_branch)}"
           if hook.object_attributes.description
             robot.send user, ">> #{hook.object_attributes.description}"


Improve insult script

Improve insult script

Hubot will now choose a random insult from randominsults.net rather than
the short array of built-in insults he previously had.

--- src/scripts/insult.coffee
+++ src/scripts/insult.coffee
@@ -1,8 +1,9 @@
 # Description:
-#   None
+#   Allows Hubot to lambast someone with a random insult
 #
 # Dependencies:
-#   None
+#   "soupselect: "0.2.0"
+#   "htmlparser": "1.7.6"
 #
 # Configuration:
 #   None
@@ -10,20 +11,31 @@
 # Commands:
 #   hubot insult <name> - give <name> the what-for
 #
-# Author:
-#   ajacksified
+# Authors:
+#   ajacksified, brandonvalentine
+
+Select     	= require("soupselect").select
+HtmlParser  = require "htmlparser"

 module.exports = (robot) ->
   robot.respond /insult (.*)/i, (msg) ->
     name = msg.match[1].trim()
-    msg.send(insult(name))
+    insult(msg, name)

-insult = (name) ->
-  insults[(Math.random() * insults.length) >> 0].replace(/{name}/, name);
+insult = (msg, name) ->
+  msg
+    .http("http://www.randominsults.net")
+    .header("User-Agent: Insultbot for Hubot (+https://github.com/github/hubot-scripts)")
+    .get() (err, res, body) ->
+      quote = parse_html body, "i"
+      msg.send name + ": " + parse_quote(quote)

-insults = [
-  "{name} is a scoundrel.",
-  "{name} should be ashamed of himself.",
-  "{name} is a motherless son of a goat.",
-  "{name} is a gravy-sucking pig."
-]
+parse_html = (html, selector) ->
+  handler = new HtmlParser.DefaultHandler((() ->), ignoreWhitespace: true)
+  parser  = new HtmlParser.Parser handler
+
+  parser.parseComplete html
+  Select handler.dom, selector
+
+parse_quote = (quote) ->
+  quote[0].children[0].data


work in progress

work in progress

--- src/openpgp/packet/sess.iced
+++ src/openpgp/packet/sess.iced
@@ -12,6 +12,26 @@

   @parse : (slice) -> (new PKESK_Parser(slice)).parse()

+
+#=================================================================================
+
+# 5.13.  Sym. Encrypted Integrity Protected Data Packet (Tag 18)
+class SEIPD extends Packet
+
+#=================================================================================
+
+class SEIPD_Parser
+
+  constructor : (@slice) ->
+
+  #  The body of this packet consists of:
+  #
+  #   - A one-octet version number.  The only currently defined value is 1.
+  #   - Encrypted data, the output of the selected symmetric-key cipher
+  #     operating in Cipher Feedback mode with shift amount equal to the
+  #     block size of the cipher (CFB-n where n is the block size).
+  parse : () ->
+    throw new Error "Unknown SEIPD version #{v}" unless (v = @slice.read_uint8()) is C.versions.SEIPD

 #=================================================================================


Debounce content checks

Debounce content checks

- Wait until 200 ms of inactivity before checking content.

--- community/browser/app/scripts/controllers/Layout.coffee
+++ community/browser/app/scripts/controllers/Layout.coffee
@@ -97,7 +97,7 @@
       $scope.editorChanged = (codeMirror) ->
         $scope.editorOneLine = codeMirror.lineCount() == 1 and !Editor.document
         $scope.disableHighlighting = codeMirror.getValue().trim()[0] == ':'
-        $scope.editor.checkCypherContent codeMirror
+        checkCypherContent(codeMirror)

       $scope.isDrawerShown = false
       $scope.whichDrawer = ""
@@ -161,6 +161,11 @@
           $scope.$emit 'layout.changed'
       , 100)

+      checkCypherContent = Utils.debounce(
+        (codeMirror) ->
+          $scope.editor.checkCypherContent codeMirror
+      , 200)
+
       $(window).resize(resizeStream)

       if !!navigator.userAgent.match(/Gecko\/[\d\.]+.*Firefox/)


Buttonbar: Add cui-last-visible-child class to the buttonbar's last visible child.

While at it, fixed a corner case when setting cui-first-visible-child.


Add default keybinding for go-to-page command

--- keymaps/pdf-view.cson
+++ keymaps/pdf-view.cson
@@ -1,3 +1,6 @@
+'.pdf-view':
+  'ctrl-g': 'pdf-view:go-to-page'
+
 '.platform-darwin .pdf-view':
   'cmd-+': 'pdf-view:zoom-in'
   'cmd-=': 'pdf-view:zoom-in'


control-t returns from symbol, not control-shift-t

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -162,7 +162,7 @@
   '.': 'vim-mode:repeat'

   'ctrl-]': 'symbols-view:go-to-declaration'
-  'ctrl-T': 'symbols-view:return-from-declaration'
+  'ctrl-t': 'symbols-view:return-from-declaration'

   'ctrl-a': 'vim-mode:increase'
   'ctrl-x': 'vim-mode:decrease'


Watch the correct config. Silly copy paste

--- lib/linter-erlc.coffee
+++ lib/linter-erlc.coffee
@@ -14,11 +14,11 @@

   constructor: (editor) ->
     super(editor)
-    atom.config.observe 'linter-erlc.elixircExecutablePath', =>
-      @executablePath = atom.config.get 'linter-erlc.elixircExecutablePath'
+    atom.config.observe 'linter-erlc.erlcExecutablePath', =>
+      @executablePath = atom.config.get 'linter-erlc.erlcExecutablePath'

   destroy: ->
-    atom.config.unobserve 'linter-erlc.elixircExecutablePath'
+    atom.config.unobserve 'linter-erlc.erlcExecutablePath'

   lintFile: (filePath, callback) ->
     @cwd = atom.project.path


:fire: Remove an invalid reference

:fire: Remove an invalid reference

--- lib/linter-plus.coffee
+++ lib/linter-plus.coffee
@@ -54,7 +54,6 @@

   deactivate: ->
     @subscriptions.dispose()
-    @panel.removeDecorations()
     @eachLinter (linter) ->
       linter.subscriptions.dispose()
     @views.deactivate()


Properly load 'marked'

Properly load 'marked'

--- ui/scripts/app.coffee
+++ ui/scripts/app.coffee
@@ -4,7 +4,7 @@
         handlebars: 'bower/handlebars/handlebars'
         underscore: 'bower/underscore/underscore'
         backbone: 'bower/backbone/backbone'
-        markdown: 'bower/marked/marked'
+        markdown: 'bower/marked/lib/marked'
         moment: 'bower/moment/moment'
         d3: 'bower/d3/d3'
         modernizr: 'bower/modernizr/modernizr'


hasOwn is Object.prototype.hasOwnProperty

--- lib/nodevisitor.coffee
+++ lib/nodevisitor.coffee
@@ -10,7 +10,7 @@
                         rv.push y
         rv

-hasOwn = Object.hasOwnProperty
+hasOwn = Object.prototype.hasOwnProperty

 exports.NodeVisitor = class NodeVisitor
         constructor: ->


Teamwork: Removed unused method.

Teamwork: Removed unused method.

--- client/Teamwork/Views/teamworktabview.coffee
+++ client/Teamwork/Views/teamworktabview.coffee
@@ -334,11 +334,6 @@

     KD.mixpanel "Teamwork tab browser, click"

-  switchToPane: (paneIndexKey) ->
-    for pane in @tabView.panes
-      if pane.getOptions().indexKey is paneIndexKey
-        debugger
-
   createChat: ->
     pane = new KDTabPaneView title: "Chat"
     chat = new ChatPane


The item property of the requestObject might be missing, added a ToDo.

--- lib/recommender.coffee
+++ lib/recommender.coffee
@@ -1,4 +1,6 @@
 _ = require 'underscore'
+
+# TODO the item property might be missing

 class Recommender
   constructor: (@itemStorage) ->


Boyscouting: simplify core_loaded usage

Boyscouting: simplify core_loaded usage

--- js-library/app/js/loader/loader_common.coffee
+++ js-library/app/js/loader/loader_common.coffee
@@ -70,11 +70,8 @@

     root.jail_ready_promise.resolve()

-    root.core_loaded_promise
-    .then( ->
-        root.perf.add_timing_event 'core_loaded'
-    )
-    .then ->
+    root.core_loaded_promise.then ->
+      root.perf.add_timing_event 'core_loaded'
       #called from jail-iframe when core iframe is ready.
       for name in methods
         do (name) ->
@@ -93,6 +90,7 @@
     if document.body
       whenHasBody()
     else
+      console.log('skipped init attempt ' + i)
       setTimeout tryToInit(i+1), i

   tryToInit(1)()


remove log

remove log

--- js-library/app/js/loader/loader_common.coffee
+++ js-library/app/js/loader/loader_common.coffee
@@ -90,7 +90,7 @@
     if document.body
       whenHasBody()
     else
-      console.log('skipped init attempt ' + i)
+      if localStorage?['debug'] then console.log('skipped init attempt ' + i)
       setTimeout tryToInit(i+1), i

   tryToInit(1)()


CHG: stop propagation on sortable dragstart

--- lib/assets/javascripts/tao/ui/sortable.coffee
+++ lib/assets/javascripts/tao/ui/sortable.coffee
@@ -10,6 +10,7 @@

   _connected: ->
     @on 'dragstart', @itemSelector, (e) =>
+      e.stopPropagation()
       $item = $ e.currentTarget
       itemRect = $item.get(0).getBoundingClientRect()
       @_startDragging $item


consolidated output to display function for both errors and standard output

--- lib/script-view.coffee
+++ lib/script-view.coffee
@@ -36,7 +36,7 @@
     @check()

     if @err?
-      @displayError()
+      @display("Error", "error", @err)
       @err = null
       @stop()
     else
@@ -52,8 +52,8 @@
         cwd: atom.project.getPath()
         env: process.env

-      stdout = (output) => @displayOutput(output, "stdout")
-      stderr = (output) => @displayOutput(output, "stderr")
+      stdout = (output) => @display(@lang, "stdout", output)
+      stderr = (output) => @display(@lang, "stderr", output)
       exit = (return_code) -> console.log("Exited with #{return_code}")

       @bufferedProcess = new BufferedProcess({command, args, options, stdout, stderr, exit})
@@ -89,10 +89,6 @@
         "new?title=Add%20support%20for%20" + @lang + "'>issue on GitHub" +
         " or send your own Pull Request"

-  displayOutput: (line, out_type)->
-    @heading.text(@lang)
-    @output.append("
#{line}
")
-
-  displayError: ->
-    @heading.text("Error")
-    @output.append("
#{@err}
")
+  display: (title, css, line)->
+    @heading.text(title)
+    @output.append("
#{line}
")


No more selectedText and filepath as properties

--- lib/script-view.coffee
+++ lib/script-view.coffee
@@ -89,26 +89,26 @@
     @filename = editor.getTitle()

     # Get selected text
-    @selectedText = editor.getSelectedText()
-    @filepath = editor.getPath()
+    selectedText = editor.getSelectedText()
+    filepath = editor.getPath()

     # If no text was selected, either use the file
     # or select ALL the code in the editor

     # Brand new file, text not selected, "select" ALL the text
-    if (not @selectedText? or not @selectedText) and not @filepath?
-      @selectedText = editor.getText()
+    if (not selectedText? or not selectedText) and not filepath?
+      selectedText = editor.getText()

     # If we still don't have selected text, use the path
-    if (not @selectedText? or not @selectedText) and @filepath?
+    if (not selectedText? or not selectedText) and filepath?
       console.log("Down the file path")
-      @filepath = editor.getPath()
+      filepath = editor.getPath()
       makeargs = grammarMap[@lang]["byFileArgs"]
-      args = makeargs(@filepath)
+      args = makeargs(filepath)
     else
       console.log("Down the selection path")
       makeargs = grammarMap[@lang]["bySelectionArgs"]
-      args = makeargs(@selectedText)
+      args = makeargs(selectedText)

     @run(command, args)


remove logging

remove logging

--- shared/ironTableController.coffee
+++ shared/ironTableController.coffee
@@ -29,7 +29,7 @@

     constructor: ->
-        console.log("IronTableController constuct", @collection()._name)
+        #console.log("IronTableController constuct", @collection()._name)
         super
         @reset()
         #@setupEditRoute()
@@ -48,7 +48,6 @@

     fetchRecordCount: ->
         if not @fetchingCount
-            console.log("fetchingCount")
             @fetchingCount = true
             Meteor.call 'ironTable_' +  @_collectionName() + '_recordCount', @_select(), (error, number) =>
                 @fetchingCount = false


Making sure the image background gets set.

[#59358426] Making sure the background comes up the first time you try to answer an ImageQuestion with an author-provided background.

https://www.pivotaltracker.com/story/show/59358426


add source code link

add source code link

--- views/layout.coffee
+++ views/layout.coffee
@@ -19,4 +19,5 @@
         span -> img src: '/images/coffeescript.png'
         p ->
           em 'Powered with Meryl, Node.js, coffee-script, Redis nowJS and coffeeKup!'
-          a href: 'http://github.com/gradus/node-chess'
+          a href: 'http://github.com/gradus/node-chess', ->
+            'Source Code'