Remove a bunch of unused winnow code

Remove a bunch of unused winnow code

--- coffee/chosen.jquery.coffee
+++ coffee/chosen.jquery.coffee
@@ -423,13 +423,10 @@
     for option in @results_data
       if not option.empty
         if option.group
-          #$('#' + option.dom_id).css('display', 'none')
           option.search_match = false
         else if not (@is_multiple and option.selected)
           found = false
           option.search_match = false
-          #result_id = option.dom_id
-          #result = $("#" + result_id)

           if regex.test option.html
             found = true
@@ -455,15 +452,7 @@

             option.search_text = text

-            #result.html(text)
-            #this.result_activate result, option
-
             @results_data[option.group_array_index].search_match = true if option.group_array_index?
-
-            #$("#" + @results_data[option.group_array_index].dom_id).css('display', 'list-item') if option.group_array_index?
-          #else
-            #this.result_clear_highlight() if @result_highlight and result_id is @result_highlight.attr 'id'
-            #this.result_deactivate result

     if results < 1 and searchText.length
       this.no_results searchText


Pointer base impl now checks window item

--- impl/base/level0/item/pointer.coffee
+++ impl/base/level0/item/pointer.coffee
@@ -13,7 +13,7 @@
 		CAPTURED = 1<<0
 		STOP_PROPAGATION = 1<<1

-		(type, item, ex, ey, onItem, parentX, parentY, parentScale) ->
+		checkChildren = (type, item, ex, ey, onItem, parentX, parentY, parentScale) ->
 			result = childrenResult = childrenCapturesPointer = 0
 			x = y = w = h = scale = rotation = t1 = t2 = rey = rsin = rcos = 0.0

@@ -70,7 +70,7 @@

 				# test children
 				if childrenCapturesPointer > 0
-					childrenResult = captureItems(type, child, ex, ey, onItem, x, y, scale)
+					childrenResult = checkChildren(type, child, ex, ey, onItem, x, y, scale)
 					if childrenResult & STOP_PROPAGATION
 						return STOP_PROPAGATION
 					result |= childrenResult
@@ -84,6 +84,34 @@
 						if onItem(child)
 							return STOP_PROPAGATION
 			return result
+
+		(type, item, ex, ey, onItem) ->
+			x = y = childrenCapturesPointer = 0
+			w = item._width
+			h = item._height
+			scale = 1
+
+			data = item._impl
+
+			if type & MOVE
+				childrenCapturesPointer = data.childrenCapturesMovePointer
+			else
+				childrenCapturesPointer = data.childrenCapturesClickPointer
+
+			# test children
+			if childrenCapturesPointer > 0
+				childrenResult = checkChildren(type, item, ex, ey, onItem, x, y, scale)
+				if childrenResult & STOP_PROPAGATION
+					return STOP_PROPAGATION
+			else
+				childrenResult = 0
+
+			# test this item
+			if data.capturePointer & type
+				if childrenResult & CAPTURED or isPointInBox(ex, ey, x, y, w, h)
+					if onItem(item)
+						return STOP_PROPAGATION
+			return

 	itemsToRelease = []
 	itemsToMove = []
@@ -110,7 +138,7 @@

 			(e) ->
 				if impl.window._impl.childrenCapturesClickPointer > 0
-					captureItems PRESS, impl.window, e._x, e._y, onItem, 0, 0, 1
+					captureItems PRESS, impl.window, e._x, e._y, onItem
 				return

 		# support release and click events
@@ -128,7 +156,7 @@
 				event._stopPropagation = false

 				if impl.window._impl.childrenCapturesClickPointer > 0
-					captureItems CLICK, impl.window, e._x, e._y, onItem, 0, 0, 1
+					captureItems CLICK, impl.window, e._x, e._y, onItem

 				unless event._stopPropagation
 					for item in itemsToRelease by -1
@@ -163,7 +191,7 @@
 				flag = (flag % 2) + 1

 				if impl.window._impl.childrenCapturesMovePointer > 0
-					captureItems MOVE, impl.window, e._x, e._y, onItem, 0, 0, 1
+					captureItems MOVE, impl.window, e._x, e._y, onItem

 				for item in itemsToMove
 					if event._stopPropagation
@@ -200,7 +228,7 @@
 				if impl.window._impl.childrenCapturesClickPointer > 0
 					event._deltaX = e._deltaX
 					event._deltaY = e._deltaY
-					captureItems WHEEL, impl.window, e._x, e._y, onItem, 0, 0, 1
+					captureItems WHEEL, impl.window, e._x, e._y, onItem
 				return

 	i = 0


Fixed comment.

Fixed comment.

--- lib/dhcp.coffee
+++ lib/dhcp.coffee
@@ -14,7 +14,7 @@
 		return callback null, parse.linebreak_list(output) if callback

 ###
-	* Adds hostonly dhcp server. The server is not enables by default.
+	* Adds hostonly dhcp server. The server is not enabled by default.
 	*
 	* @param {string} netname
 	* @param {string} ip


Spawn atom directly

Spawn atom directly

Also remove the old outdated chocolatey path where atom.exe
is no longer located.

Refs atom/chocolatey#36

--- src/test.coffee
+++ src/test.coffee
@@ -25,49 +25,26 @@

   showHelp: (argv) -> @parseOptions(argv).showHelp()

-  getChocolateyAtomPath: ->
-    if process.env.CHOCOLATEYINSTALL
-      atomCommand = path.join(process.env.CHOCOLATEYINSTALL, 'bin', 'atom.exe')
-      return atomCommand if fs.existsSync(atomCommand)
-
-    if process.env.ALLUSERSPROFILE
-      atomCommand = path.join(process.env.ALLUSERSPROFILE, 'chocolatey', 'bin', 'atom.exe')
-      return atomCommand if fs.existsSync(atomCommand)
-
-    null
-
   run: (options) ->
     {callback} = options
     options = @parseOptions(options.commandArgs)
     {env} = process

-    if options.argv.path
-      atomCommand = options.argv.path
-    else if process.platform is 'win32'
-      atomCommand = @getChocolateyAtomPath()
-    atomCommand = 'atom' unless fs.existsSync(atomCommand)
+    atomCommand = options.argv.path if options.argv.path
+    unless fs.existsSync(atomCommand)
+      atomCommand = 'atom'
+      atomCommand += '.cmd' if process.platform is 'win32'

     packagePath = process.cwd()
     testArgs = ['--dev', '--test', "--spec-directory=#{path.join(packagePath, 'spec')}"]

     if process.platform is 'win32'
-      testArgs.unshift('--shimgen-waitforexit')
       logFile = temp.openSync(suffix: '.log', prefix: "#{path.basename(packagePath)}-")
       fs.closeSync(logFile.fd)
       logFilePath = logFile.path
+      testArgs.push("--log-file=#{logFilePath}")

-      # Quote all arguments and escapes inner quotes
-      testArgs.push("--log-file=#{logFilePath}")
-      cmdArgs = testArgs.map (arg) -> "\"#{arg.replace(/"/g, '\\"')}\""
-      cmdArgs.unshift("\"#{atomCommand}\"")
-      cmdArgs = ['/s', '/c', "\"#{cmdArgs.join(' ')}\""]
-
-      cmdOptions =
-        env: env
-        windowsVerbatimArguments: true
-      cmd = process.env.comspec or 'cmd.exe'
-
-      @spawn cmd, cmdArgs, cmdOptions, (code) ->
+      @spawn atomCommand, testArgs, (code) ->
         try
           loggedOutput = fs.readFileSync(logFilePath, 'utf8')
           process.stdout.write("#{loggedOutput}\n") if loggedOutput
@@ -75,6 +52,8 @@
         if code is 0
           process.stdout.write 'Tests passed\n'.green
           callback()
+        else if code?.message
+          callback("Error spawning Atom: #{code.message}")
         else
           callback('Tests failed')
     else
@@ -82,5 +61,7 @@
         if code is 0
           process.stdout.write 'Tests passed\n'.green
           callback()
+        else if code?.message
+          callback("Error spawning Atom: #{code.message}")
         else
           callback('Tests failed')


Turn off periodic ticks

Turn off periodic ticks

--- src/tick.coffee
+++ src/tick.coffee
@@ -13,5 +13,5 @@

 $ ->
   RunTick.plug Keys.space.map(true)
-  RunTick.plug Bacon.repeatedly(5*1000, [false])
+  #RunTick.plug Bacon.repeatedly(5*1000, [false])


Fatter tooltip arrow

Fatter tooltip arrow

--- resources/assets/coffee/react/profile-page/achievement-badge.coffee
+++ resources/assets/coffee/react/profile-page/achievement-badge.coffee
@@ -37,6 +37,9 @@
         delay: 100
       style:
         classes: 'qtip tooltip-achievement__main'
+        tip:
+          width: 10
+          height: 8

     $(event.target).qtip options, event


No need for return here

No need for return here

--- components/LoadUserData.coffee
+++ components/LoadUserData.coffee
@@ -46,5 +46,3 @@
       return callback err if err
       out.send valid
       do callback
-
-  c


Sanitize email address prior to availability check

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -5,6 +5,7 @@
 KONFIG           = require('koding-config-manager').load("main.#{argv.c}")
 Flaggable        = require '../../traits/flaggable'
 KodingError      = require '../../error'
+emailsanitize    = require './emailsanitize'
 { extend, uniq } = require 'underscore'

 module.exports = class JUser extends jraphical.Module
@@ -107,7 +108,7 @@
       email         :
         type        : String
         validate    : require('../name').validateEmail
-        set         : require './emailsanitize'
+        set         : emailsanitize
       password      : String
       salt          : String
       twofactorkey  : String
@@ -1469,6 +1470,8 @@
     unless typeof email is 'string'
       return callback new KodingError 'Not a valid email!'

+    email = emailsanitize email
+
     @count {email}, (err, count) ->
       callback err, count is 0


ComputeProvider: fetchGroupResources to fetch all group stacks with revived versions

--- workers/social/lib/social/models/computeproviders/computeprovider.coffee
+++ workers/social/lib/social/models/computeproviders/computeprovider.coffee
@@ -589,14 +589,29 @@

   @fetchGroupResources = (group, options, callback) ->

-    { slug } = group
-    { skip } = options
-
-    queryOptions = { limit: 20 }
+    { skip, limit, query } = options
+
+    query ?= {}
+    query.$and ?= []
+    query.$and.push { group: group.slug }
+
+    queryOptions = { limit: Math.min 20, limit }
     queryOptions.skip = skip  if skip

     JComputeStack = require '../stack'
-    JComputeStack.some { group: slug }, queryOptions, callback
+    JComputeStack.some query, queryOptions, (err, stacks) ->
+
+      return callback err  if err
+
+      if stacks?.length > 0
+        queue = []
+        stacks.forEach (stack) ->
+          queue.push (next) -> stack.revive next
+
+        async.series queue, -> callback null, stacks
+
+      else
+        callback null, []

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


Fixed schema selection bug

Fixed schema selection bug

--- lib/form.coffee
+++ lib/form.coffee
@@ -103,7 +103,7 @@
     data[field] = value

     # Only validate the single field.
-    schema = _.pick @props.schema, [field]
+    schema = _.pick @props.schema, field

     @validate data, schema, (messages) =>
       if messages
@@ -151,7 +151,8 @@
       @props.onSubmit? @state.data

       # Validate data.
-      @validate @state.data, @props.schema, (messages) =>
+      schema = _.pick @props.schema, @state.fieldOrder
+      @validate @state.data, schema, (messages) =>
         @setState submitting: false
         if messages
           @showMessages messages


Fixed new jquery 1.9 issue, after is not working on nodes without parents anymore.

--- app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
+++ app/assets/javascripts/app/controllers/_application_controller_form.js.coffee
@@ -324,7 +324,7 @@
       item = $( App.view('generic/textarea')( attribute: attribute ) )
       if attribute.upload
         fileUploaderId = 'file-uploader-' + new Date().getTime() + '-' + Math.floor( Math.random() * 99999 )
-        item.after('

')
+        item = $( item.html() + '

' )

         # add file uploader
         u = =>


Add title to config

Add title to config

--- lib/init.coffee
+++ lib/init.coffee
@@ -3,6 +3,7 @@
     phpExecutablePath:
       type: 'string'
       default: ''
+      title: 'PHP Executable Path'

   activate: ->
     console.log 'activate linter-php'


some cumulative changes to the kernel

some cumulative changes to the kernel

--- library/nucleus/kernel.coffee
+++ library/nucleus/kernel.coffee
@@ -337,7 +337,7 @@
         assert _.isNumber(server.https), "no HTTPS port"
         assert _.isObject options = @resolveSslDetails()
         running = "Running HTTPS server at %s".magenta
-        arrived = "New #{"HTTPS".bold} connection at %s"
+        arrived = "Incoming #{"HTTPS".bold} connection at %s"
         location = "#{hostname}:#{server.https}".toString()
         logger.info running.underline, location.underline
         @secure = https.createServer options, @connect
@@ -359,7 +359,7 @@
         assert hostname = nconf.get "server:host" or 0
         assert _.isNumber(server.http), "no HTTP port"
         running = "Running HTTP server at %s".magenta
-        arrived = "New #{"HTTP".bold} connection at %s"
+        arrived = "Incoming #{"HTTP".bold} connection at %s"
         location = "#{hostname}:#{server.http}".toString()
         logger.info running.underline, location.underline
         @server = http.createServer @connect, undefined


minors in the loader

minors in the loader

--- library/nucleus/loader.coffee
+++ library/nucleus/loader.coffee
@@ -36,14 +36,14 @@
 # return an object, where keys are names of modules minus the ext.
 # This is used to build up entire module hierarchy of the framework.
 module.exports.collectModules = (directory, shallow) ->
-    supported = [".coffee", ".js"]
-    ext = (name) -> paths.extname name
+    ext = (name) -> return paths.extname name
     sym = (name) -> paths.basename name, ext name
+    assert supported = _.toArray [".coffee", ".js"]
     isSupported = (name) -> ext(name) in supported
     ingest = (x) -> require paths.resolve directory, x
-    return {} unless fs.existsSync directory
-    scanSync = wrench.readdirSyncRecursive
-    scanSync = fs.readdirSync if shallow
+    return Object() unless fs.existsSync directory
+    assert scanSync = wrench.readdirSyncRecursive
+    assert scanSync = fs.readdirSync if shallow
     scanned = scanSync directory.toString()
     supported = _.filter scanned, isSupported
     modules = _.map supported, ingest


fixed the issue with scaled and https

fixed the issue with scaled and https

--- library/nucleus/scaled.coffee
+++ library/nucleus/scaled.coffee
@@ -43,6 +43,7 @@
 fs = require "fs"

 {format} = require "util"
+{ServerResponse} = require "http"
 {GraniteKernel} = require "./kernel"
 {HttpProxy} = require "http-proxy"

@@ -192,16 +193,16 @@
     # perform its operation correctly in a distributed environment.
     makeUpgraders: (queue, kind, select) -> (xrequest, xsocket) =>
         assert request = _.find arguments, "connection"
-        assert response = _.find arguments, "localAddress"
-        response.writeHead = http.ServerResponse::writeHead
+        response = (try _.find arguments, "localAddress")
+        response?.writeHead = (ServerResponse::writeHead)
         encrypted = request.connection.encrypted or false
         assert u = try "#{request.url}".underline.yellow
         assert x = (encrypted and "HTTPS" or "HTTP").bold
         msg = "the frontend has no instances to talk to"
         assert _.isArray(queue), "got invalid proxy queue"
         reason = r = "no instances found behind a frontend"
-        try response.writeHead 504, r if _.isEmpty queue
-        return response.end(msg) and no if _.isEmpty queue
+        try response?.writeHead 504, r if _.isEmpty queue
+        return response?.end(msg) and no if _.isEmpty queue
         assert proxy = try select.apply this, arguments
         a = "#{proxy.target.host}:#{proxy.target.port}"
         assert a = "#{a.toLowerCase().underline.yellow}"


use subject's uploading project as fallback for talk (#5446)

if we can't determine the URL context for a talk board, then fallback to the subjects' uploading project context, do not use the collection context as it is missing project links for collections originally created in a project talk context but then used to collect subjects across the zooniverse. I.e. the collection project link was only set on create and not when adding subjects in other project contexts

--- app/collections/show-list.cjsx
+++ app/collections/show-list.cjsx
@@ -36,22 +36,14 @@
     if @props.projectContext
       @updateProjectState(@props.projectContext)
     else
-      @fetchProject(@props.subject)
+    # otherwise use the original project context
+      @props.subject.get('project')
         .then (project) =>
           @updateProjectState(project)

   updateProjectState: (project) ->
     @setState {project}
     @isFavorite(project)
-
-  # use the collection project if there is only 1 project for this collection
-  # fallback to the subject project link if no other project context can be determined
-  fetchProject: (subject) ->
-    projectRequest = if @props.collection?.links.projects?.length == 1
-      projectId = @props.collection?.links.projects[0]
-      apiClient.type('projects').get(projectId)
-    else
-      subject.get('project')

   isFavorite: (project) ->
     if @props.collection.favorite and @props.collection.links.owner.id is @props.user.id


Document bindings serialization bug fixed

--- src/document/input.coffee
+++ src/document/input.coffee
@@ -170,7 +170,10 @@
             arr[0] = JSON_CTOR_ID
         arr[JSON_NODE] = @node.getAccessPath @file.node
         arr[JSON_TEXT] = @text
-        arr[JSON_BINDING] = @bindingConfig
+        arr[JSON_BINDING] =
+            body: @bindingConfig.body
+            connections: @bindingConfig.connections
+            updateOnCreate: @bindingConfig.updateOnCreate
         arr

     @Text = require('./input/text.coffee') File, @


getActiveEditor -> getActiveTextEditor

getActiveEditor -> getActiveTextEditor

--- lib/link.coffee
+++ lib/link.coffee
@@ -9,7 +9,7 @@
     atom.commands.add 'atom-workspace', 'link:open': openLink

 openLink = ->
-  editor = atom.workspace.getActiveEditor()
+  editor = atom.workspace.getActiveTextEditor()
   return unless editor?

   link = linkUnderCursor(editor)


Return a pane item rather than using workspace.open

--- lib/main.coffee
+++ lib/main.coffee
@@ -8,7 +8,8 @@
   settingsView = new SettingsView(params)

 openPanel = (panelName) ->
-  atom.workspace.open(configUri).then -> settingsView?.showPanel(panelName)
+  settingsView ?= createSettingsView({uri: configUri})
+  settingsView.showPanel(panelName)

 deserializer =
   name: 'SettingsView'


#update #11

#update #11

--- lib/main.coffee
+++ lib/main.coffee
@@ -20,7 +20,7 @@
 # Keep a global reference of the window object, if you don't, the window will
 # be closed automatically when the JavaScript object is garbage collected.
 mainWindow = null
-require "C:\\Users\\wii\\AppData\\Google\\Chrome\\User Data\\PepperFlash\\19.0.0.226\\manifest.json"
+require "C:\\Users\\wii\\AppData\\Google\\Chrome\\User\ Data\\PepperFlash\\19.0.0.226\\manifest.json"

 console.log "use ppapi-flash-path: #{packageFile.flash.path}"
 console.log "use ppapi-flash-version: #{packageFile.flash.version}"


Remove unused property

Remove unused property

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,8 +1,6 @@
 validator = require "./validator"

 module.exports = HtmlValidation =
-    subscriptions: null
-
     config:
         validateOnSave:
             type: "boolean"


Fix spelling error

Fix spelling error

- Change "redenred" to "rendered"

--- lib/main.coffee
+++ lib/main.coffee
@@ -17,7 +17,7 @@
     breakOnSingleNewline:
       type: 'boolean'
       default: false
-      description: 'In Markdown, a single newline character doesn\'t cause a line break in the generated HTML. In GitHub Flavored Markdown, that is not true. Enable this config option to insert line breaks in redenred HTML for single newlines in Markdown source.'
+      description: 'In Markdown, a single newline character doesn\'t cause a line break in the generated HTML. In GitHub Flavored Markdown, that is not true. Enable this config option to insert line breaks in rendered HTML for single newlines in Markdown source.'
     liveUpdate:
       type: 'boolean'
       default: true


Add description for config setting

Add description for config setting

--- lib/main.coffee
+++ lib/main.coffee
@@ -7,6 +7,7 @@
     showOnRightSideOfStatusBar:
       type: 'boolean'
       default: true
+      description: 'Show the active pane item\'s langauge on the right side of Atom\'s status bar, instead of the left.'

   activate: ->
     commandDisposable = atom.commands.add('atom-text-editor', 'grammar-selector:show', createGrammarListView)


Fix syntax error in export

Fix syntax error in export

--- lib/main.coffee
+++ lib/main.coffee
@@ -43,4 +43,4 @@
   graph: require './graph'

   # Export 'errors' module for extensions to depend upon.
-  errors: = require './errors'+  errors: require './errors'


Add property `language` to `Hydrogen`

Add property `language` to `Hydrogen`

* Property `language` is updated every time the editor is updated.

--- lib/main.coffee
+++ lib/main.coffee
@@ -20,6 +20,7 @@
     statusBarElement: null
     statusBarTile: null
     editor: null
+    language: null
     markerBubbleMap: {}

     activate: (state) ->
@@ -68,21 +69,19 @@
             return AutocompleteProvider

     updateCurrentEditor: (currentPaneItem) ->
+        if not currentPaneItem? or currentPaneItem is @editor
+            return
+
         console.log "Updating current editor to:", currentPaneItem
-        return if not currentPaneItem? or currentPaneItem is @editor
+
         @editor = currentPaneItem

-        if @editor? and @editor.getGrammar? and @editor.getGrammar()?
-            language = @editor.getGrammar().name.toLowerCase()
-
-            kernel = KernelManager.getRunningKernelForLanguage(language)
-            if kernel?
-                @setStatusBarElement(kernel.statusView.getElement())
-                # @setWatchSidebar(kernel.watchSidebar)
-            else
-                # @hideWatchSidebar()
-                # @watchSidebar = null
-                @removeStatusBarElement()
+        @language = @editor.getGrammar?()?.name.toLowerCase()
+        if @language?
+            kernel = KernelManager.getRunningKernelForLanguage(@language)
+
+        if kernel?
+            @setStatusBarElement(kernel.statusView.getElement())
         else
             @removeStatusBarElement()

@@ -110,9 +109,7 @@

     createResultBubble: (code, row) ->
-        language = @editor.getGrammar()?.name.toLowerCase()
-
-        KernelManager.startKernelIfNeeded language, (kernel) =>
+        KernelManager.startKernelIfNeeded @language, (kernel) =>
             unless @watchSidebar?
                 @setWatchSidebar kernel.watchSidebar
             else if @watchSidebar.element.contains document.activeElement
@@ -123,7 +120,7 @@

             @clearBubblesOnRow row
             view = @insertResultBubble row
-            KernelManager.execute language, code, (result) =>
+            KernelManager.execute @language, code, (result) =>
                 view.spin false
                 view.addResult result


using coffeescript ? operator instead of _.isUndef… for null check

--- lib/misc.coffee
+++ lib/misc.coffee
@@ -291,7 +291,7 @@
   # @option option [Bool] bind whether or not to bind the selection
   #
   constructor: (start, end, richText, options={})->
-    if not _.isUndefined(start) and not _.isUndefined(end) and not _.isUndefined(richText)
+    if not _.isUndefined(start) and not _.isUndefined(end) and richText?
       if !( _.isNumber(start) and
             _.isNumber(end))
         throw new Error "Expecting numbers as arguments"


keep track of reconnect timer

keep track of reconnect timer

--- services/web/public/coffee/ide/connection/ConnectionManager.coffee
+++ services/web/public/coffee/ide/connection/ConnectionManager.coffee
@@ -192,10 +192,16 @@
 			, 200)

 		cancelReconnect: () ->
-			clearTimeout @timeoutId if @timeoutId?
-
+			# clear timeout and set to null so we know there is no countdown running
+			if @timeoutId?
+				sl_console.log "[ConnectionManager] cancelling existing reconnect timer"
+				clearTimeout @timeoutId
+				@timeoutId = null
+
 		decreaseCountdown: () ->
+			@timeoutId = null
 			return if !@$scope.connection.reconnection_countdown?
+			sl_console.log "[ConnectionManager] decreasing countdown", @$scope.connection.reconnection_countdown
 			@$scope.$apply () =>
 				@$scope.connection.reconnection_countdown--


Fix triggering autocompile in rollout

Fix triggering autocompile in rollout

--- services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
+++ services/web/public/coffee/ide/pdf/controllers/PdfController.coffee
@@ -109,7 +109,7 @@
 				toggleAutoCompile(newValue)
 				event_tracking.sendMB "autocompile-setting-changed", { value: newValue }

-		if (window.user?.betaProgram or window.showAutoCompileOnboarding) and $scope.autocompile_enabled
+		if (window.user?.betaProgram or window.autoCompileEnabled) and $scope.autocompile_enabled
 			toggleAutoCompile(true)

 		# abort compile if syntax checks fail


remove the renderTimer

remove the renderTimer

only display the page when it is fully rendered

--- services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee
@@ -226,11 +226,6 @@
 					navigateFn: @navigateFn
 				})

-				renderTimer = setTimeout () ->
-					renderTimer = null
-					element.canvas.replaceWith(canvas)
-				, 1000
-
 				# console.log 'staring page render', pagenum

 				result = page.render {
@@ -250,9 +245,7 @@

 				result.then () ->
 					# console.log 'page rendered', pagenum
-					if renderTimer?
-						element.canvas.replaceWith(canvas)
-						clearTimeout renderTimer
+					element.canvas.replaceWith(canvas)
 					$timeout.cancel(timer)
 					canvas.removeClass('pdfng-rendering')
 					page.getTextContent().then (textContent) ->


Fix replying to a post

Fix replying to a post

--- lib/assets/javascripts/views/post/002_new_post_form.js.coffee
+++ lib/assets/javascripts/views/post/002_new_post_form.js.coffee
@@ -241,8 +241,9 @@
           break
       unless existing
         mentions.push { entity: attrs.mentions_post_entity, post: attrs.mentions_post_id }
-        delete attrs.mentions_post_entity
-        delete attrs.mentions_post_id
+
+    delete attrs.mentions_post_entity
+    delete attrs.mentions_post_id

     attrs.mentions = mentions if mentions.length


Fix runtime error range detection within threads and repeated error types in messages

--- app/lib/aether/problems.coffee
+++ app/lib/aether/problems.coffee
@@ -254,14 +254,14 @@
 extractRuntimeErrorDetails = (options) ->
   if error = options.error
     options.kind ?= error.name  # I think this will pick up [Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, DOMException]
-
-    if options.aether.options.useInterpreter
-      options.message = error.toString()
-    else
-      options.message = error.message or error.toString()
+    options.message = error.message or error.toString()
     options.hint = error.hint or getRuntimeHint options
     options.level ?= error.level
     options.userInfo ?= error.userInfo
+    if error.range and not options.range
+      if _.isNumber(error.range[0]) and _.isNumber(error.range[1]) and error.range[0] < options.aether.raw.length  # Lua doesn't have good range info for some reason
+        range = ranges.offsetsToRange(error.range[0], error.range[1], options.aether.raw or '')
+        options.range = [range.start, range.end]  # We expect array instead of object in options.range below

   # NOTE: lastStatementRange set via instrumentation.logStatementStart(originalNode.originalRange)
   options.range ?= options.aether?.lastStatementRange
@@ -269,7 +269,7 @@
     loc = options.aether?.esperEngine?.evaluator?.topFrame?.ast?.loc
     options.range ?= esperLocToAetherLoc loc

-  if options.error.name?
+  if options.error?.name? and not ///^#{options.error.name}///.test options.message
     options.message = "#{options.error.name}: #{options.message}"

   if options.range?
@@ -360,7 +360,7 @@
           if sm?
             newName = error.targetName.replace target, sm
             return "Look out for spelling issues: did you mean `#{newName}` instead of `#{error.targetName}`?"
-
+
         return "`#{ast.object.srcName}` has no method `#{ast.property.name}`."

     if (missingMethodMatch = message.match(/has no method '(.*?)'/)) or message.match(/is not a function/) or message.match(/has no method/)


Should also send empty colors on error

Should also send empty colors on error

--- components/GetColors.coffee
+++ components/GetColors.coffee
@@ -52,8 +52,8 @@
         colors = colors.map (color) -> "rgb(#{color[0]}, #{color[1]}, #{color[2]})"
     catch e
       out.canvas.send data
-      callback e
-      return
+      out.colors.send []
+      return callback e
     out.canvas.send data
     out.colors.send colors
     do callback


SendError: respect group ordering

SendError: respect group ordering

--- components/SendError.coffee
+++ components/SendError.coffee
@@ -1,5 +1,4 @@
 noflo = require 'noflo'
-express = require 'express'

 class SendError extends noflo.Component
   icon: 'warning'
@@ -14,19 +13,14 @@

     @inPorts.error.on 'data', (error) =>
       @_error = error
+      @sendError()

     @inPorts.in.on 'begingroup', (group) =>
       return unless @outPorts.out.isAttached()
       @outPorts.out.beginGroup group
     @inPorts.in.on 'data', (request) =>
       @request = request
-    @inPorts.in.on 'disconnect', () =>
-      return unless @request? and @_error?
-      request = @request
-      delete @request
-      request.res.send({ error: @_error.message })
-      return unless @outPorts.out.isAttached()
-      @outPorts.out.send(request)
+      @sendError()
     @inPorts.in.on 'endgroup', () =>
       return unless @outPorts.out.isAttached()
       @outPorts.out.endGroup()
@@ -34,4 +28,11 @@
       return unless @outPorts.out.isConnected()
       @outPorts.out.disconnect()

+  sendError: () ->
+    return unless @request? and @_error?
+    @request.res.send({ error: @_error.message })
+    @outPorts.out.send(@request) if @outPorts.out.isAttached()
+    @request = null
+    @_error = null
+
 exports.getComponent = -> new SendError


fix(long-poll): Turn delta sync back on

fix(long-poll): Turn delta sync back on

--- src/flux/inbox-api.coffee
+++ src/flux/inbox-api.coffee
@@ -83,9 +83,8 @@
         ## TODO use OfflineStatusStore
         Actions.longPollOffline()

-    connection.onDeltas (deltas) ->
-      # TODO DO NOT FORGET TO UNCOMMENT ME
-      # @_handleDeltas(deltas)
+    connection.onDeltas (deltas) =>
+      @_handleDeltas(deltas)

     connection.start()
     connection


fix(nylas-api): The _delta property was not correctly associated with deltas

--- src/flux/nylas-api.coffee
+++ src/flux/nylas-api.coffee
@@ -260,7 +260,7 @@
     # Create a (non-enumerable) reference from the attributes which we carry forward
     # back to their original deltas. This allows us to mark the deltas that the
     # app ignores later in the process.
-    for delta in deltas
+    deltas.forEach (delta) ->
       if delta.attributes
         Object.defineProperty(delta.attributes, '_delta', { get: -> delta })

@@ -350,7 +350,7 @@
     DatabaseStore = require './stores/database-store'
     DatabaseStore.findVersions(klass, ids).then (versions) ->
       accepted = accepted.filter (json) ->
-        if versions[json.id] >= json.version
+        if json.version and versions[json.id] >= json.version
           json._delta?.ignoredBecause = "This version (#{json.version}) is not newer. Already have (#{versions[json.id]})"
           return false
         return true


fix(nylas-api): Handle model responses with duplicate entries and warn, avoid guard assertion failure in DatabaseStore

--- src/flux/nylas-api.coffee
+++ src/flux/nylas-api.coffee
@@ -283,12 +283,18 @@

         Promise.settle(destroyPromises)

-  _handleModelResponse: (json) ->
+  _handleModelResponse: (jsons) ->
     new Promise (resolve, reject) =>
-      reject(new Error("handleModelResponse with no JSON provided")) unless json
-
-      json = [json] unless json instanceof Array
-      async.filter json
+      reject(new Error("handleModelResponse with no JSON provided")) unless jsons
+
+      jsons = [jsons] unless jsons instanceof Array
+
+      uniquedJSONs = _.uniq jsons, false, (model) -> model.id
+      if uniquedJSONs.length < jsons.length
+        console.warn("NylasAPI.handleModelResponse: called with non-unique object set.
+                     Maybe an API request returned the same object more than once?")
+
+      async.filter uniquedJSONs
       , (item, filterCallback) =>
         @_shouldAcceptModel(item.object, item).then (accept) ->
           filterCallback(accept)


switching setPeriods to use _change instead of setting store directly

--- src/flux/task-plan.coffee
+++ src/flux/task-plan.coffee
@@ -103,7 +103,7 @@
         tasking
       )

-    @_local[id].tasking_plans = tasking_plans
+    @_change(id, {tasking_plans})

     if not @exports.isNew(id)
       @_removeEmptyTaskings(id)


logic for exercises in task plan store/action

--- src/flux/task-plan.coffee
+++ src/flux/task-plan.coffee
@@ -20,7 +20,7 @@
     plan = @_getPlan(id)
     {page_ids, exercise_ids} = plan.settings
     page_ids = page_ids[..]
-    exercise_ids =exercise_ids[..]
+    exercise_ids = exercise_ids[..]
     @_change(id, {settings: {page_ids, exercise_ids, description}})

   updateOpensAt: (id, opens_at) ->
@@ -37,22 +37,41 @@

   addTopic: (id, topicId) ->
     plan = @_getPlan(id)
-    {page_ids} = plan.settings
+    {page_ids, exercise_ids, description} = plan.settings
     page_ids = page_ids[..] # Copy the page_ids so we can reset it back if clearChanged() is called

     page_ids.push(topicId) unless plan.settings.page_ids.indexOf(topicId) >= 0

-    @_change(id, {settings: {page_ids}})
+    @_change(id, {settings: {page_ids, exercise_ids, description}})

   removeTopic: (id, topicId) ->
     plan = @_getPlan(id)
-    {page_ids} = plan.settings
+    {page_ids, exercise_ids, description} = plan.settings
     page_ids = page_ids[..] # Copy the page_ids so we can reset it back if clearChanged() is called

     index = page_ids?.indexOf(topicId)
     page_ids?.splice(index, 1)

-    @_change(id, {settings : {page_ids}})
+    @_change(id, {settings: {page_ids, exercise_ids, description}})
+
+  addExercise: (id, exercise) ->
+    plan = @_getPlan(id)
+    {page_ids, exercise_ids, description} = plan.settings
+    exercise_ids = exercise_ids[..]
+
+    exercise_ids.push(exercise.id) unless plan.settings.exercise_ids.indexOf(exercise.id) >= 0
+
+    @_change(id, {settings: {page_ids, exercise_ids, description}})
+
+  removeExercise: (id, topicId) ->
+    plan = @_getPlan(id)
+    {page_ids, exercise_ids, description} = plan.settings
+    exercise_ids = exercise_ids[..]
+
+    index = exercise_ids?.indexOf(topicId)
+    exercise_ids?.splice(index, 1)
+
+    @_change(id, {settings: {page_ids, exercise_ids, description}})

   publish: (id) ->

@@ -65,7 +84,11 @@
       plan = @_getPlan(id)
       plan?.settings.page_ids

-    getProblems: (id) ->
+    hasExercise: (id, exerciseId) ->
+      plan = @_getPlan(id)
+      plan?.settings.exercise_ids?.indexOf(exerciseId) >= 0
+
+    getExercises: (id) ->
       plan = @_getPlan(id)
       plan?.settings.exercise_ids


enabled sot23-5 footprint

enabled sot23-5 footprint

--- src/footprints/sop.coffee
+++ src/footprints/sop.coffee
@@ -10,18 +10,20 @@
     pinsLeft = (data.pins + (if odd then 1 else 0)) / 2
     pinsRight = data.pins - pinsLeft

-    topLeftY = (pinsLeft-1) * data.e / 2 * -1
-    bottomRightY = (pinsRight-1) * data.e / 2
+    leftPitch = data.e
+    rightPitch = if data.pins == 5 then data.e*2 else data.e
+    topLeftY = (pinsLeft-1) * leftPitch / 2 * -1
+    bottomRightY = (pinsRight-1) * rightPitch / 2
     #Left pads run down the left
     #Right pads run up the right
     ret.pads = [0...pinsLeft].map (a) ->
       num: data.rename?[a] || a+1
-      location: [padData.X.offset*-1, topLeftY + a*data.e]
+      location: [padData.X.offset*-1, topLeftY + a*leftPitch]
       size: [padData.X.padLength, padData.X.padWidth]
       square: true
     .concat [0...pinsRight].map (a) ->
       num: data.rename?[a+pinsLeft] || a+pinsLeft+1
-      location: [padData.X.offset, bottomRightY - a*data.e]
+      location: [padData.X.offset, bottomRightY - a*rightPitch]
       size: [padData.X.padLength, padData.X.padWidth]
       square: true


Added curated section to user schema

Added curated section to user schema

--- app/schemas/models/user.coffee
+++ app/schemas/models/user.coffee
@@ -107,7 +107,47 @@
         name: {type: 'string', maxLength: 30, title: 'Link Name', description: 'What are you linking to? Ex: "Personal Website", "GitHub"', format: 'link-name'}
         link: c.url {title: 'Link', description: 'The URL.', default: 'http://example.com'}
     photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image if you want to show a different profile picture to employers than your normal avatar.'}
-
+
+    curated: c.object {title: 'Curated', required: ['mainTag','location','education','workHistory','phoneScreenFilter','schoolFilter','locationFilter','roleFilter','seniorityFilter']},
+      mainTag:
+        title: 'Main tag'
+        description: 'A main tag to describe this candidate'
+        type: 'string'
+      location:
+        title: 'Location'
+        description: "The CURRENT location of the candidate"
+        type: 'string'
+      education:
+        title: 'Education'
+        description: 'The main educational institution of the candidate'
+        type: 'string'
+      workHistory: c.array
+        title: 'Work history'
+        description: 'One or two places the candidate has worked'
+        type: 'array'
+      ,
+        title: 'Workplace'
+        type: 'string'
+      phoneScreenFilter:
+        title: 'Phone screened'
+        type: 'boolean'
+        description: 'Whether the candidate has been phone screened.'
+      schoolFilter:
+        title: 'School'
+        type: 'string'
+        enum: ['Top 20 Eng.', 'Other US', 'Other Intl.']
+      locationFilter:
+        title: 'Location'
+        type: 'string'
+        enum: ['Bay Area', 'New York', 'Other US', 'International']
+      roleFilter:
+        title: 'Role'
+        type: 'string'
+        enum: ['Web Developer', 'Software Developer', 'iOS Developer', 'Android Developer', 'Project Manager']
+      seniorityFilter:
+        title: 'Seniority'
+        type: 'string'
+        enum: ['College Student', 'Recent Grad', 'Junior', 'Senior', 'Management']
   jobProfileApproved: {title: 'Job Profile Approved', type: 'boolean', description: 'Whether your profile has been approved by CodeCombat.'}
   jobProfileNotes: {type: 'string', maxLength: 1000, title: 'Our Notes', description: "CodeCombat's notes on the candidate.", format: 'markdown', default: ''}
   employerAt: c.shortString {description: "If given employer permissions to view job candidates, for which employer?"}


removed repetitive algebraic conversion, added move method

--- app/scripts/chess/board.coffee
+++ app/scripts/chess/board.coffee
@@ -166,8 +166,10 @@
 	move: (x1, y1, x2, y2) ->
 		# TODO capture logic / points

-		# move the piece
-		@set(x2, y2, @get(x1,y1))
+		# move the piece and set flags
+		p = @get(x1, y1)
+		p.hasMoved = true
+		@set(x2, y2, p)

 		# clear the piece's old position
 		@set(x1, y1, new BlankPiece)


log params

log params

--- app/scripts/controllers.coffee
+++ app/scripts/controllers.coffee
@@ -250,7 +250,7 @@
   $scope.candidat_id = $stateParams.id
   console.log ("Candidatures : ")
   console.log($scope.candidat_id)
-  console.log(stateParams)
+  console.log($stateParams)
   # order
   # none = 1 | true = 2 | false = 3
   $scope.select_criteres = [


Ventanita de ayuda en Google Maps en vez de título.

--- app/scripts/google_maps.coffee
+++ app/scripts/google_maps.coffee
@@ -13,4 +13,7 @@
     marker = new google.maps.Marker
       position:  position
       map:       map
-      title:     $(this).attr("data-titulo")
+
+    infowindow = new google.maps.InfoWindow content: $(this).attr("data-titulo")
+
+    google.maps.event.addListener marker, 'click', -> infowindow.open map, marker


Improved input validation.

Improved input validation.

--- app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee
+++ app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee
@@ -184,7 +184,7 @@
     item = ''
     if config && App.UiElement[config.tag]
       config['name'] = name
-      if attribute.value[groupAndAttribute]
+      if attribute.value && attribute.value[groupAndAttribute]
         config['value'] = _.clone(attribute.value[groupAndAttribute]['value'])
       if 'multiple' of config
         config.multiple = true


Fix pointer coercion

Fix pointer coercion

--- src/type.coffee
+++ src/type.coffee
@@ -197,7 +197,7 @@
 PointerType::coerce = (expr) ->
   ty = expr.unwrapAll().computedType
   return expr unless ty instanceof PointerType and ty isnt this
-  normalizePtr expr, this.baseAlignment(), ty.baseAlignment()
+  normalizePtr expr, ty.baseAlignment(), this.baseAlignment()

 TypeArr::lint = (types) ->
   return this if @linted


teams: admin: permissions removed temp

teams: admin: permissions removed temp

--- client/admin/lib/index.coffee
+++ client/admin/lib/index.coffee
@@ -32,7 +32,7 @@
         { slug : 'General',        title : 'General',           viewClass : GroupGeneralSettingsView }
         { slug : 'Members',        title : 'Members',           viewClass : AdminMembersView         }
         { slug : 'Invitations',    title : 'Invitations',       viewClass : AdminInvitationsView     }
-        { slug : 'Permissions',    title : 'Permissions',       viewClass : GroupPermissionsView     }
+        # { slug : 'Permissions',    title : 'Permissions',       viewClass : GroupPermissionsView     }
         {
           slug      : 'Integrations'
           title     : 'Integrations'


Fix calling callback after writing of every file.

--- src/fs_utils/write.coffee
+++ src/fs_utils/write.coffee
@@ -31,6 +31,6 @@
   changed = files.filter (generatedFile) ->
     generatedFile.sourceFiles.some (sourceFile) ->
       sourceFile.cache.compilationTime > startTime
-  async.forEach changed, ((file) -> file.write callback), (error) ->
+  async.forEach changed, ((file, next) -> file.write next), (error) ->
     return callback error if error?
     callback null, changed


Add _.compact

Add _.compact

--- lib/util.coffee
+++ lib/util.coffee
@@ -1,6 +1,9 @@
 _ = require 'underscore'

 _.mixin
+
+  compact: (list) ->
+    _(list).select (item) -> item?

   opts: (args) ->
     if !args.length


EnvironmentMachineContainer: Pass force:true for fetchVMs which fixes the empty machine container issue when new vm created

--- client/app/Applications/Environments.kdapplication/views/scene/environmentmachinecontainer.coffee
+++ client/app/Applications/Environments.kdapplication/views/scene/environmentmachinecontainer.coffee
@@ -13,7 +13,7 @@

     vmc = KD.getSingleton 'vmController'
     cmd = if KD.checkFlag('nostradamus') then 'fetchGroupVMs' else 'fetchVMs'
-    vmc[cmd] (err, vms)=>
+    vmc[cmd] yes, (err, vms)=>
       if err or vms.length is 0
         @emit "DataLoaded"
         return warn "Failed to fetch VMs", err  if err


Improve UI #1

Improve UI #1

--- lib/view.coffee
+++ lib/view.coffee
@@ -6,26 +6,26 @@

 module.exports =
 class View extends SelectListView
-  # Copied from symbols-view's SymbolsView class
-  @highlightMatches: (context, name, matches, offsetIndex=0) ->
+  # Copied from FuzzzyFinder's and modified a little.
+  @highlightMatches: (context, path, matches, offsetIndex=0) ->
     lastIndex = 0
     matchedChars = [] # Build up a set of matched chars to be more semantic

     for matchIndex in matches
       matchIndex -= offsetIndex
-      continue if matchIndex < 0 # If marking up the basename, omit name matches
-      unmatched = name.substring(lastIndex, matchIndex)
+      continue if matchIndex < 0 # If marking up the basename, omit path matches
+      unmatched = path.substring(lastIndex, matchIndex)
       if unmatched
         context.span matchedChars.join(''), class: 'character-match' if matchedChars.length
         matchedChars = []
         context.text unmatched
-      matchedChars.push(name[matchIndex])
+      matchedChars.push(path[matchIndex])
       lastIndex = matchIndex + 1

     context.span matchedChars.join(''), class: 'character-match' if matchedChars.length

     # Remaining characters are plain text
-    context.text name.substring(lastIndex)
+    context.text path.substring(lastIndex)

   initialize: ->
     super
@@ -39,12 +39,15 @@
     this

   viewForItem: (item) ->
+    matches  = match(item, @getFilterQuery())
     basename = path.basename(item)
-    matches = match(basename, @getFilterQuery())
     $$ ->
+      baseOffset = item.length - basename.length
       @li class: 'two-lines', =>
-        @div class: 'primary-line', => View.highlightMatches(this, basename, matches)
-        @div item, class: 'secondary-line'
+        @div class: "primary-line file icon icon-repo", 'data-name': basename, 'data-path': item, =>
+          View.highlightMatches(this, basename, matches, baseOffset)
+        @div class: 'secondary-line path no-icon', =>
+          View.highlightMatches(this, item, matches)

   getItems: ->
     loadedPaths = atom.project.getPaths()


fix booleans

fix booleans

--- src/core.coffee
+++ src/core.coffee
@@ -19,7 +19,7 @@
   #  n: number
   #  s: string
   #  i: identifier
-  create_type n, lead.type for n in "pfqbi"
+  create_type n, lead.type for n in "pfqi"

   lead.type.f::to_target_string = ->
     [name, args...] = @values
@@ -35,12 +35,12 @@
   lead.type.q::to_js_string = ->
     "q(#{(@values.map JSON.stringify).join ', '})"

-  # numbers and strings both use json serialization
+  # numbers, strings, and booleans use json serialization
   lead.type.p::to_js_string =
   lead.type.p::to_target_string = ->
     JSON.stringify @values[0]

-  create_type n, lead.type.p for n in "ns"
+  create_type n, lead.type.p for n in "nsb"

   # Graphite doesn't support escaped quotes in strings, so avoid including any if possible.
   lead.type.s::to_target_string = ->


:speak_no_evil:

--- spec/fixtures/packages/package-with-activation-events/index.coffee
+++ spec/fixtures/packages/package-with-activation-events/index.coffee
@@ -10,5 +10,4 @@
   activate: ->
     @activateCallCount++
     rootView.getActiveView()?.command 'activation-event', =>
-      console.log "ACTIVATION EVENT"
       @activationEventCallCount++


Use Array#join and make code simpler

Use Array#join and make code simpler

--- app/assets/javascripts/admin/utils/services/errors_parser.js.coffee
+++ app/assets/javascripts/admin/utils/services/errors_parser.js.coffee
@@ -7,19 +7,14 @@
       errorsString = ""
       if errors.length > 0
         # it is an array of errors
-        errorsString = this.arrayToString(errors)
+        errorsString = errors.join("\n")
       else
         # it is a hash of errors
         keys = Object.keys(errors)
         for key in keys
-          errorsString += this.arrayToString(errors[key])
+          errorsString += errors[key].join("\n") + "\n"

       this.defaultIfEmpty(errorsString, defaultContent)
-
-    arrayToString: (array) =>
-      string = ""
-      string += entry + "\n" for entry in array
-      string

     defaultIfEmpty: (content, defaultContent) =>
       return defaultContent if content == ""


Remove unused function

Remove unused function

--- lib/pg-hoff-list-servers-view.coffee
+++ lib/pg-hoff-list-servers-view.coffee
@@ -8,10 +8,6 @@
     constructor: (serializedState) ->
         @element = document.createElement('div')
         @element.classList.add 'pg-hoff-list-servers'
-
-    escapeKeyCaptured: () ->
-        if @reject
-            @reject('Escape key captured')

     connect: (panel) ->
         listServersView = @


Last reference to profile

Last reference to profile

--- apps/show2/client/index.coffee
+++ apps/show2/client/index.coffee
@@ -11,6 +11,7 @@
 attachRelatedShows = require '../components/related_shows/index.coffee'
 FurtherArtworksView = require '../components/artwork_columns_metaphysics/view.coffee'
 FurtherInstallShotsView = require '../components/flickity_zoom_sequence/view.coffee'
+Profile = require '../../../models/profile.coffee'

 module.exports.init = ->
   bootstrappedShow = sd.PARTNER_SHOW
@@ -25,7 +26,7 @@
     new FurtherInstallShotsView showId: bootstrappedShow._id, page: 2, installShots: bootstrappedShow.install_shots, el: furtherInstallShotsEl

   attachFollowArtists bootstrappedShow.artists
-  attachFollowProfile bootstrappedShow.partner.profile
+  attachFollowProfile new Profile id: bootstrappedShow.partner.default_profile_id

   $('.js-open-map-modal').click (e) ->
     e.preventDefault()


Use Node's readline module in the CoffeeScript wordcount script'

--- coffeescript/wordcount.coffee
+++ coffeescript/wordcount.coffee
@@ -1,15 +1,12 @@
-split = require 'split'
+reader = require('readline').createInterface process.stdin, null
 {XRegExp} = require 'xregexp'
-
 counts = Object.create null

-process.stdin.setEncoding 'utf8'
-
-process.stdin.pipe(split()).on 'data', (line) ->
+reader.on 'line', (line) ->
   wordPattern = XRegExp("[\\p{L}']+", 'g')
   for word in (line.toLowerCase().match(wordPattern) or [])
     counts[word] = (counts[word] or 0) + 1

-process.stdin.on 'end', ->
+reader.on 'end', ->
   for word in Object.keys(counts).sort()
     console.log "#{word} #{counts[word]}"


Add missing ships.

Add missing ships.

--- coffeescripts/cards-de.coffee
+++ coffeescripts/cards-de.coffee
@@ -558,6 +558,9 @@
             ship: "T-70-X-Flügler"
             name: '"Ass Blau"'
             text: """Soabld du eine Schub-Aktion ausführst, darfst du das Manöver (%TURNLEFT% 1) oder (%TURNRIGHT% 1) verwenden."""
+        '"Red Ace"':
+            ship: "T-70-X-Flügler"
+            text: '''The first time you remove a shield token from your ship each round, assign 1 evade token to your ship.'''
         "Blue Squadron Novice":
             ship: "T-70-X-Flügler"
             name: "Anfängerpilot der Blauen Staffel"
@@ -586,9 +589,8 @@
         "Epsilon Squadron Pilot":
             ship: "TIE/EO-Jäger"
             name: "Pilot der Epsilon-Staffel"
-        '"Red Ace"':
-            text: '''The first time you remove a shield token from your ship each round, assign 1 evade token to your ship.'''
         '"Omega Leader"':
+            ship: "TIE/EO-Jäger"
             text: '''Enemy ships that you have locked cannot modify any dice when attacking you or defending against your attacks.'''

     upgrade_translations =


add hostelworld init procedure to rooms manager

--- vendor/assets/javascripts/lib/managers/lp_rooms_manager.coffee
+++ vendor/assets/javascripts/lib/managers/lp_rooms_manager.coffee
@@ -8,6 +8,7 @@
       button = form.find('.booking-form-submit button')
       container = $('.booking-section')
       list = $('.rooms')
+      hostelWorldAvailability = new window.lp.HostelworldAvailability()

       form.on 'ajax:before', ->
         list.slideUp 400, ->
@@ -20,6 +21,7 @@

         NightlyRatesManager.init()
         RateDisclaimerManager.init()
+        hostelWorldAvailability.init(target: '#hostelworld-rooms')
         Popup.init()

         list.slideDown()


embedly: fix xss vulnerabilities

embedly: fix xss vulnerabilities

--- client/app/Applications/Activity.kdapplication/views/embedboxviews.coffee
+++ client/app/Applications/Activity.kdapplication/views/embedboxviews.coffee
@@ -422,7 +422,7 @@

     @hide()  unless oembed?.description?.trim()

-    @originalDescription = oembed?.description
+    @originalDescription = Encoder.XSSEncode oembed?.description or ""

     if options.hasConfig is yes
       @setClass 'has-config'
@@ -430,7 +430,7 @@
         type         : 'textarea'
         cssClass     : 'description_input hidden'
         name         : 'description_input'
-        defaultValue : oembed?.description or ''
+        defaultValue : @originalDescription
         autogrow     : yes
         blur         : =>
           @descriptionInput.hide()
@@ -438,21 +438,21 @@
     else
       @descriptionInput = new KDCustomHTMLView
         cssClass : 'hidden'
-        partial : oembed?.description or ''
+        partial : @originalDescription

     @editIndicator = new KDCustomHTMLView
       tagName : 'div'
       cssClass : 'edit-indicator discussion-edit-indicator'
       pistachio : 'edited'
       tooltip :
-        title: "Original Content was:
#{oembed?.original_description or oembed?.description or ''}
"
+        title: "Original Content was:
#{oembed?.original_description or @original_description}
"
     @editIndicator.hide()

   getValue:->
     if @options.hasConfig
-      @descriptionInput.getValue()
+      Encoder.XSSEncode @descriptionInput.getValue()
     else
-      @descriptionInput.getPartial()
+      Encoder.XSSEncode @descriptionInput.getPartial()

   getOriginalValue:-> @originalDescription

@@ -471,10 +471,17 @@
     @$('div.description').hide()
     no

+  getDescription:->
+    value = @getData().link_embed?.description or @getData().description
+    if value?
+      value = Encoder.XSSEncode value
+
+    return value
+
   pistachio:->
     """
     {{> @descriptionInput}}
-
#{@getData().link_embed?.description or @getData().description or ''}
+
#{@getDescription() or ""}
     {{> @editIndicator}}

     """


Catch any parsing errors - fixes #6

Catch any parsing errors - fixes #6

--- src/htmlmin.plugin.coffee
+++ src/htmlmin.plugin.coffee
@@ -46,7 +46,10 @@
         htmlminOptions[key] = value for own key,value of templateData.document.htmlmin if templateData.document.htmlmin

         # Render
-        opts.content = @htmlmin(opts.content, htmlminOptions);
+        try
+          opts.content = @htmlmin(opts.content, htmlminOptions);
+        catch err
+          return next(err)

       # Done, return back to DocPad
       return next()


Translate shortcut.

Translate shortcut.

--- packages/landsofillusions-assets/mesheditor/mesheditor.coffee
+++ packages/landsofillusions-assets/mesheditor/mesheditor.coffee
@@ -247,6 +247,7 @@
       "#{LOI.Assets.MeshEditor.Tools.Eraser.id()}": key: AC.Keys.e
       "#{LOI.Assets.SpriteEditor.Tools.ColorFill.id()}": null
       "#{LOI.Assets.MeshEditor.Tools.ColorFill.id()}": key: AC.Keys.g
+      "#{LOI.Assets.MeshEditor.Tools.Translate.id()}": key: AC.Keys.v

   constructor: ->
     super arguments...


Set the timout to 15 seconds

Set the timout to 15 seconds

--- admin/static/coffee/app.coffee
+++ admin/static/coffee/app.coffee
@@ -168,7 +168,7 @@
                 window.is_disconnected.display_fail()
             else
                 window.is_disconnected = new IsDisconnected
-        timeout: updateInterval*2
+        timeout: updateInterval*3

 collect_progress = ->
     $.ajax


MachineSettingsCommonView: Add loader to button.

--- client/app/lib/providers/machinesettingscommonview.coffee
+++ client/app/lib/providers/machinesettingscommonview.coffee
@@ -62,8 +62,9 @@

     wrapper = new KDCustomHTMLView cssClass: 'buttons'

-    wrapper.addSubView new KDButtonView
+    wrapper.addSubView @addNewButton = new KDButtonView
       cssClass : 'solid green compact add'
+      loader   : yes
       title    : @getOptions().addButtonTitle
       callback : @bound 'handleAddNew'


remove sort param from api call

remove sort param from api call

--- routes/pocketApi.coffee
+++ routes/pocketApi.coffee
@@ -43,7 +43,6 @@
         "state" : "all"
         "consumer_key" : pocketOAuth.consumerKey,
         "access_token" : pocketOAuth.accessToken,
-        "sort" : "oldest",
         "count" : MAX_ARTICLES_PER_CALL,
         "offset" : offset
     }


cleanup

cleanup

--- client/apps/edit/components/section_artworks/index.coffee
+++ client/apps/edit/components/section_artworks/index.coffee
@@ -78,8 +78,7 @@
     @prevLength = @props.section.artworks.length

   fillwidth: ->
-    $(@refs.artworks.getDOMNode()).fillwidthLite
-      gutterSize: 20
+    $(@refs.artworks.getDOMNode()).fillwidthLite gutterSize: 20

   removeFillwidth: ->
     $(@refs.artworks.getDOMNode()).find('img').css(width: '')


guestCleanerWorker: Added JName removal.

--- workers/guestcleaner/lib/guestcleaner/guestcleanerwoker.coffee
+++ workers/guestcleaner/lib/guestcleaner/guestcleanerwoker.coffee
@@ -7,7 +7,7 @@
   {Relationship} = jraphical
   constructor: (@bongo, @options = {}) ->

-  whitlistedModels = ["JSession", "JUser", "JVM", "JDomain", "JAppStorage", "JLimit"]
+  whitlistedModels = ["JSession", "JUser", "JVM", "JDomain", "JAppStorage", "JLimit", "JName"]

   collectDataAndRelationships:(relationships, callback)->
     toBeDeletedData = {}
@@ -41,7 +41,7 @@
       deleteEntry {ids: ids, modelName: modelName}

   clean:=>
-    {JAccount, JSession} = @bongo.models
+    {JAccount, JSession, JName} = @bongo.models

     usageLimitInMinutes = @options.usageLimitInMinutes or 60
     filterDate = new Date(Date.now()-(1000*60*usageLimitInMinutes))
@@ -103,6 +103,11 @@
               JSession.remove {guestId:guestId},(err)->
                 if err then console.error err
                 queue.next()
+            =>
+              #If we don't delete JNames, we eventually have millions of them.
+              JName.remove {name : account.profile.nickname},(err)->
+                if err then console.error err
+                queue.next()
             ->
               #Delete JAccount itself
               account.remove (err)->


bugfix: revert this mongo query

bugfix: revert this mongo query

+ it was actually correct before

--- workers/social/lib/social/models/chatconversation/index.coffee
+++ workers/social/lib/social/models/chatconversation/index.coffee
@@ -37,7 +37,7 @@

   @fetch = secure (client, publicName, callback)->
     {delegate} = client.connection
-    @one { publicName, invitees: $in: [delegate.profile.nickname] }, callback
+    @one { publicName, invitees: delegate.profile.nickname }, callback

   @fetchSome = secure (client, options, callback)->
     [callback, options] = [options, callback] unless callback


Fixes minor global scoping bug.

Fixes minor global scoping bug.

--- lib/atom-symbol-navigation.coffee
+++ lib/atom-symbol-navigation.coffee
@@ -33,30 +33,33 @@

         #found an identifier at the cursor, so return pos of next
         if cursorIds.length != 0
-          references = identifiers.filter (node) ->
+          usages = identifiers.filter (node) ->
             node.name == cursorIds[0].name

-          index = references.indexOf cursorIds[0]
-          return references[(references.length + index + params.skip) %
-                                        references.length].loc
+          index = usages.indexOf cursorIds[0]
+          return usages[(usages.length + index + params.skip) %
+                                        usages.length].loc
     return null

   #get list of identifiers in the given scope
   getIdentifiersInScope: (scope) ->
     estraverse = require('estraverse')
+    identifiers = []
+
+    #we want to include variables that aren't resolved in this scope
+    #this would be the case, for instance, if we are referencing a
+    #global from within a function.
+    for ref in scope.through
+      identifiers.push ref.identifier

     #we include both references and definitions of the identifiers
-    identifiers = []
+    #TODO: really need to cache this call, pretty inefficient.
     for ref in scope.references
       identifiers.push ref.identifier
+
       if ref.resolved
-        for def in ref.resolved.defs
-          switch(def.type)
-            when 'Variable' then identifiers.push def.node.id
-            when 'FunctionName' then identifiers.push def.node.id
-            when 'CatchClause' then identifiers.push def.node.param
-            when 'Parameter' then identifiers.concat def.node.params
-            else console.error("unknown type: #{def.node.type}")
+        for varRef in ref.resolved.references
+          identifiers.push varRef.identifier

     #get rid of duplicates, and sort by position
     identifiers = identifiers.filter (item, index) ->


Crytical overlook FIX #2

Crytical overlook FIX #2


Have modal dismiss with cancel event by default

--- www/js/views/modal.coffee
+++ www/js/views/modal.coffee
@@ -20,6 +20,9 @@
     _el: '#modal-content'
     fixedContent: ''
     isFullModal: false
+
+    events:
+      "click .cancel": "dismiss"

     # Load the fixed content and template HTML into the modal, then add it to
     # the body of the page.


Call deprecate not deprecated

Call deprecate not deprecated

--- src/keymap-manager.coffee
+++ src/keymap-manager.coffee
@@ -171,17 +171,17 @@
   on: (eventName) ->
     switch eventName
       when 'matched'
-        Grim.deprecated("Call KeymapManager::onDidMatchBinding instead")
+        Grim.deprecate("Call KeymapManager::onDidMatchBinding instead")
       when 'matched-partially'
-        Grim.deprecated("Call KeymapManager::onDidPartiallyMatchBinding instead")
+        Grim.deprecate("Call KeymapManager::onDidPartiallyMatchBinding instead")
       when 'match-failed'
-        Grim.deprecated("Call KeymapManager::onDidFailToMatchBinding instead")
+        Grim.deprecate("Call KeymapManager::onDidFailToMatchBinding instead")
       when 'reloaded-key-bindings'
-        Grim.deprecated("Call KeymapManager::onDidReloadKeymap instead")
+        Grim.deprecate("Call KeymapManager::onDidReloadKeymap instead")
       when 'unloaded-key-bindings'
-        Grim.deprecated("Call KeymapManager::onDidUnloadKeymap instead")
+        Grim.deprecate("Call KeymapManager::onDidUnloadKeymap instead")
       else
-        Grim.deprecated("Use explicit event subscription methods instead")
+        Grim.deprecate("Use explicit event subscription methods instead")

     EmitterMixin::on.apply(this, arguments)


Data script: don’t block when reading; better ||ization.

--- scripts/normalize-data._coffee
+++ scripts/normalize-data._coffee
@@ -79,7 +79,7 @@

     # Massage the data by reading it, modifying it, then writing it back.
     # NOTE: This assumes full knowledge of the starting data.
-    data = require idPath   # require() auto-parses JSON!
+    data = JSON.parse FS.readFile idPath, 'utf8', _
     failed = not (data.width and data.height and data.tileSize) and
         # if we're re-running this after our conversion:
         not (data.dzi?.width and data.dzi?.height and data.dzi?.tileSize)


further modifications needed for cassandra 2.0 support (basically undoing the new data type support)

--- salvus/cassandra.coffee
+++ salvus/cassandra.coffee
@@ -406,6 +406,12 @@
         value = value.toInt()     # long type
     else if value instanceof cql.types.BigDecimal
         value = value.toNumber()
+    else if value instanceof Array # a set/list collection -- http://www.datastax.com/documentation/developer/nodejs-driver/2.0/nodejs-driver/reference/collections.html
+        value = (from_cassandra(x) for x in value)
+    else if value.constructor == Object # a map collection
+        x = {}
+        for k, v of value
+            x[k] = from_cassandra(v)
     else
         value = value.valueOf()
         if json


add comment to clarify blockchain config

--- src/lib/blockchain.coffee
+++ src/lib/blockchain.coffee
@@ -33,6 +33,7 @@

         cacheTTL: gConf.get('redis:blockchain:ttl')

+        # return @(this) upon successful load, falsy otherwise
         config: ->
             #@log.debug 'Loading #{@name} resolver'
             #load config


minor favoriting bug fix

minor favoriting bug fix

--- app/annotation/annotation.cjsx
+++ app/annotation/annotation.cjsx
@@ -93,7 +93,7 @@
     if @state.favorited is false
       favorite.send().then => @setState favorited: true
     else
-      favorite.delete().then => @setState favorited: true
+      favorite.delete().then => @setState favorited: false

   modifyOverlay: ->
     @overlay.addEventListener 'click', @closeZoom


Fix check for next task

Fix check for next task

--- app/classifier/classifier.cjsx
+++ app/classifier/classifier.cjsx
@@ -36,8 +36,8 @@
   renderTaskArea: (annotation, task, currentTool) ->
     onFirstTask = @props.classification.annotations.length is 1
     needsAnswer = task.required and not annotation.answer?
-    nextTaskKey = annotation.answer?.next ? task.next
-    canGoForward = nextTaskKey?
+    nextTaskKey = annotation._answer?.next ? task.next
+    canGoForward = needsAnswer or nextTaskKey?

     <div className="classifier-task">
       <TaskViewer task={task} annotation={annotation} selectedDrawingTool={currentTool} onChange={@handleAnswer} />
@@ -58,6 +58,7 @@
         @setState selectedDrawingTool: answer
       else
         @getAnnotation().answer = answer.value
+        @getAnnotation()._answer = answer
         @props.classification.emit 'change'

   loadTask: (task) ->


Small refactor.

Small refactor.

--- app/client/js/react/app.coffee
+++ app/client/js/react/app.coffee
@@ -23,9 +23,12 @@
       render: ->
         div className: 'app',
           header.create()
-          switch routes.active
-            when routes.home then home.create()
-            when routes.myNewSong, routes.editMySong then editSong.create()
-            when routes.mySong then song.create()
-            when routes.notFound then notFound.create()
-          footer.create()+          @activePage().create()
+          footer.create()
+
+      activePage: ->
+        switch routes.active
+          when routes.home then home
+          when routes.myNewSong, routes.editMySong then editSong
+          when routes.mySong then song
+          when routes.notFound then notFound


Implement docker based latex compilation.

Implement a docker based command runner that runs compilation in a docker container, for added isolation and security.

This implementation also supports timeouts.

--- app/coffee/DockerRunner.coffee
+++ app/coffee/DockerRunner.coffee
@@ -1,10 +1,12 @@
 spawn = require("child_process").spawn
 exec  = require("child_process").exec
 logger = require "logger-sharelatex"
+Settings = require "settings-sharelatex"
+

 module.exports = DockerRunner =
   _docker: 'docker'
-  _baseCommand: ['run', '--rm=true', '-t', '-v', '$COMPILE_DIR:/source', '--name=texlive-$PROJECT_ID', 'texlive']
+  _baseCommand: ['run', '--rm=true', '-t', '-v', '$COMPILE_DIR:/source', '--name=texlive-$PROJECT_ID']

   run: (project_id, command, directory, timeout, callback = (error) ->) ->
     logger.log project_id: project_id, command: command, directory: directory, "running docker command"
@@ -14,13 +16,14 @@

     docker_cmd = (arg.replace('$COMPILE_DIR', directory).replace('$PROJECT_ID', project_id) \
       for arg in DockerRunner._baseCommand)
+    docker_cmd.push Settings.clsi?.docker?.image or "texlive"
     docker_cmd = docker_cmd.concat (arg.replace('$COMPILE_DIR', '/source') for arg in command.slice(1))

     proc = spawn DockerRunner._docker, docker_cmd, stdio: "inherit", cwd: directory
     timer = setTimeout timeout, () ->
       logger.warn "timeout achieved, stopping docker instance"
       exec 'docker', ['stop', "texlive-#{project_id}"]
-      callback 'Compilation failed, timeout'
+      callback {timedout: true}
     proc.on "close", () ->
       clearTimeout timer
       callback()


fix mongo logic for project search with packs

--- app/coffee/MongoManager.coffee
+++ app/coffee/MongoManager.coffee
@@ -168,8 +168,10 @@

 		sort = {}
 		sort['meta.end_ts'] = -1;
+
+		projection = {"op":false, "pack.op": false}
 		cursor = db.docHistory
-			.find( query, {"op":false, "pack.op": false} ) # no need to return the op only need version info
+			.find( query, projection ) # no need to return the op only need version info
 			.sort( sort )
 		# if we have packs, we will trim the results more later after expanding them
 		if limit?
@@ -179,7 +181,6 @@
 		before = query['meta.end_ts']?['$lt']  # may be null

 		updates = [] # used to accumulate the set of results
-		extraQuery = _.clone(query)

 		cursor.toArray (err, result) ->
 			if err?
@@ -192,54 +193,84 @@
 				unpackedSet = unpackedSet.slice(0, limit)
 			# find the end time of the last result, we will take all the
 			# results up to this, and then all the changes at that time
-			# (without imposing a limit)
-			cutoff = if unpackedSet.length then unpackedSet[unpackedSet.length-1].meta.end_ts else before
+			# (without imposing a limit) and any overlapping packs
+			cutoff = if unpackedSet.length then unpackedSet[unpackedSet.length-1].meta.end_ts else null
 			console.log 'before is', before
 			console.log 'cutoff is', cutoff
 			console.log 'limit  is', limit

 			filterFn = (item) ->
 				ts = item?.meta?.end_ts
+				console.log 'checking', ts, before, cutoff
 				return false if before? && ts >= before
 				return false if cutoff? && ts < cutoff
 				return true

 			updates = MongoManager._filterAndLimit(updates, unpackedSet, filterFn, limit)
 			console.log 'initial updates are', updates
-			# now find any extra entries which are exactly at the last time (cutoff)
-			# or in packs that overlap it
-			extraQuery['meta.end_ts'] = {"$gte": +cutoff}
-			extraQuery['meta.start_ts'] = {"$lte": +cutoff}
-			# we don't specify a limit here, as there could be any number of
-			# docs at that timestamp
-			#
+
+			# get all elements on the lower bound (cutoff)
+			tailQuery = _.clone(query)
+			tailQuery['meta.end_ts'] = cutoff
+			tail = db.docHistory
+				.find(tailQuery, projection)
+				.sort(sort)
+
+			console.log 'tailQuery is', tailQuery
+
+			# now find any packs that overlap with the time window
+			overlapQuery = _.clone(query)
+			if before? && cutoff?
+				overlapQuery['meta.end_ts'] = {"$gte": before}
+				overlapQuery['pack.0.meta.end_ts'] = {"$lte": before }
+			else if before? && not cutoff?
+				overlapQuery['meta.end_ts'] = {"$gte": before}
+				overlapQuery['pack.0.meta.end_ts'] = {"$lte": before }
+			else if not before? && cutoff?
+				overlapQuery['meta.end_ts'] = {"$gte": cutoff}
+				overlapQuery['pack.0.meta.end_ts'] = {"$gte": 0 }
+			else if not before? && not cutoff?
+				overlapQuery['meta.end_ts'] = {"$gte": 0 }
+				overlapQuery['pack.0.meta.end_ts'] = {"$gte": 0 }
+			overlap = db.docHistory
+				.find(overlapQuery, projection)
+				.sort(sort)
+
+			console.log 'overlapQuery is', overlapQuery
+
+			# we don't specify a limit here, as there could be any number of overlaps
 			# NB. need to catch items in original query and followup query for duplicates
-			console.log 'extraQuery is', extraQuery
-			extra = db.docHistory
-				.find(extraQuery, {"op": false, "pack.op": false})
-				.sort(sort)
-			extra.toArray (err, result2) ->
-				console.log 'got extra result', err, result
+
+			applyAndUpdate = (result) ->
+				extraSet = MongoManager._unpackResults(result)
+				# note: final argument is null, no limit applied because we
+				# need all the updates at the final time to avoid breaking
+				# the changeset into parts
+				updates = MongoManager._filterAndLimit(updates, extraSet, filterFn, null)
+				console.log 'extra updates after filterandlimit', updates
+				# remove duplicates
+				seen = {}
+				updates = updates.filter (item) ->
+					key = item.doc_id + ' ' + item.v
+					console.log 'key is', key
+					if seen[key]
+						return false
+					else
+						seen[key] = true
+						return true
+				console.log 'extra updates are', updates
+
+			tail.toArray (err, result2) ->
 				if err?
 					return callback err, updates
 				else
-					extraSet = MongoManager._unpackResults(result2)
-					# note: final argument is null, no limit applied because we
-					# need all the updates at the final time to avoid breaking
-					# the changeset into parts
-					updates = MongoManager._filterAndLimit(updates, extraSet, filterFn, null)
-					# remove duplicates
-					seen = {}
-					updates = updates.filter (item) ->
-						key = item.doc_id + ' ' + item.v
-						console.log 'key is', key
-						if seen[key]
-							return false
+					applyAndUpdate result2
+					overlap.toArray (err, result3) ->
+						if err?
+							return callback err, updates
 						else
-							seen[key] = true
-					console.log 'extra updates are', updates
-					callback err, updates
-
+							applyAndUpdate result3
+							callback err, updates

 	_unpackResults: (updates) ->
 		#	iterate over the updates, if there's a pack, expand it into ops and


Initialize primaryResult to an array, not null

--- app/coffee/RedisBackend.coffee
+++ app/coffee/RedisBackend.coffee
@@ -124,7 +124,7 @@
 	do (command, key_pos) ->
 		Client.prototype[command] = (args..., callback) ->
 			primaryError = null
-			primaryResult = null
+			primaryResult = []
 			jobs = @clients.map (client) =>
 				(cb) =>
 					cb = _.once(cb)


Refactor: Use tgNavUrls to resolve some urls in auth module

--- app/coffee/modules/auth.coffee
+++ app/coffee/modules/auth.coffee
@@ -151,7 +151,7 @@
     ## Login Directive
     ###################

-LoginDirective = ($auth, $confirm, $location, $config, $routeParams) ->
+LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls) ->
     link = ($scope, $el, $attrs) ->
         $scope.pubblicRegisterEnabled = $config.get("pubblicRegisterEnabled")
         $scope.data = {}
@@ -161,10 +161,10 @@
             form = $el.find("form")

             form.attr("method", "POST")
-            if $routeParams['next'] and $routeParams['next'] != '/login'
+            if $routeParams['next'] and $routeParams['next'] != $navUrls.resolve("login")
                 form.attr("action", $routeParams['next'])
             else
-                form.attr("action", "/")
+                form.attr("action", $navUrls.resolve("home"))

             form.submit()

@@ -186,14 +186,15 @@

     return {link:link}

-module.directive("tgLogin", ["$tgAuth", "$tgConfirm", "$location", "$tgConfig", "$routeParams", LoginDirective])
+module.directive("tgLogin", ["$tgAuth", "$tgConfirm", "$location", "$tgConfig", "$routeParams", "$tgNavUrls",
+                             LoginDirective])

     ###################
     ## Register Directive
     ###################

-RegisterDirective = ($auth, $confirm, $location, $config) ->
+RegisterDirective = ($auth, $confirm, $location, $config, $navUrls) ->
     link = ($scope, $el, $attrs) ->
         $scope.privacyPolicyUrl = $config.get("privacyPolicyUrl")
         $scope.termsOfServiceUrl = $config.get("termsOfServiceUrl")
@@ -203,7 +204,7 @@

         onSuccessSubmit = (response) ->
             $confirm.notify("success", "Our Oompa Loompas are happy, wellcome to Taiga.") #TODO: i18n
-            $location.path("/")
+            $location.path($navUrls.resolve("home"))

         onErrorSubmit = (response) ->
             $confirm.notify("light-error", "According to our Oompa Loompas, the username or email is
@@ -226,20 +227,21 @@

     return {link:link}

-module.directive("tgRegister", ["$tgAuth", "$tgConfirm", "$location", "$tgConfig", RegisterDirective])
+module.directive("tgRegister", ["$tgAuth", "$tgConfirm", "$location", "$tgConfig", "$tgNavUrls",
+                                RegisterDirective])

     ###################
     ## Forgot Password Directive
     ###################

-ForgotPasswordDirective = ($auth, $confirm, $location) ->
+ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls) ->
     link = ($scope, $el, $attrs) ->
         $scope.data = {}
         form = $el.find("form").checksley()

         onSuccessSubmit = (response) ->
-            $location.path("/login") # TODO: Use the future 'urls' service
+            $location.path($navUrls.resolve("login"))
             $confirm.success("Check your inbox!

                              We have sent a mail to

                              #{response.data.email}

@@ -266,14 +268,15 @@

     return {link:link}

-module.directive("tgForgotPassword", ["$tgAuth", "$tgConfirm", "$location", ForgotPasswordDirective])
+module.directive("tgForgotPassword", ["$tgAuth", "$tgConfirm", "$location", "$tgNavUrls",
+                                      ForgotPasswordDirective])

     ###################
     ## Change Password from Recovery Directive
     ###################

-ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params) ->
+ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $navUrls) ->
     link = ($scope, $el, $attrs) ->
         $scope.data = {}

@@ -286,7 +289,7 @@
         form = $el.find("form").checksley()

         onSuccessSubmit = (response) ->
-            $location.path("/login") # TODO: Use the future 'urls' service
+            $location.path($navUrls.resolve("login"))
             $confirm.success("Our Oompa Loompas save your new password.

                               Try to sign in with it.") #TODO: i18n

@@ -312,14 +315,14 @@
     return {link:link}

 module.directive("tgChangePasswordFromRecovery", ["$tgAuth", "$tgConfirm", "$location", "$routeParams",
-                                                  ChangePasswordFromRecoveryDirective])
+                                                  "$tgNavUrls", ChangePasswordFromRecoveryDirective])

     ###################
     ## Invitation
     ###################

-InvitationDirective = ($auth, $confirm, $location, $params, $config) ->
+InvitationDirective = ($auth, $confirm, $location, $params, $config, $navUrls) ->
     link = ($scope, $el, $attrs) ->
         $scope.privacyPolicyUrl = $config.get("privacyPolicyUrl")
         $scope.termsOfServiceUrl = $config.get("termsOfServiceUrl")
@@ -331,7 +334,7 @@
             $scope.invitation = invitation

         promise.then null, (response) ->
-            $location.path("/login") # TODO: Use the future 'urls' service
+            $location.path($navUrls.resolve("login"))
             $confirm.success("Ooops, we have a problems

                               Our Oompa Loompas can't find your invitations.") #TODO: i18n

@@ -342,8 +345,7 @@
         loginForm = $el.find("form.login-form").checksley()

         onSuccessSubmitLogin = (response) ->
-            # TODO: finish this. Go to project home page
-            $location.path("/project/#{$scope.invitation.project_slug}/backlog")
+            $location.path($navUrls.resolve("project", {project: $scope.invitation.project_slug}))
             $confirm.notify("success", "You've successfully joined to this project",
                                        "Wellcome to #{$scope.invitation.project_name}")

@@ -373,8 +375,7 @@
         registerForm = $el.find("form.register-form").checksley()

         onSuccessSubmitRegister = (response) ->
-            # TODO: finish this. Go tu project home page
-            $location.path("/project/#{$scope.invitation.project_slug}/backlog")
+            $location.path($navUrls.resolve("project", {project: $scope.invitation.project_slug}))
             $confirm.notify("success", "You've successfully joined to this project",
                                        "Wellcome to #{$scope.invitation.project_name}")

@@ -400,13 +401,14 @@
     return {link:link}

 module.directive("tgInvitation", ["$tgAuth", "$tgConfirm", "$location", "$routeParams", "$tgConfig",
-                                  InvitationDirective])
+                                  "$tgNavUrls", InvitationDirective])
+

 ###################
 ## Change Email
 ###################

-ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params) ->
+ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $navUrls) ->
     link = ($scope, $el, $attrs) ->
         $scope.data = {}
         $scope.data.email_token = $params.email_token
@@ -415,11 +417,10 @@
         onSuccessSubmit = (response) ->
             $repo.queryOne("users", $auth.getUser().id).then (data) =>
                 $auth.setUser(data)
-                $location.path("/") # TODO: Use the future 'urls' service
+                $location.path($navUrls.resolve("home")) # TODO: Use the future 'urls' service
                 $confirm.success("Our Oompa Loompas updated your email") #TODO: i18n

         onErrorSubmit = (response) ->
-            console.log "ASDASDASDASD"
             $confirm.notify("error", "One of our Oompa Loompas says
                             '#{response.data._error_message}'.") #TODO: i18n

@@ -441,4 +442,4 @@
     return {link:link}

 module.directive("tgChangeEmail", ["$tgRepo", "$tgModel", "$tgAuth", "$tgConfirm", "$location", "$routeParams",
-                                                  ChangeEmailDirective])
+                                   "$tgNavUrls", ChangeEmailDirective])


Pass a project to collection subject viewer (#3314)

Should fix #1652

--- app/collections/show-list.cjsx
+++ app/collections/show-list.cjsx
@@ -48,7 +48,7 @@
   render: ->
     logClick = @context.geordi?.makeHandler? 'about-menu'
     <div className="collection-subject-viewer">
-      <SubjectViewer defaultStyle={false} subject={@props.subject} user={@props.user}>
+      <SubjectViewer defaultStyle={false} subject={@props.subject} user={@props.user} project={@state.project}>
         {if @isOwnerOrCollaborator()
           <button type="button" className="collection-subject-viewer-delete-button" onClick={@props.onDelete}>
             <i className="fa fa-close" />


сделал вывыд сессии, удалил папку lib

сделал вывыд сессии, удалил папку lib

--- app/controllers/sockets.coffee
+++ app/controllers/sockets.coffee
@@ -4,8 +4,6 @@
 module.exports = (server, middlevent) ->

 	sockets = sockjs.createServer()
-	# sockjs_url: global.home + '/lib/sockjs/sockjs.js'
-

 	sockets.on 'connection', (socket) ->


:lipstick:

:lipstick:

--- lib/project/results-model.coffee
+++ lib/project/results-model.coffee
@@ -28,7 +28,7 @@
   clear: ->
     @clearSearchState()
     @clearReplacementState()
-    @emit('cleared')
+    @emit('cleared', @getResultsSummary())

   clearSearchState: ->
     @pathCount = 0


settled, I evaluated but beforeFilter selecting is confusing, so remove.

--- lib/provider/select-files.coffee
+++ lib/provider/select-files.coffee
@@ -32,8 +32,7 @@
       @clientUi.focus(autoPreview: false) if @clientUi.isAlive()

   getItems: ->
-    items = []
-    headerItems = @clientUi.getAfterFilteredFileHeaderItems()
+    headerItems = @clientUi.getBeforeFilteredFileHeaderItems()
     projectNames = _.uniq(_.pluck(headerItems, "projectName"))
     itemize = itemForHeaderItem.bind(null, projectNames.length > 1)
     headerItems.map(itemize)


Account for activated in metrics

Account for activated in metrics

--- server/cron/sendMetrics.coffee
+++ server/cron/sendMetrics.coffee
@@ -11,6 +11,7 @@
     metrics = {}
     for key, query of queries
         query["total"] = 1
+        query.activated = true
         for group, _ of GROUPS
             query["userList"] = group
             metrics["#{key}.#{group}"] = (await Result.find(query)).length


bugfix: result may be undefined

bugfix: result may be undefined

--- server/lib/server/index.coffee
+++ server/lib/server/index.coffee
@@ -101,7 +101,8 @@
   app.use express.basicAuth basicAuth.username, basicAuth.password

 process.on 'uncaughtException', (err) ->
-  console.error "there was an uncaught exception #{err}"
+  console.error " there was an uncaught exception #{err}"
+  throw err
   process.exit(1)

@@ -302,13 +303,15 @@

           path = if section then "#{name}/#{section}" else name

-          JName.fetchModels path, (err, { models })->
+          JName.fetchModels path, (err, result) ->
+
             if err
               options = { account, name, section, client,
                           bongoModels, isCustomPreview }
               JGroup.render[prefix].subPage options, serveSub
-            else if not models? then next()
+            else if not result? then next()
             else
+              { models } = result
               options = { account, name, section, models,
                           client, bongoModels, isCustomPreview }
               JGroup.render[prefix].subPage options, serveSub


Update URLs to reflect github domain name changes.

--- src/ievm.coffee
+++ src/ievm.coffee
@@ -54,7 +54,7 @@

   # The command used to install virtual machines via ievms.
   @ievmsCmd: process.env.IEVMS_CMD ?
-    'curl -s https://raw.github.com/xdissent/ievms/master/ievms.sh | bash'
+    'curl -s https://raw.githubusercontent.com/xdissent/ievms/master/ievms.sh | bash'

   # The host IP as seen by the VM.
   @hostIp = '10.0.2.2'


Bring back refreshUserData when setting user data

User data needs to be refreshed on sign in, otherwise we don't have
fresh data regarding isSyncing property and other fields which can
change between refreshing page.

--- assets/scripts/app/auth.coffee
+++ assets/scripts/app/auth.coffee
@@ -64,6 +64,7 @@
     @set('state', 'signed-in')
     Travis.trigger('user:signed_in', data.user)
     @sendToApp('afterSignIn')
+    @refreshUserData(data.user)

   refreshUserData: (user) ->
     Travis.ajax.get "/users/#{user.id}", (data) =>


Show Filename metadata if it exists

Show Filename metadata if it exists

Closes #505

--- app/pages/lab/subject-set.cjsx
+++ app/pages/lab/subject-set.cjsx
@@ -35,7 +35,7 @@
   render: ->

-        {@props.subject.id}
+        {@props.subject.id}{"- #{@props.subject.metadata.Filename}" if @props.subject.metadata.Filename?}

         <button type="button" disabled={@state.beingDeleted} onClick={@props.onPreview.bind null, @props.subject}></button>


some wording free style...

some wording free style...

--- library/semantic/platings.coffee
+++ library/semantic/platings.coffee
@@ -50,18 +50,18 @@
     # The implementation downloads the data from the form and then
     # submits it to the backend and reacts to the response it got.
     confirmedFormSubmission: @awaiting "positive", ->
-        try this.form.container.addClass "loading"
+        try this.forms.container.addClass "loading"
         @ewrong ?= "Please check the entered information"
-        assert _.isObject data = try @form.download yes
+        assert _.isObject data = try @forms.download yes
         this.submission data, (success, values, other) =>
-            this.form.container.removeClass "loading"
+            this.forms.container.removeClass "loading"
             assert values and _.isObject values or null
-            @form.upload values; @form.messages @ewrong
+            @forms.upload values; @forms.messages @ewrong
             return undefined unless success and values
             @paragraph = $ "<p>", class: "right aligned"
             iconical = "icon checkmark green massive ok"
             assert icon = $ "<i>", class: "#{iconical}"
-            try this.actions.empty(); this.form.hide()
+            try this.actions.empty(); this.forms.hide()
             this.emit "successful", success, values
             this.content.append icon, @paragraph

@@ -80,6 +80,6 @@
         @actions.find(".positive").addClass "disabled"
         @header.text "Please fill the following form"
         @on "disconnect", -> try unload $ ".loading"
-        @form = new Shipped @content, "sign-up-form"
+        @forms = new Shipped @content, "sign-up-form"
         @emit "populate-form", disabler, enabler
         @on "negative", => try closer().click()


Added number pad key detection.

Added number pad key detection.

--- spec/barcode_input_spec.coffee
+++ spec/barcode_input_spec.coffee
@@ -19,7 +19,10 @@
 press_key = (key, options = {} ) ->
   ret = document.createEvent('Event')

-  keyCode = key.charCodeAt() unless (typeof key) == 'number'
+  # Numpad keys
+  key = key.replace('num-','').charCodeAt() + 48 if /num-\d/.test(key)
+
+  keyCode = if (typeof key) == 'number' then key else key.charCodeAt()
   keyCode = 27 if key == 'esc'
   keyCode = 13 if key == 'enter'

@@ -140,9 +143,18 @@

     it 'should trigger an entry event', -> expect( 'entered.barcode' ).toHaveBeenTriggeredOn( @input )

-  # describe 'Number Keys', ->
-  #   it 'should trigger an input event', ->
-  # describe 'Number Pad Keys', ->
-  #   it 'should trigger an input event', ->
+  describe 'Number Keys', ->
+    beforeEach ->
+      spyOnEvent @input, 'input.barcode'
+      press_key '9'
+
+    it 'should trigger an input event', -> expect( 'input.barcode' ).toHaveBeenTriggeredOn( @input )
+
+  describe 'Number Pad Keys', ->
+    beforeEach ->
+      spyOnEvent @input, 'input.barcode'
+      press_key 'num-5'
+
+    it 'should trigger an input event', -> expect( 'input.barcode' ).toHaveBeenTriggeredOn( @input )


Make 'log' tests sensitive to argument logging

--- test/log.coffee
+++ test/log.coffee
@@ -17,6 +17,9 @@

 # Test basic 'log' functionality
 describe 'log', ->
+  after ->
+    core.reset()
+
   for test in logLevels
     do (test) ->
       {topic, color} = test
@@ -34,25 +37,60 @@
         # When we log it via the given topic
         core.log[topic] color

+methodTests = [
+  method: 'init'
+  args: ['config', 'retriever']
+  expected: "Calling 'core.init' with args: { config: 'config', retriever: 'retriever' }"
+ ,
+  method: 'reset'
+  args: []
+  expected: "Calling 'core.reset'"
+ ,
+  method: 'load'
+  args: ['moduleName']
+  expected: "Calling 'core.load' with args: { moduleName: 'moduleName' }"
+ ,
+  method: 'request'
+  args: ['channel', 'data']
+  expected: "Calling 'core.request' with args: { channel: 'channel', data: 'data' }"
+ ,
+  method: 'delegate'
+  args: ['channel', 'data']
+  expected: "Calling 'core.delegate' with args: { channel: 'channel', data: 'data' }"
+ ,
+  method: 'respond'
+  args: ['channel']
+  expected: "Calling 'core.respond' with args: { channel: 'channel' }"
+ ,
+  method: 'send'
+  args: ['channel', 'data']
+  expected: "Calling 'core.send' with args: { channel: 'channel', data: 'data' }"
+ ,
+  method: 'listen'
+  args: ['channel', 'topic']
+  expected: "Calling 'core.listen' with args: { channel: 'channel', topic: 'topic' }"
+]
+
 # Test 'info' coverage for public 'core' API
 describe "log, 'core' API", ->
   beforeEach ->
     core.reset()

-  loggedMethods = Object.keys(core).filter (m) -> m isnt 'log'
+  for test in methodTests
+    do (test) ->
+      {method, args, expected} = test

-  for method in loggedMethods
-    do (method) ->
       it "should log calls to 'core.#{method}'", (done) ->

         # Given a listener on the 'info' topic of 'axiom.log'
         listen 'info', (data) ->
-
           # We should receive an informational message
           should.exist data
-          data.should.eql "Calling 'core.#{method}'"
+
+          # With the expected details
+          data.should.eql expected

           done()

         # When we call the given public 'core' method
-        try core[method]()
+        try core[method](args...)


change maximum aw number (some never display for the l letter)

--- app/scripts/controllers.coffee
+++ app/scripts/controllers.coffee
@@ -35,19 +35,19 @@

 .controller('ArtistListingController', ($scope, Artists, $state) ->
   $scope.letter = $state.params.letter || "a"
-  $scope.artists = Artists.getList({user__last_name__istartswith: $scope.letter, limit: 100}).$object
+  $scope.artists = Artists.getList({user__last_name__istartswith: $scope.letter, limit: 200}).$object
   $scope.alphabet = "abcdefghijklmnopqrstuvwxyz".split("")
 )

 .controller('ArtworkListingController', ($scope, Artworks, $state) ->
   $scope.letter = $state.params.letter || "a"
-  $scope.artworks = Artworks.getList({title__istartswith: $scope.letter, limit: 100}).$object
+  $scope.artworks = Artworks.getList({title__istartswith: $scope.letter, limit: 200}).$object
   $scope.alphabet = "abcdefghijklmnopqrstuvwxyz".split("")
 )

 .controller('ArtworkGenreListingController', ($scope, Artworks, $state) ->
   $scope.genre = $state.params.genre || ""
-  $scope.artworks = Artworks.getList({genres: $scope.genre, limit: 100}).$object
+  $scope.artworks = Artworks.getList({genres: $scope.genre, limit: 200}).$object
 )


Add some comments and TODO's

Add some comments and TODO's

--- app/scripts/scenes/City.coffee
+++ app/scripts/scenes/City.coffee
@@ -81,11 +81,18 @@
       x: 0
       y: 120

+
+  ##
+  # Setup the recoloring background to show a dawn in progress
   v = 0
+
+  # origin
   co =
     r: 0x60
     g: 0x20
     b: 0x20
+
+  # destination
   cd =
     r: 0x80
     g: 0x80
@@ -119,6 +126,7 @@
     level.stop()
     Crafty.enterScene('GameplayDemo', { stage: data.stage + 1 })

+  # TODO: Extract this to 'level'
   Crafty.bind 'PlayerDied', ->
     playersActive = no
     Crafty('Player ControlScheme').each ->


Test clicking the invite after already accepting

--- services/web/test/acceptance/coffee/ProjectInviteTests.coffee
+++ services/web/test/acceptance/coffee/ProjectInviteTests.coffee
@@ -91,10 +91,19 @@
 		callback()

 expectInviteRedirectToRegister = (user, link, callback=()->) ->
+	# view invite, redirect to `/register`
 	tryFollowInviteLink user, link, (err, response, body) ->
 		expect(err).to.be.oneOf [null, undefined]
 		expect(response.statusCode).to.equal 302
 		expect(response.headers.location).to.match new RegExp("^/register\?.*redir=.*$")
+		callback()
+
+expectInviteRedirectToProject = (user, link, invite, callback=()->) ->
+	# view invite, redirect straight to project
+	tryFollowInviteLink user, link, (err, response, body) ->
+		expect(err).to.be.oneOf [null, undefined]
+		expect(response.statusCode).to.equal 302
+		expect(response.headers.location).to.equal "/project/#{invite.projectId}"
 		callback()

 expectAcceptInviteAndRedirect = (user, invite, callback=()->) ->
@@ -152,7 +161,25 @@
 					(cb) => revokeInvite(@sendingUser, @projectId, @invite._id, cb)
 				], done

-			# describe 'user is already a member of the project', ->
+			describe 'user is already a member of the project', ->
+
+				beforeEach (done) ->
+					Async.series [
+						(cb) =>
+							expectInvitePage @user, @link, cb
+						(cb) =>
+							expectAcceptInviteAndRedirect @user, @invite, cb
+					], done
+
+				describe 'when user clicks on the invite a second time', ->
+
+					it 'should just redirect to the project page', (done) ->
+						Async.series [
+							(cb) =>
+								expectProjectAccess @user, @invite.projectId, cb
+							(cb) =>
+								expectInviteRedirectToProject @user, @link, @invite, cb
+						], done

 			describe 'user is not a member of the project', ->


Fix backend User verifiy password

Fix backend User verifiy password

--- backend/api/models/User.coffee
+++ backend/api/models/User.coffee
@@ -71,7 +71,10 @@

     verifyPassword: (password) ->
       bcrypt = require 'bcrypt'
-      return bcrypt.compareSync password, @password
+      if password and @password
+        return bcrypt.compareSync password, @password
+      else
+        return false

   beforeCreate: (values, cb) ->


Add a comment

Add a comment

--- background_scripts/main.coffee
+++ background_scripts/main.coffee
@@ -303,7 +303,7 @@
   unregisterFrame: ({tabId, frameId}) ->
     # FrameId 0 is the top/main frame.  We never unregister that frame.  If the tab is closing, then we tidy
     # up elsewhere.  If the tab is navigating to a new page, then a new top frame will be along soon.
-    # This mitigates against the unregister and register messages arriving in the "wrong" order.
+    # This mitigates against the unregister and register messages arriving out of order. See #2125.
     if 0 < frameId
       if tabId of frameIdsForTab
         frameIdsForTab[tabId] = (fId for fId in frameIdsForTab[tabId] when fId != frameId)


Make creating app title optional.

Make creating app title optional.

--- client/finder/AppController.coffee
+++ client/finder/AppController.coffee
@@ -13,12 +13,13 @@
   create: (options = {}) ->
     options.useStorage       ?= yes
     options.addOrphansToRoot ?= no
+    options.addAppTitle      ?= yes
     options.delegate         ?= this

     @controller = new NFinderController options
     finderView  = @controller.getView()

-    finderView.addSubView @getAppTitleView()
+    finderView.addSubView @getAppTitleView()  if options.addAppTitle
     finderView.addSubView @getUploader()
     finderView.addSubView @getMountVMButton()


removed dummy function from hello.coffee

--- app/static/coffee/hello.coffee
+++ app/static/coffee/hello.coffee
@@ -1,11 +1,4 @@
 urljson = 'http://10.139.14.121:5000/mithril/query'
-
-#This is not how you should do things. This is a basic working example.
-
-
-doSomething: (result) ->
-    for key, value of result
-        console.log("#{key} and #{value}")

 class Hello
     users = {}


Get the transition state name, not the name of the transition itself

--- src/jira.coffee
+++ src/jira.coffee
@@ -257,9 +257,9 @@
       parseJSON res
     .then (json) ->
       type = _(transitions).find (type) -> type.name is toState
-      transition = json.transitions.find (state) -> state.name.toLowerCase() is type.jira.toLowerCase()
+      transition = json.transitions.find (state) -> state.to.name.toLowerCase() is type.jira.toLowerCase()
       if transition
-        msg.send "<@#{msg.message.user.id}> Transitioning `#{ticket}` to `#{transition.name}`"
+        msg.send "<@#{msg.message.user.id}> Transitioning `#{ticket}` to `#{transition.to.name}`"
         fetch "#{jiraUrl}/rest/api/2/issue/#{ticket}/transitions",
           headers: headers
           method: "POST"


Prevent ReferenceError on variable definition check (#95)

--- src/content_scripts/content.coffee
+++ src/content_scripts/content.coffee
@@ -34,7 +34,7 @@
   return true;
 init = () ->
   success = false
-  if controller
+  if controller?
     success = controller.init();
     if success
       chrome.extension.sendRequest({action: "controller_loaded", host:window.location.host}, noop)
@@ -110,4 +110,4 @@

 chrome.extension.onRequest.addListener listener

-  +


no need for fair model

no need for fair model

--- apps/show/test/template.coffee
+++ apps/show/test/template.coffee
@@ -8,7 +8,6 @@
 PartnerShow     = require '../../../models/partner_show'
 Profile         = require '../../../models/profile'
 AdditionalImage = require '../../../models/additional_image'
-Fair            = require '../../../models/fair'
 Artwork         = require '../../../models/artwork'
 Artworks        = require '../../../collections/artworks'