Removes old socket.io deps

Removes old socket.io deps

--- app/scripts/main.coffee
+++ app/scripts/main.coffee
@@ -4,7 +4,7 @@
   'config/development',
   'app',
   'controllers/controllers', 'directives/directives', 'services/services', 'config/routing'
-  "services/configuration_service","services/connectivity_service","services/local_media_service","services/peer_connection_service","services/remote_media_service","services/signal_service","services/signal_service_socket_io","services/socket_service","services/user_service","services/util_service",
+  "services/configuration_service","services/connectivity_service","services/local_media_service","services/peer_connection_service","services/remote_media_service","services/signal_service","services/socket_service","services/user_service","services/util_service",
   "controllers/connectivity_controller","controllers/local_media_controller","controllers/remote_media_controller","controllers/user_controller",
   "directives/available_stream_info_directive","directives/bootstrap_modal_directive","directives/connecting_stream_info_directive","directives/remote_stream_directive","directives/template_directive","directives/user_media_directive"
 ],


Create Test That Reproduces #10

Create Test That Reproduces #10

--- spec/gobuild-spec.coffee
+++ spec/gobuild-spec.coffee
@@ -5,7 +5,7 @@
 _ = require 'underscore-plus'

 describe "build", ->
-  [editor, testEditor, directory, filePath, testFilePath] = []
+  [editor, secondEditor, thirdEditor, testEditor, directory, filePath, secondFilePath, thirdFilePath, testFilePath] = []

   beforeEach ->
     directory = temp.mkdirSync()
@@ -13,10 +13,16 @@
     atom.workspaceView = new WorkspaceView()
     atom.workspace = atom.workspaceView.model
     filePath = path.join(directory, "src", "github.com", "testuser", "example", "go-plus.go")
+    secondFilePath = path.join(directory, "src", "github.com", "testuser", "example", "util", "util.go")
+    thirdFilePath = path.join(directory, "src", "github.com", "testuser", "example", "util", "strings.go")
     testFilePath = path.join(directory, "src", "github.com", "testuser", "example", "go-plus_test.go")
     fs.writeFileSync(filePath, '')
+    fs.writeFileSync(secondFilePath, '')
+    fs.writeFileSync(thirdFilePath, '')
     fs.writeFileSync(testFilePath, '')
     editor = atom.workspace.openSync(filePath)
+    secondEditor = atom.workspace.openSync(secondFilePath)
+    thirdEditor = atom.workspace.openSync(thirdFilePath)
     testEditor = atom.workspace.openSync(testFilePath)

     waitsForPromise ->
@@ -31,6 +37,7 @@
       atom.config.set("go-plus.vetOnSave", false)
       atom.config.set("go-plus.lintOnSave", false)
       atom.config.set("go-plus.goPath", directory)
+      atom.config.set("go-plus.environmentOverridesConfiguration", false)
       atom.config.set("go-plus.syntaxCheckOnSave", true)
       atom.config.set("go-plus.goExecutablePath", "/usr/local/go/bin/go")
       atom.config.set("go-plus.gofmtPath", "/usr/local/go/bin/gofmt")
@@ -75,3 +82,27 @@

       waitsFor ->
         done is true
+
+    it "does not display errors for dependent functions spread across multiple files in the same package", ->
+      done = false
+      runs ->
+        console.log 'Test Directory: ' + directory
+        buffer = editor.getBuffer()
+        secondBuffer = secondEditor.getBuffer()
+        thirdBuffer = thirdEditor.getBuffer()
+        buffer.setText("package main\n\nimport \"fmt\"\nimport \"github.com/testuser/example/util\"\n\nfunc main() {\n\tfmt.Println(\"Hello, world!\")\n\tutil.ProcessString(\"Hello, world!\")\n}")
+        secondBuffer.setText("package util\n\nimport \"fmt\"\n\n// ProcessString processes strings\nfunc ProcessString(text string) {\n\tfmt.Println(\"Processing...\")\n\tfmt.Println(Stringify(\"Testing\"))\n}")
+        thirdBuffer.setText("package util\n\n// Stringify stringifies text\nfunc Stringify(text string) string {\n\treturn text + \"-stringified\"\n}")
+        buffer.save()
+        secondBuffer.save()
+        thirdBuffer.save()
+        dispatch = atom.packages.getLoadedPackage('go-plus').mainModule.dispatch
+        dispatch.on 'dispatch-complete', =>
+          expect(fs.readFileSync(secondFilePath, {encoding: 'utf8'})).toBe "package util\n\nimport \"fmt\"\n\n// ProcessString processes strings\nfunc ProcessString(text string) {\n\tfmt.Println(\"Processing...\")\n\tfmt.Println(Stringify(\"Testing\"))\n}"
+          expect(dispatch.errorCollection?).toBe true
+          expect(_.size(dispatch.errorCollection)).toBe 0
+          done = true
+        secondBuffer.save()
+
+      waitsFor ->
+        done is true


:white_check_mark: Added single & double quote tests

--- spec/grammar-spec.coffee
+++ spec/grammar-spec.coffee
@@ -122,6 +122,13 @@
       expect(tokens[3]).toEqual value: "qx();", scopes: ["source.perl"]

   describe "tokenizes single quoting", ->
+    it "'text'", ->
+      {tokens} = grammar.tokenizeLine("'Test this\\nsimple one';")
+      expect(tokens[0]).toEqual value: "'", scopes: ["source.perl", "string.quoted.single.perl", "punctuation.definition.string.begin.perl"]
+      expect(tokens[1]).toEqual value: "Test this\\nsimple one", scopes: ["source.perl", "string.quoted.single.perl"]
+      expect(tokens[2]).toEqual value: "'", scopes: ["source.perl", "string.quoted.single.perl", "punctuation.definition.string.end.perl"]
+      expect(tokens[3]).toEqual value: ";", scopes: ["source.perl"]
+
     it "q(text)", ->
       {tokens} = grammar.tokenizeLine("q(Test this\\nsimple one);")
       expect(tokens[0]).toEqual value: "q(", scopes: ["source.perl", "string.quoted.other.q-paren.perl", "punctuation.definition.string.begin.perl"]
@@ -163,6 +170,15 @@
       expect(lines[4][1]).toEqual value: ";", scopes: ["source.perl"]

   describe "tokenizes double quoting", ->
+    it "\"text\"", ->
+      {tokens} = grammar.tokenizeLine("\"Test this\\nsimple one\";")
+      expect(tokens[0]).toEqual value: "\"", scopes: ["source.perl", "string.quoted.double.perl", "punctuation.definition.string.begin.perl"]
+      expect(tokens[1]).toEqual value: "Test this", scopes: ["source.perl", "string.quoted.double.perl"]
+      expect(tokens[2]).toEqual value: "\\n", scopes: ["source.perl", "string.quoted.double.perl", "constant.character.escape.perl"]
+      expect(tokens[3]).toEqual value: "simple one", scopes: ["source.perl", "string.quoted.double.perl"]
+      expect(tokens[4]).toEqual value: "\"", scopes: ["source.perl", "string.quoted.double.perl", "punctuation.definition.string.end.perl"]
+      expect(tokens[5]).toEqual value: ";", scopes: ["source.perl"]
+
     it "qq(text)", ->
       {tokens} = grammar.tokenizeLine("qq(Test this\\nsimple one);")
       expect(tokens[0]).toEqual value: "qq(", scopes: ["source.perl", "string.quoted.other.qq-paren.perl", "punctuation.definition.string.begin.perl"]


replace $timeout by setTimeout in pdf viewer

--- services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee
@@ -91,7 +91,8 @@
 				@resetState()

 			triggerRenderQueue: (interval = @JOB_QUEUE_INTERVAL) ->
-				$timeout () =>
+				@queueTimer = setTimeout () =>
+					@queueTimer = null
 					@processRenderQueue()
 				, interval

@@ -134,7 +135,7 @@
 				@jobs = @jobs + 1

 				element.canvas.addClass('pdfng-loading')
-				spinTimer = $timeout () =>
+				spinTimer = setTimeout () =>
 					@spinner.add(element.canvas)
 				, 100

@@ -147,7 +148,7 @@
 					Raven.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms')
 					# console.log 'page load timed out', pagenum
 					timedOut = true
-					$timeout.cancel(spinTimer)
+					clearTimeout(spinTimer)
 					@spinner.stop(element.canvas)
 					# @jobs = @jobs - 1
 					# @triggerRenderQueue(0)
@@ -159,7 +160,7 @@
 				@pageLoad[pagenum].then (pageObject) =>
 					# console.log 'in page load success', pagenum
 					$timeout.cancel(timer)
-					$timeout.cancel(spinTimer)
+					clearTimeout(spinTimer)
 					@renderTask[pagenum] = @doRender element, pagenum, pageObject
 					@renderTask[pagenum].then () =>
 						# complete
@@ -173,7 +174,7 @@
 				.catch (error) ->
 					# console.log 'in page load error', pagenum, 'timedOut=', timedOut
 					$timeout.cancel(timer)
-					$timeout.cancel(spinTimer)
+					clearTimeout(spinTimer)
 					# console.log 'ERROR', error

 			doRender: (element, pagenum, page) ->
@@ -278,6 +279,7 @@
 			destroy: () ->
 				# console.log 'in pdf renderer destroy', @renderQueue
 				@shuttingDown = true
+				clearTimeout @queueTimer if @queueTimer?
 				@renderQueue = []
 				for task in @renderTask
 					task.cancel() if task?


spec/heterogenous: Role is mandatory in discovery

--- spec/heterogenous.coffee
+++ spec/heterogenous.coffee
@@ -57,7 +57,7 @@
         onDiscovery = (msg) ->
           def = msg.data
           chai.expect(def).to.be.an 'object'
-          chai.expect(def).to.have.keys ['id', 'icon', 'component', 'label', 'inports', 'outports']
+          chai.expect(def).to.have.keys ['id', 'icon', 'role', 'component', 'label', 'inports', 'outports']
           state.broker.ackMessage msg
           return if def.component != name
           done()


:green_heart:

:green_heart:

Signed-off-by: Max Brunsfeld <78036c9b69b887700d5846f26a788d53b201ffbb@github.com>

--- spec/upgrade-spec.coffee
+++ spec/upgrade-spec.coffee
@@ -172,7 +172,7 @@
     beforeEach ->
       delete process.env.ATOM_ELECTRON_URL
       delete process.env.ATOM_PACKAGES_URL
-      delete process.env.ATOM_ELECTRON_VERSION
+      process.env.ATOM_ELECTRON_VERSION = "0.22.0"

       gitRepo = path.join(__dirname, "fixtures", "test-git-repo.git")
       cloneUrl = "file://#{gitRepo}"


Added destroy input on removed tab for existing translations

--- app/assets/javascripts/active_admin/active_admin_globalize.js.coffee
+++ app/assets/javascripts/active_admin/active_admin_globalize.js.coffee
@@ -108,7 +108,21 @@
               $("li:not(.add-locale) > a", this).each ->
                 # Remove them if the locale is hidden.
                 if $(this).hasClass('hidden')
-                  $fieldsets.filter($(this).attr('href')).remove()
+                  # check if it's an existing translation otherwise remove it
+                  $currentFieldset = $("fieldset#{$(this).attr('href')}")
+                  $translationId = $('input[id$=_id]', $currentFieldset)
+                  if $translationId.val()
+                    # mark it for database removal appending a _destroy element
+                    $destroy = $('<input/>').attr(
+                      type: 'hidden',
+                      name: $translationId.attr('name').replace('[id]', '[_destroy]'),
+                      id: $translationId.attr('id').replace('_id', '_destroy'),
+                      value: '1'
+                    )
+                    $destroy.appendTo($currentFieldset)
+                  else
+                    # remove the fieldset from dom so it won't be submitted
+                    $fieldsets.filter($(this).attr('href')).remove()

         #Initially update the buttons' status
         updateLocaleButtonsStatus($dom)


Remove unused file

Remove unused file


collision: adding scrollMonitor check

collision: adding scrollMonitor check

--- app/_src/components/blog/estimation-survey/collision.coffee
+++ app/_src/components/blog/estimation-survey/collision.coffee
@@ -7,7 +7,7 @@
 	SELECTOR_CONTAINER = '#js-estimation-post-collision-container'

 	NODES = [
-		# 18 of these bad boys
+		# 18 of these bad boys (blue)
 		{ r: 10, fill: "#006457" },
 		{ r: 10, fill: "#006457" },
 		{ r: 10, fill: "#006457" },
@@ -26,18 +26,18 @@
 		{ r: 10, fill: "#006457" },
 		{ r: 10, fill: "#006457" },
 		{ r: 10, fill: "#006457" },
-		# 3 of these bad boys
-		{ r: 10, fill: "#83aa08" },
-		{ r: 10, fill: "#83aa08" },
-		{ r: 10, fill: "#83aa08" },
-		# 4 of these bad boys
-		{ r: 10, fill: "#daa500" },
-		{ r: 10, fill: "#daa500" },
-		{ r: 10, fill: "#daa500" },
-		{ r: 10, fill: "#daa500" },
-		# 2 of these bad boys
-		{ r: 10, fill: "#f17e0b" }
-		{ r: 10, fill: "#f17e0b" }
+		# 3 of these bad boys (green)
+		{ r: 15, fill: "#83aa08" },
+		{ r: 15, fill: "#83aa08" },
+		{ r: 15, fill: "#83aa08" },
+		# 4 of these bad boys (yellow)
+		{ r: 20, fill: "#daa500" },
+		{ r: 20, fill: "#daa500" },
+		{ r: 20, fill: "#daa500" },
+		{ r: 20, fill: "#daa500" },
+		# 2 of these bad boys (orange)
+		{ r: 25, fill: "#f17e0b" }
+		{ r: 25, fill: "#f17e0b" }
 	]

 	W = 600
@@ -48,29 +48,20 @@

 	onScriptsLoaded: =>
 		@init()
+		setTimeout =>
+			@watcher = scrollMonitor.create @$context
+			@watcher.enterViewport @_onEnterViewport
+			@watcher.exitViewport @_onExitViewport
+			@watcher.recalculateLocation()
+		, 1

-	init: =>
+	_onEnterViewport: () =>
+		@run()
+		@watcher.destroy()

-		@root = NODES[0]
-		@root.radius = 0
-		@root.fixed = true
-
-		@svg = d3.select( SELECTOR_CONTAINER )
-			 .append("svg")
-			 .attr("preserveAspectRatio", "xMinYMin meet")
-			 .attr("viewBox", "0 0 " + W + " " + H)
-			 .classed("svg-content", true)
-
-		@svg.selectAll("circle")
-			.data( NODES )
-			.enter()
-			.append("svg:circle")
-			.attr("r", (d) -> d.r )
-			.style("fill", (d, i) -> d.fill )
-
+	run: =>
 		@force = d3.layout.force()
 			.gravity(0.05)
-			# .charge( (d, i) -> i ? 0 : -2000 )
 			.nodes( NODES )
 			.size([ W, H])

@@ -89,17 +80,23 @@
 				.attr("cy", (d) -> d.y )
 		)

-		that = this
 		@svg.on("mousemove", () ->
-		  p1 = d3.mouse(this)
-		  that.root.px = p1[0]
-		  that.root.py = p1[1]
-		  that.force.resume()
-		  return
+			onInteract(this)
+		)
+		@svg.on("touchmove", () ->
+		  onInteract(this)
 		)

+		that = this
+		onInteract = (arg) ->
+			p1 = d3.mouse(arg)
+			that.root.px = p1[0]
+			that.root.py = p1[1]
+			that.force.resume()
+			return
+
 		collide = (node) ->
-			r = node.radius + 16
+			r = node.r + 0
 			nx1 = node.x - r
 			nx2 = node.x + r
 			ny1 = node.y - r
@@ -110,7 +107,7 @@
 					x = node.x - (quad.point.x)
 					y = node.y - (quad.point.y)
 					l = Math.sqrt(x * x + y * y)
-					r = node.radius + quad.point.radius
+					r = node.r + quad.point.r
 					if l < r
 						l = (l - r) / l * .5
 						node.x -= x *= l
@@ -119,5 +116,24 @@
 						quad.point.y += y
 				x1 > nx2 or x2 < nx1 or y1 > ny2 or y2 < ny1

+	init: =>
+		@root = NODES[0]
+		@root.r = 0
+		@root.fixed = true
+
+		@svg = d3.select( SELECTOR_CONTAINER )
+			 .append("svg")
+			 .attr("preserveAspectRatio", "xMinYMin meet")
+			 .attr("viewBox", "0 0 " + W + " " + H)
+			 .classed("svg-content", true)
+
+		@svg.selectAll("circle")
+			.data( NODES )
+			.enter()
+			.append("svg:circle")
+			.attr("r", (d) -> d.r )
+			.style("fill", (d, i) -> d.fill )
+
+
 	destroy: ->
 		super()


Reduce the large text size from 5 to 0.5 MB.

--- test/integration/parameterised-statements-test.coffee
+++ test/integration/parameterised-statements-test.coffee
@@ -166,7 +166,7 @@
   execSql(test, TYPES.Text, 'small')

 exports.textLarge = (test) ->
-  dBuf = new Buffer(5000000)
+  dBuf = new Buffer(500000)
   dBuf.fill('x')
   execSql(test, TYPES.Text, dBuf.toString())


Missed component template

Missed component template

--- app/components/all.coffee
+++ app/components/all.coffee
@@ -1 +1,2 @@
+require './team-member'
 require './team_member'


Update zh-HANS.coffee (#5560)

Update zh-HANS.coffee (#5560)

* Update zh-HANS.coffee

* Update zh-HANS.coffee

* Update zh-HANS.coffee

* Update zh-HANS.coffee


Update search query to check if contains string

This overrides the original search method which required an exact
match to show results. The new contains approach will return any title
that contains the query string.

--- app/routes/explore.coffee
+++ app/routes/explore.coffee
@@ -15,7 +15,7 @@
   query =
     text:
       'declare namespace tei="http://www.tei-c.org/ns/1.0"; ' +
-      '//tei:title[. = "' + req.query.q + '"]'
+      '//tei:title[contains(text(), "' + req.query.q + '")]'

   client.query query, (results) ->
     # TODO: Convert XML to JS object


rename

rename

--- lib/ui.coffee
+++ lib/ui.coffee
@@ -13,7 +13,7 @@
 Grammar = require './grammar'
 getFilterSpecForQuery = require './get-filter-spec-for-query'

-class PromptGutter
+class CurrentItemIndicator
   constructor: (@editor) ->
     @gutter = @editor.addGutter(name: 'narrow-prompt', priority: 100)

@@ -112,7 +112,7 @@
     @disposables.add @onDidMoveToItemArea =>
       @vmpActivateNormalMode() if @vmpIsInsertMode()

-    @promptGutter = new PromptGutter(@editor)
+    @currentItemIndicator = new CurrentItemIndicator(@editor)

     @grammar = new Grammar(@editor, includeHeaderRules: @provider.includeHeaderGrammar)

@@ -198,7 +198,7 @@
     @activateProviderPane()

     @provider?.destroy?()
-    @promptGutter?.destroy()
+    @currentItemIndicator?.destroy()
     @rowMarker?.destroy()

   registerCommands: ->
@@ -544,7 +544,7 @@
   selectItemForRow: (row) ->
     item = @items[row]
     if @isNormalItem(item)
-      @promptGutter.setToRow(row)
+      @currentItemIndicator.setToRow(row)
       @selectedItem = item

   getSelectedItem: ->


connecting status

connecting status

--- app/scripts/editor.coffee
+++ app/scripts/editor.coffee
@@ -7,6 +7,7 @@
 		shift: false
 		empty: false
 		new: true
+		connecting: false
 	displayPrompt: ->
 		$('#editor').html @promptMessage
 	clear: ->


Minor changes

Minor changes

--- app/scripts/pocket.coffee
+++ app/scripts/pocket.coffee
@@ -90,10 +90,13 @@
     parent.appendChild textArea

   editLabel: (event) ->
+    event.preventDefault()
+
     text  = event.target
     textArea = text.pocketTextArea
     textArea.value = text.innerText
     textArea.focus()
+    textArea.select()

     group = text.parentElement
     @changeGroupState group, @State.EDIT


Add missing apostrophe to comment box

Add missing apostrophe to comment box

--- app/talk/comment-box.cjsx
+++ app/talk/comment-box.cjsx
@@ -93,7 +93,7 @@
         {if @props.reply

-              In reply to {@props.reply.comment.user_display_name}s comment:
+              In reply to {@props.reply.comment.user_display_name}'s comment:

             <Markdown project={@props.project}>{@props.reply.comment.body}</Markdown>
             <button type="button" onClick={@props.onClickClearReply}> Clear Reply</button>


Add translator as a Talk role

Add translator as a Talk role

--- app/talk/lib/roles.coffee
+++ app/talk/lib/roles.coffee
@@ -1,7 +1,8 @@
 module.exports = [
 # Role          | Can access:
-  "admin"       # admin, moderator, ream, all
-  "moderator"   # moderator, team, all
-  "team"        # team, all
+  "admin"       # admin, moderator, team, translator, all
+  "moderator"   # moderator, team, translator, all
+  "team"        # team, translator, all
+  "translator"  # translator, all
   "all"         # all *
   ]


fixed default focus on finderitem delete

--- client/app/MainApp/filetree/itemsubviews/finderitemdeleteview.coffee
+++ client/app/MainApp/filetree/itemsubviews/finderitemdeleteview.coffee
@@ -20,7 +20,7 @@
     @label = new KDLabelView
       title     : 'Are you sure?'

-  show:->
+  viewAppended:->

     super
     @button.$().focus()


We'll never actually bind to anything if we specify a port.


render a div instead of array

render a div instead of array

button's lacks a key, causing warnings.  Since it's passed down as a
prop, it seems unrealistic to force the parent to provide a key

--- tutor/src/components/task-step/step-footer-mixin.cjsx
+++ tutor/src/components/task-step/step-footer-mixin.cjsx
@@ -141,17 +141,12 @@

   renderFooter: ({stepId, taskId, courseId, review}) ->
     className = @getFooterClasses({stepId, taskId, courseId, review})
-
-    buttons = @renderButtons({stepId, taskId, courseId, review})
-
-    taskDetails =

-      {@renderTaskDetails({stepId, taskId, courseId, review})}
+

+      {@renderButtons({stepId, taskId, courseId, review})}
+

+        {@renderTaskDetails({stepId, taskId, courseId, review})}
+

-
-    [
-      React.cloneElement(buttons, { key: "buttons" })
-      taskDetails
-    ]

   renderEndFooter: ({stepId, taskId, courseId, review}) ->
     panel = StepPanel.getPanel(stepId)


[loadingFree] previosu failed attempt removed

--- client/app/MainApp/maincontroller/mainviewcontroller.coffee
+++ client/app/MainApp/maincontroller/mainviewcontroller.coffee
@@ -1,8 +1,4 @@
 class MainViewController extends KDViewController
-
-  lazyloadQueue = [
-    'Topics', 'Members', 'Apps'
-  ]

   constructor:->

@@ -26,16 +22,6 @@

     mainController.on "ToggleChatPanel", =>
       mainView.chatPanel.toggle()
-
-    # mainView.ready ->
-    #   log "i am ready motherfucker"
-    #   i = 0
-    #   r = repeat 5000, ->
-    #     appManager.open lazyloadQueue[i++],
-    #       params       :
-    #         background : yes
-    #     log "i am opening #{lazyloadQueue[i-1]}"
-    #     killRepeat r if i is lazyloadQueue.length

     if KD.checkFlag 'super-admin'
     then $('body').addClass 'super'


teamwork: make `http` protocol mandatory for `URL` RegExp in chat messages

--- client/landing/CollaborativeWorkspace/panes/chatpane.coffee
+++ client/landing/CollaborativeWorkspace/panes/chatpane.coffee
@@ -117,7 +117,7 @@

     element  = @lastMessage.getElement()
     words    = @lastMessageBody.split " "
-    urlRegex = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
+    urlRegex = /^(https?:\/\/)([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/
     hasUrl   = no

     for word, index in words


make reorder plugin turbolinks compatible

--- app/assets/javascripts/active_admin/lib/jquery.reorder.coffee
+++ app/assets/javascripts/active_admin/lib/jquery.reorder.coffee
@@ -1,6 +1,8 @@
-$ ->
+initSort = ->
   $(".index_table").has("td.col-position").each ->
     $table = $(@)
+    return if $table.data('aa.reorder')
+    $table.data('aa.reorder', true)
     resource = $table.attr('id').split("index_table_")[1]
     $table.find("tbody").sortable
       update: (e, ui) ->
@@ -19,3 +21,6 @@
         ui.children().each ->
           $(@).width($(@).width())
         ui
+
+document.addEventListener('turbolinks:load', initSort)
+$ -> initSort()


removed blue measels from map

removed blue measels from map

--- app/assets/javascripts/gmaps4rails/gmaps4rails.base.js.coffee
+++ app/assets/javascripts/gmaps4rails/gmaps4rails.base.js.coffee
@@ -50,7 +50,8 @@
       #Marker config
       title: ""
       #MarkerImage config
-      picture : "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle_blue.png"
+#      picture : "https://maps.gstatic.com/intl/en_us/mapfiles/markers2/measle_blue.png"
+      picture: ""
       width: 22
       length: 32
       draggable: false         # how to modify: <%= gmaps( "markers" => { "data" => @object.to_gmaps4rails, "options" => { "draggable" => true }}) %>


Workspace: Hide loader of inactive session.

--- client/app/CommonViews/workspace/collaborativeworkspace.coffee
+++ client/app/CommonViews/workspace/collaborativeworkspace.coffee
@@ -110,6 +110,7 @@
       callback : @bound "startNewSession"

     @container.addSubView notValid
+    @loader.hide()

   startNewSession: ->
     @destroySubViews()


NavigationMachineItem: Added vm label to URL.

--- client/Main/navigation/navigationmachineitem.coffee
+++ client/Main/navigation/navigationmachineitem.coffee
@@ -10,7 +10,7 @@

     machine            = data
     @alias             = machine.label
-    path               = KD.utils.groupifyLink "/IDE/my-workspace"
+    path               = KD.utils.groupifyLink "/IDE/#{@alias}/my-workspace"

     options.tagName    = 'a'
     options.cssClass   = "vm #{machine.status.state.toLowerCase()} #{machine.provider}"


shortcut: conflicts with default `Go to previous line` key combo

--- client/ide/views/shortcutsview/shortcutsview.coffee
+++ client/ide/views/shortcutsview/shortcutsview.coffee
@@ -82,7 +82,6 @@
       'Go to line end'         : { Others: 'End',            Apple: 'Ctrl-E'    }
       'Go to line start'       : { Others: 'Alt-Left',       Apple: 'Meta-Left' }
       'Go to line start'       : { Others: 'End',            Apple: 'Ctrl-A'    }
-      'Go to matching bracket' : 'Ctrl-P'
       'Go to page down'        : 'Ctrl-V'
       'Go to word left'        : { Others: 'Ctrl-Left',      Apple: 'Alt-Left'  }
       'Go to word right'       : { Others: 'Ctrl-Right',    Apple: 'Alt-Right' }


tweak to previous fix for forms with checkboxes

--- app/assets/javascripts/tenon/features/tenon_content/record_list_updater.js.coffee
+++ app/assets/javascripts/tenon/features/tenon_content/record_list_updater.js.coffee
@@ -11,7 +11,7 @@
     if $el.prop("tagName").toLowerCase() == 'form'
       @_updateWithQuery(@_processFormData($el), 'Search')
     else
-      @_updateWithQuery(URI($el.attr('href')).query(), $el.textContent)
+      @_updateWithQuery(URI($el.attr('href')).query(true), $el.textContent)

   _processFormData: (form) =>
     formData = URI("?" + form.serialize()).query(true)
@@ -22,7 +22,7 @@

   _updateWithQuery: (query, title) =>
     query = if @clearQuery then query else @_mergedQuery(query)
-    history.pushState({recordListUpdate: true}, title, "?#{query}")
+    history.pushState({recordListUpdate: true}, title, "?#{query.toString()}")
     Tenon.refreshed = false
     Tenon.activeRecordList.refresh(clear: true)


KDFramework: KDTabViewWithForms callback problem fixed

--- client/Framework/components/tabs/KDTabViewWithForms.coffee
+++ client/Framework/components/tabs/KDTabViewWithForms.coffee
@@ -33,17 +33,18 @@

     oldCallback = formData.callback
     formData.callback = (formData)=>
-      log formData, "><><><"
       @showNextPane() if @getOptions().goToNextFormOnSubmit
       oldCallback? formData
-      if index is @getOptions().forms.length - 1
+      # debugger
+      {forms} = @getOptions()
+      if forms and index is Object.keys(forms).length - 1
         @fireFinalCallback()

     @createForm formData,tab
     return tab

   createTabs:(forms)->
-    forms.forEach @bound 'createTab'
+    forms.forEach (formData, i)=> @createTab formData, i

   createForm:(formData,parentTab)->
     parentTab.addSubView form = new KDFormViewWithFields formData


Revert "Cleanup messed code"

Revert "Cleanup messed code"

This reverts commit ec05ba48a1ca2a58468592cc20dd7be8aa4a0227.

--- client/app/CommonViews/comments/commentlistitemview.coffee
+++ client/app/CommonViews/comments/commentlistitemview.coffee
@@ -12,22 +12,36 @@
     originType  = data.getAt('originType')
     deleterId   = data.getAt('deletedBy')?.getId?()

-    origin =
+    origin = {
       constructorName  : originType
       id               : originId
-
+    }
     @avatar = new AvatarView {
-      size     :
-        width  : 30
-        height : 30
+      size    : {width: 30, height: 30}
+      origin
+    }
+    @author = new ProfileLinkView {
       origin
     }

-    @author = new ProfileLinkView { origin }
-
     if deleterId? and deleterId isnt originId
       @deleter = new ProfileLinkView {}, data.getAt('deletedBy')
-
+    # if data.originId is KD.whoami().getId()
+    #   @settingsButton = new KDButtonViewWithMenu
+    #     style       : 'transparent activity-settings-context'
+    #     cssClass    : 'activity-settings-menu'
+    #     title       : ''
+    #     icon        : yes
+    #     delegate    : @
+    #     iconClass   : "cog"
+    #     menu        : [
+    #       type      : "contextmenu"
+    #       items     : [
+    #         { title : 'Delete', id : 2,  parentId : null, callback : => data.delete (err)=> @propagateEvent KDEventType: 'CommentIsDeleted' }
+    #       ]
+    #     ]
+    #     callback    : (event)=> @settingsButton.contextMenu event
+    # else
     @deleteLink = new KDCustomHTMLView
       tagName     : 'a'
       attributes  :


sidebarstacksection: add stack view option to menu items

--- client/app/lib/components/sidebarstacksection/index.coffee
+++ client/app/lib/components/sidebarstacksection/index.coffee
@@ -87,7 +87,7 @@

     switch title
-      when 'Edit' then router.handleRoute "/Stack-Editor/#{templateId}"
+      when 'Edit', 'View Stack' then router.handleRoute "/Stack-Editor/#{templateId}"
       when 'Reinitialize', 'Update'
         reinitStackFromWidget(stack).then ->
           # invalidate editor cache
@@ -127,6 +127,8 @@
     else
       if isAdmin() or @props.stack.get('accessLevel') is 'private'
         menuItems['Edit'] = { callback }
+      else
+        menuItems['View Stack'] = { callback }
       ['Reinitialize', 'VMs', 'Destroy VMs'].forEach (name) ->
         menuItems[name] = { callback }
       if isAdmin() and not isStackTemplateSharedWithTeam @props.stack.get 'baseStackId'


payment: fix typo

payment: fix typo

--- client/landing/app/MainApp/payment/paymentformmodal.coffee
+++ client/landing/app/MainApp/payment/paymentformmodal.coffee
@@ -33,7 +33,6 @@
     @paymentForm = new PaymentForm

     @forwardEvent @paymentForm, 'PaymentInfoSubmitted'
-paymentInfo
     @addSubView @paymentForm

     @paymentForm.hide()


payment: clean up GroupProductListItem (a bit)

--- client/app/Applications/Dashboard.kdapplication/views/groupproductlistitem.coffee
+++ client/app/Applications/Dashboard.kdapplication/views/groupproductlistitem.coffee
@@ -1,19 +1,20 @@
 class GroupProductListItem extends KDListItemView
+
   constructor:(options,data)->
     super options, data

-    {code} = @getData()
+    { planCode } = @getData()

     codeCheck =
       """
-      KD.remote.api.JPaymentSubscription.checkUserSubscription '#{code}', (err, subscriptions)->
+      KD.remote.api.JPaymentSubscription.checkUserSubscription '#{planCode}', (err, subscriptions)->
         if not err and subscriptions.length > 0
           console.log "User is subscribed to the plan."
       """

     codeGet =
       """
-      KD.remote.api.JPaymentPlan.fetchPlanByCode '#{code}', (err, plan)->
+      KD.remote.api.JPaymentPlan.fetchPlanByCode '#{planCode}', (err, plan)->
         if not err and plan
           plan.fetchSubscriptions (err, subs)->
             console.log "Subscribers:", subs
@@ -28,7 +29,7 @@
           console.log "Open video..."

       @payment = new PaymentWidget
-        planCode        : '#{code}'
+        planCode        : '#{planCode}'
         contentCssClass : 'modal-clean-green'
         content         : @content

@@ -56,18 +57,18 @@
     @clientsButton = new KDButtonView
       title    : "View Buyers"
       callback : =>
-        plan = @getData()
-        plan.fetchSubscriptions (err, subs)->
+        product = @getData()
+        product.fetchSubscriptions (err, subs)->
           if err
             subs = []
           new KDNotificationView
             title: "This product has #{subs.length} buyer(s)."

     @deleteButton = new KDButtonView
-      title    : "-"
+      title    : "Remove"
       callback : =>
         @confirmDelete =>
-          @getDelegate().emit "DeleteItem", code
+          @getDelegate().emit "DeleteItem", planCode

   confirmDelete:(callback) ->
     deleteModal = new KDModalView
@@ -90,9 +91,9 @@
   pistachio:->
     product = @getData()

-    code  = product.planCode
-    title = product.title
-    price = (product.amount / 100).toFixed(2).toLocaleString()
+    planCode  = product.planCode
+    title     = product.title
+    price     = (product.amount / 100).toFixed(2)

     subscriptionType =
       if product.subscriptionType is 'single'


JSecretName: whitelist update events

JSecretName: whitelist update events

Fixes following issues in social log https://papertrailapp.com/groups/867873/events?q=program%3Asocialworker.log+JSecretName

--- workers/social/lib/social/models/secretname.coffee
+++ workers/social/lib/social/models/secretname.coffee
@@ -4,6 +4,9 @@

   @set
     softDelete    : no
+    sharedEvents  :
+      instance    : []
+      static      : []

   # TODO: the below should be made a bit more secure:
   @setSchema


social: sanitize email before checking if it's available

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -1202,7 +1202,10 @@
   @emailAvailable = (email, callback)->
     unless typeof email is 'string'
       return callback createKodingError 'Not a valid email!'
+
     email = email.toLowerCase()
+    email = (require "./emailSanitize")(email)
+
     @count {email}, (err, count)->
       callback err, count is 0


Remove sessions of user changed password

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -1630,6 +1630,10 @@

         account.sendNotification 'SessionHasEnded', { clientId }

+        selector = { clientId: $ne: client.sessionToken }
+
+        user.killSessions selector, callback
+

   sendChangedEmail = (username, firstName, to, type) ->


simplified one line of code, you are welcome me

--- app/assets/javascripts/app/views/album_pop_over.coffee
+++ app/assets/javascripts/app/views/album_pop_over.coffee
@@ -25,7 +25,7 @@
         @eventBus.trigger 'album:update', @
         if @collection.length > 0 and !@hasState 'show'
           @setState 'show'
-        else if @collection.length == 0
+        else if !@collection.length
           @unsetState 'show'
       super()


SocialWorker: refactor fetchSession helper function

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -359,7 +359,7 @@
       callback null, response

-  fetchSession = (options, queue, callback, fetchData) ->
+  fetchSession = (options, callback) ->

     { clientId, username } = options

@@ -372,9 +372,7 @@
         console.error "login: session not found #{username}"
         return callback new KodingError 'Couldn\'t restore your session!'

-      fetchData session
-
-      queue.next()
+      callback null, session

   validateLoginCredentials = (options, queue, callback, fetchData) ->


Added red asterisk next to supplier label

--- app/assets/javascripts/backend/interventions.js.coffee
+++ app/assets/javascripts/backend/interventions.js.coffee
@@ -362,6 +362,11 @@
     $(this).each ->
       E.interventions.isPurchaseOrderSelectorEnabled($(this))

+  $(document).behave "load", ".reception-supplier", ->
+    supplierLabel = $($(this).parents('.nested-receptions').find('.control-label')[0])
+    supplierLabel.addClass('required')
+    supplierLabel.prepend("<abbr title='Obligatoire'>*</abbr>")
+
   $(document).ready ->

     # E.interventions.hideKujakuFilters($('.view-toolbar a[data-janus-href="cobbles"]').hasClass('active'))


comment alex line to get amount in intervention

--- app/assets/javascripts/backend/interventions.js.coffee
+++ app/assets/javascripts/backend/interventions.js.coffee
@@ -397,21 +397,21 @@
       if unitName
         intervention['unit_name'] = unitName

-      $.ajax
-        url: "/backend/interventions/costs/parameter_cost",
-        data: { intervention: intervention }
-        success: (data, status, request) ->
-          if !data.human_amount.nature || data.human_amount.nature != "failed"
-            nestedProductParameter = $(target).closest('.nested-product-parameter')
-
-            if $(nestedProductParameter).find('.product-parameter-cost').length > 0
-              $(nestedProductParameter).find('.product-parameter-cost-value').text(data.human_amount)
-            else
-              parameterCostBlock = $('

')
-              parameterCostBlock.append('Coût : ')
-              parameterCostBlock.append('' + data.human_amount + '')
-
-              $(nestedProductParameter).find('.intervention_inputs_quantity').append(parameterCostBlock)
+      # $.ajax
+      #   url: "/backend/interventions/costs/parameter_cost",
+      #   data: { intervention: intervention }
+      #   success: (data, status, request) ->
+      #     if !data.human_amount.nature || data.human_amount.nature != "failed"
+      #       nestedProductParameter = $(target).closest('.nested-product-parameter')
+
+            # if $(nestedProductParameter).find('.product-parameter-cost').length > 0
+            #   $(nestedProductParameter).find('.product-parameter-cost-value').text(data.human_amount)
+            # else
+            #   parameterCostBlock = $('

')
+            #   parameterCostBlock.append('Coût : ')
+            #   parameterCostBlock.append('' + data.human_amount + '')
+            #
+            #   $(nestedProductParameter).find('.intervention_inputs_quantity').append(parameterCostBlock)

   $(document).ready ->


ensure already annotated buckets are only loaded once, fixes #952

--- app/assets/javascripts/oxalis/model/binary/cube.coffee
+++ app/assets/javascripts/oxalis/model/binary/cube.coffee
@@ -191,7 +191,7 @@
     if not bucketIndex?
       return true

-    return cube[bucketIndex]? and not cube[bucketIndex].temporal
+    return cube[bucketIndex]? and cube[bucketIndex].requested

   isBucketLoadedByZoomedAddress : (address) ->
@@ -208,6 +208,7 @@
     bucketIndex = @getBucketIndexByZoomedAddress(address)
     if not cube[bucketIndex]?
       cube[bucketIndex] = @LOADING_PLACEHOLDER
+    cube[bucketIndex].requested = true

   setBucketByZoomedAddress : (address, bucketData) ->
@@ -245,14 +246,15 @@
     voxelPerBucket = 1 << @BUCKET_SIZE_P * 3
     for i in [0...voxelPerBucket]

-      voxelData = (oldBucketData[i * @BYTE_OFFSET + j] for j in [0...@BYTE_OFFSET])
-      voxelEmpty = _.reduce(voxelData, ((memo, v) => memo and v == 0), true)
-
-      unless voxelEmpty
+      newVoxel = (newBucketData[i * @BYTE_OFFSET + j] for j in [0...@BYTE_OFFSET])
+      oldVoxel = (oldBucketData[i * @BYTE_OFFSET + j] for j in [0...@BYTE_OFFSET])
+      oldVoxelEmpty = _.reduce(oldVoxel, ((memo, v) => memo and v == 0), true)
+
+      if oldVoxelEmpty
         for j in [0...@BYTE_OFFSET]
-          newBucketData[i * @BYTE_OFFSET + j] = oldBucketData[i * @BYTE_OFFSET + j]
-
-    return newBucketData
+          oldBucketData[i * @BYTE_OFFSET + j] = newBucketData[i * @BYTE_OFFSET + j]
+
+    return oldBucketData

   setArbitraryBucketByZoomedAddress : ([bucket_x, bucket_y, bucket_z, zoomStep], bucketData) ->


waitReady method in file object

waitReady method in file object

--- app/assets/javascripts/uploadcare/files/base.js.coffee
+++ app/assets/javascripts/uploadcare/files/base.js.coffee
@@ -22,9 +22,11 @@
       @previewUrl = null
       @isImage = null
       @imageInfo = null
+      @isReady = null

       @__uploadDf = $.Deferred()
       @__infoDf = $.Deferred()
+      @__waitReadyDf = null
       @__progressState = 'uploading'
       @__progress = 0

@@ -84,8 +86,27 @@
       previewUrl: @previewUrl
       preview: @apiPromise.preview
       dimensions: if @isImage then =>
+          window.console?.warn? "'dimensions' method is deprecated. " +
+                                "Use originalImageInfo instead."
           $.Deferred().resolve(@imageInfo).promise()
         else null
+      waitReady: =>
+        @__waitReady()
+
+    __waitReady: =>
+      unless @__waitReadyDf
+        @__waitReadyDf = $.Deferred()
+        timeout = 100
+        do check = =>
+          if @isReady
+            @__waitReadyDf.resolve()
+          else
+            setTimeout =>
+              timeout += 50
+              @__requestInfo().fail(@__waitReadyDf.reject)
+                              .done(check)
+            , timeout
+      @__waitReadyDf.promise()

     __cancel: =>
       @__uploadDf.reject('user', this)


Add wantInSchool to individual create account analytics

--- app/views/core/CreateAccountModal/BasicInfoView.coffee
+++ app/views/core/CreateAccountModal/BasicInfoView.coffee
@@ -286,7 +286,7 @@
     if @signupState.get('path') is 'student'
       window.tracker?.trackEvent 'CreateAccountModal Student BasicInfoView Submit Success', category: 'Students'
     if @signupState.get('path') is 'individual'
-      window.tracker?.trackEvent 'CreateAccountModal Individual BasicInfoView Submit Success', category: 'Individuals'
+      window.tracker?.trackEvent 'CreateAccountModal Individual BasicInfoView Submit Success', category: 'Individuals', wantInSchool: @$('#want-in-school-checkbox').is(':checked')
       if @$('#want-in-school-checkbox').is(':checked')
         @signupState.set 'wantInSchool', true
     @trigger 'signup'


Server: minor code styling

Server: minor code styling

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -247,7 +247,7 @@
       else
         res.status(200).send authTemplate data

-app.post "/:name?/Validate", (req, res) ->
+app.post '/:name?/Validate', (req, res) ->
   { JUser } = koding.models
   { fields } = req.body

@@ -267,7 +267,7 @@
   res.status(if validations.isValid then 200 else 400).send validations

-app.post "/:name?/Validate/Username/:username?", (req, res) ->
+app.post '/:name?/Validate/Username/:username?', (req, res) ->

   { JUser } = koding.models
   { username } = req.params
@@ -285,7 +285,7 @@
     else
       res.status(400).send response

-app.post "/:name?/Validate/Email/:email?", (req, res) ->
+app.post '/:name?/Validate/Email/:email?', (req, res) ->

   { JUser }    = koding.models
   { email }    = req.params
@@ -318,7 +318,7 @@

-app.get "/Verify/:token", (req, res) ->
+app.get '/Verify/:token', (req, res) ->
   { JPasswordRecovery } = koding.models
   { token } = req.params

@@ -327,7 +327,7 @@

     res.redirect 301, "/Verified"

-app.post "/:name?/Register", (req, res) ->
+app.post '/:name?/Register', (req, res) ->
   { JUser } = koding.models
   context = { group: 'koding' }
   { redirect } = req.body


Nodejs: metrics: use koding-datadog middleware in server/index.coffee

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -10,6 +10,7 @@
 express               = require 'express'
 helmet                = require 'helmet'
 bodyParser            = require 'body-parser'
+datadog               = require 'koding-datadog'
 usertracker           = require '../../../workers/usertracker'
 app                   = express()
 webPort               = argv.p ? webserver.port
@@ -42,6 +43,7 @@
   app.use helmet.ienoopen()
   app.use helmet.contentTypeOptions()
   app.use helmet.hidePoweredBy()
+  app.use datadog.middleware.sendMetrics

 # handle basic auth


server: added wufoo api route

server: added wufoo api route

--- servers/lib/server/index.coffee
+++ servers/lib/server/index.coffee
@@ -82,6 +82,7 @@

 app.get  '/-/my/permissionsAndRoles'             , require './handlers/myPermissionsAndRoles'
 app.get  '/-/google-api/authorize/drive'         , require './handlers/authorizedrive'
+app.get  '/-/wufoo/submit/:identifier?'          , require './handlers/wufooproxy'
 app.post '/-/support/new', bodyParser.json()     , require './handlers/supportnew'
 # should deprecate those /Validates, they don't look like api endpoints
 app.post '/:name?/Validate/Username/:username?'  , require './handlers/validateusername'


Optimizations.

Optimizations.

--- src/CPU.coffee
+++ src/CPU.coffee
@@ -57,7 +57,7 @@
         if @dma.isTransferInProgress()
             @tick() # CPU can't access memory during DMA (empty cycle).
         else
-            @_resolveInterrupt()
+            @resolveInterrupt()
             @executeInstruction()

     ###########################################################
@@ -65,7 +65,7 @@
     ###########################################################

     resolveInterrupt: ->
-        if @requestedInterrupt and not @_isRequestedInterruptDisabled()
+        if @requestedInterrupt and not @isRequestedInterruptDisabled()
             switch @requestedInterrupt
                 when Interrupt.IRQ   then @handleIRQ()
                 when Interrupt.NMI   then @handleNMI()
@@ -112,16 +112,16 @@
         instruction addressingMode()

     readOperation: ->
-        operationCode = @readNextProgramByte()
+        operationCode = @_readNextProgramByte()
         operation = @operationsTable[operationCode]
         throw "Unsupported operation (code: 0x#{byteAsHex operationCode})" unless operation?
         operation

     readNextProgramByte: ->
-        @_readByte @_moveProgramCounter 1
+        @readByte @moveProgramCounter 1

     readNextProgramWord: ->
-        @_readWord @_moveProgramCounter 2
+        @readWord @moveProgramCounter 2

     moveProgramCounter: (size = 1) ->
         previousValue = @programCounter
@@ -140,12 +140,12 @@
         @_read address

     readWord: (address) ->
-        highByte = @_readByte (address + 1) & 0xFFFF
-        highByte << 8 | @_readByte address
+        highByte = @readByte (address + 1) & 0xFFFF
+        highByte << 8 | @readByte address

     readWordFromSamePage: (address) ->
-        highByte = @_readByte address & 0xFF00 | (address + 1) & 0x00FF
-        highByte << 8 | @_readByte address
+        highByte = @readByte address & 0xFF00 | (address + 1) & 0x00FF
+        highByte << 8 | @readByte address

     write: (address, value) ->
         @cpuMemory.write address, value
@@ -155,43 +155,43 @@
         @_write address, value

     writeWord: (address, value) ->
-        @_writeByte address, value & 0xFF
-        @_writeByte (address + 1) & 0xFFFF, value >>> 8
+        @writeByte address, value & 0xFF
+        @writeByte (address + 1) & 0xFFFF, value >>> 8

     ###########################################################
     # Stack pushing / pulling
     ###########################################################

     pushByte: (value) ->
-        @_writeByte 0x100 + @stackPointer, value
+        @writeByte 0x100 + @stackPointer, value
         @stackPointer = (@stackPointer - 1) & 0xFF

     pushWord: (value) ->
-        @_pushByte value >>> 8
-        @_pushByte value & 0xFF
+        @pushByte value >>> 8
+        @pushByte value & 0xFF

     popByte: ->
         @stackPointer = (@stackPointer + 1) & 0xFF
-        @_readByte 0x100 + @stackPointer
+        @readByte 0x100 + @stackPointer

     popWord: ->
-        @_popByte() | @_popByte() << 8
+        @popByte() | @popByte() << 8

     ###########################################################
     # Memory reading / writing cycles handling
     ###########################################################

     resolveReadCycles: ->
-        @tick()
+        @_tick()
         if @emptyReadCycles
             @emptyReadCycles--
-            @tick()
+            @_tick()

     resolveWriteCycles: ->
-        @tick()
+        @_tick()
         if @emptyWriteCycles
             @emptyWriteCycles--
-            @tick()
+            @_tick()

     tick: ->
         @cyclesCount++
@@ -240,13 +240,13 @@
     ###########################################################

     impliedMode: =>
-        @_tick()
+        @tick()

     accumulatorMode: =>
-        @_tick()
+        @tick()

     immediateMode: =>
-        @_moveProgramCounter 1
+        @moveProgramCounter()

     ###########################################################
     # Zero page addressing modes
@@ -288,13 +288,13 @@
     ###########################################################

     indirectMode: =>
-        @_readWordFromSamePage @_readNextProgramWord()
+        @readWordFromSamePage @_readNextProgramWord()

     indirectXMode: =>
-        @_readWordFromSamePage @zeroPageXMode()
+        @readWordFromSamePage @zeroPageXMode()

     indirectYMode: =>
-        base = @_readWordFromSamePage @_readNextProgramByte()
+        base = @readWordFromSamePage @_readNextProgramByte()
         @_getIndexedAddressWord base, @registerY

     ###########################################################
@@ -370,37 +370,37 @@
     ###########################################################

     LDA: (address) =>
-        @storeValueIntoAccumulator @readByte address
+        @_storeValueIntoAccumulator @readByte address

     LDX: (address) =>
-        @storeValueIntoRegisterX @readByte address
+        @_storeValueIntoRegisterX @readByte address

     LDY: (address) =>
-        @storeValueIntoRegisterY @readByte address
+        @_storeValueIntoRegisterY @readByte address

     LAX: (address) =>
         value = @readByte address
-        @storeValueIntoAccumulator value
-        @storeValueIntoRegisterX value
+        @_storeValueIntoAccumulator value
+        @_storeValueIntoRegisterX value

     ###########################################################
     # Register transfer instructions
     ###########################################################

     TAX: =>
-        @storeValueIntoRegisterX @accumulator
+        @_storeValueIntoRegisterX @accumulator

     TAY: =>
-        @storeValueIntoRegisterY @accumulator
+        @_storeValueIntoRegisterY @accumulator

     TXA: =>
-        @storeValueIntoAccumulator @registerX
+        @_storeValueIntoAccumulator @registerX

     TYA: =>
-        @storeValueIntoAccumulator @registerY
+        @_storeValueIntoAccumulator @registerY

     TSX: =>
-        @storeValueIntoRegisterX @stackPointer
+        @_storeValueIntoRegisterX @stackPointer

     TXS: =>
         @stackPointer = @registerX
@@ -410,33 +410,33 @@
     ###########################################################

     PHA: =>
-        @pushByte @accumulator
+        @_pushByte @accumulator

     PHP: =>
-        @pushByte @getStatus() | 0x10 # Pushes status with bit 4 on (break command flag).
+        @_pushByte @getStatus() | 0x10 # Pushes status with bit 4 on (break command flag).

     ###########################################################
     # Stack pop instructions
     ###########################################################

     PLA: =>
-        @storeValueIntoAccumulator @popByte()
+        @_storeValueIntoAccumulator @_popByte()

     PLP: =>
-        @setStatus @popByte()
+        @setStatus @_popByte()

     ###########################################################
     # Accumulator bitwise instructions
     ###########################################################

     AND: (address) =>
-        @storeValueIntoAccumulator @accumulator & @readByte address
+        @_storeValueIntoAccumulator @accumulator & @readByte address

     ORA: (address) =>
-        @storeValueIntoAccumulator @accumulator | @readByte address
+        @_storeValueIntoAccumulator @accumulator | @readByte address

     EOR: (address) =>
-        @storeValueIntoAccumulator @accumulator ^ @readByte address
+        @_storeValueIntoAccumulator @accumulator ^ @readByte address

     BIT: (address) =>
         value = @readByte address
@@ -449,67 +449,67 @@
     ###########################################################

     INC: (address) =>
-        @storeValueIntoMemory address, ((@readByte address) + 1) & 0xFF
+        @_storeValueIntoMemory address, ((@readByte address) + 1) & 0xFF

     INX: =>
-        @storeValueIntoRegisterX (@registerX + 1) & 0xFF
+        @_storeValueIntoRegisterX (@registerX + 1) & 0xFF

     INY: =>
-        @storeValueIntoRegisterY (@registerY + 1) & 0xFF
+        @_storeValueIntoRegisterY (@registerY + 1) & 0xFF

     ###########################################################
     # Decrement instructions
     ###########################################################

     DEC: (address) =>
-        @storeValueIntoMemory address, ((@readByte address) - 1) & 0xFF
+        @_storeValueIntoMemory address, ((@readByte address) - 1) & 0xFF

     DEX: =>
-        @storeValueIntoRegisterX (@registerX - 1) & 0xFF
+        @_storeValueIntoRegisterX (@registerX - 1) & 0xFF

     DEY: =>
-        @storeValueIntoRegisterY (@registerY - 1) & 0xFF
+        @_storeValueIntoRegisterY (@registerY - 1) & 0xFF

     ###########################################################
     # Comparison instructions
     ###########################################################

     CMP: (address) =>
-        @compareRegisterAndMemory @accumulator, address
+        @_compareRegisterAndMemory @accumulator, address

     CPX: (address) =>
-        @compareRegisterAndMemory @registerX, address
+        @_compareRegisterAndMemory @registerX, address

     CPY: (address) =>
-        @compareRegisterAndMemory @registerY, address
+        @_compareRegisterAndMemory @registerY, address

     ###########################################################
     # Branching instructions
     ###########################################################

     BCC: (address) =>
-        @branchIf not @carryFlag, address
+        @_branchIf not @carryFlag, address

     BCS: (address) =>
-        @branchIf @carryFlag, address
+        @_branchIf @carryFlag, address

     BNE: (address) =>
-        @branchIf not @zeroFlag, address
+        @_branchIf not @zeroFlag, address

     BEQ: (address) =>
-        @branchIf @zeroFlag, address
+        @_branchIf @zeroFlag, address

     BVC: (address) =>
-        @branchIf not @overflowFlag, address
+        @_branchIf not @overflowFlag, address

     BVS: (address) =>
-        @branchIf @overflowFlag,  address
+        @_branchIf @overflowFlag,  address

     BPL: (address) =>
-        @branchIf not @negativeFlag, address
+        @_branchIf not @negativeFlag, address

     BMI: (address) =>
-        @branchIf @negativeFlag, address
+        @_branchIf @negativeFlag, address

     ###########################################################
     # Jump / subroutine instructions
@@ -519,11 +519,11 @@
         @programCounter = address

     JSR: (address) =>
-        @pushWord (@programCounter - 1) & 0xFFFF # The pushed address must be the end of the current instruction.
+        @_pushWord (@programCounter - 1) & 0xFFFF # The pushed address must be the end of the current instruction.
         @programCounter = address

     RTS: =>
-        @programCounter = (@popWord() + 1) & 0xFFFF # We decremented the address when pushing it during JSR.
+        @programCounter = (@_popWord() + 1) & 0xFFFF # We decremented the address when pushing it during JSR.
         @tick()

     ###########################################################
@@ -531,95 +531,95 @@
     ###########################################################

     BRK: =>
-        @pushWord @programCounter
-        @pushByte @getStatus() | 0x10 # Pushes status with bit 4 on (break command flag).
+        @_pushWord @programCounter
+        @_pushByte @getStatus() | 0x10 # Pushes status with bit 4 on (break command flag).
         @programCounter = @readWord 0xFFFE

     RTI: =>
-        @setStatus @popByte()
-        @programCounter = @popWord()
+        @setStatus @_popByte()
+        @programCounter = @_popWord()

     ###########################################################
     # Addition / subtraction instructions
     ###########################################################

     ADC: (address) =>
-        @addValueToAccumulator @readByte address
+        @_addValueToAccumulator @readByte address

     SBC: (address) =>
-        @addValueToAccumulator (@readByte address) ^ 0xFF # Together with internal carry incremment makes negative operand.
+        @_addValueToAccumulator (@readByte address) ^ 0xFF # Together with internal carry incremment makes negative operand.

     ###########################################################
     # Shifting / rotation instructions
     ###########################################################

     ASL: (address) =>
-        @rotateAccumulatorOrMemory address, @rotateLeft, false
+        @_rotateAccumulatorOrMemory address, @rotateLeft, false

     LSR: (address) =>
-        @rotateAccumulatorOrMemory address, @rotateRight, false
+        @_rotateAccumulatorOrMemory address, @rotateRight, false

     ROL: (address) =>
-        @rotateAccumulatorOrMemory address, @rotateLeft, true
+        @_rotateAccumulatorOrMemory address, @rotateLeft, true

     ROR: (address) =>
-        @rotateAccumulatorOrMemory address, @rotateRight, true
+        @_rotateAccumulatorOrMemory address, @rotateRight, true

     ###########################################################
     # Hybrid instructions
     ###########################################################

     DCP: (address) =>
-        @compareRegisterAndOperand @accumulator, @DEC address
+        @_compareRegisterAndOperand @accumulator, @DEC address

     ISB: (address) =>
-        @addValueToAccumulator (@INC address) ^ 0xFF # Together with internal carry incremment makes negative operand.
+        @_addValueToAccumulator (@INC address) ^ 0xFF # Together with internal carry incremment makes negative operand.

     SLO: (address) =>
-        @storeValueIntoAccumulator @accumulator | @ASL address
+        @_storeValueIntoAccumulator @accumulator | @ASL address

     SRE: (address) =>
-        @storeValueIntoAccumulator @accumulator ^ @LSR address
+        @_storeValueIntoAccumulator @accumulator ^ @LSR address

     RLA: (address) =>
-        @storeValueIntoAccumulator @accumulator & @ROL address
+        @_storeValueIntoAccumulator @accumulator & @ROL address

     RRA: (address) =>
-        @addValueToAccumulator @ROR address
+        @_addValueToAccumulator @ROR address

     ###########################################################
     # Instruction helper functions
     ###########################################################

     storeValueIntoAccumulator: (value) ->
-        @updateZeroAndNegativeFlag value
+        @_updateZeroAndNegativeFlag value
         @accumulator = value

     storeValueIntoRegisterX: (value) ->
-        @updateZeroAndNegativeFlag value
+        @_updateZeroAndNegativeFlag value
         @registerX = value

     storeValueIntoRegisterY: (value) ->
-        @updateZeroAndNegativeFlag value
+        @_updateZeroAndNegativeFlag value
         @registerY = value

     storeValueIntoMemory: (address, value) ->
-        @updateZeroAndNegativeFlag value
+        @_updateZeroAndNegativeFlag value
         @writeByte address, value

     addValueToAccumulator: (operand) ->
         result = @accumulator + operand + @carryFlag
         @carryFlag = (result >>> 8) & 1
         @overflowFlag = (((@accumulator ^ result) & (operand ^ result)) >>> 7) & 1 # Signed overflow
-        @storeValueIntoAccumulator result & 0xFF
+        @_storeValueIntoAccumulator result & 0xFF

     compareRegisterAndMemory: (register, address) ->
-        @compareRegisterAndOperand register, @readByte address
+        @_compareRegisterAndOperand register, @readByte address

     compareRegisterAndOperand: (register, operand) ->
         result = register - operand
         @carryFlag = result >= 0 # Unsigned comparison (bit 8 is actually the result sign).
-        @updateZeroAndNegativeFlag result # Not a signed comparison
+        @_updateZeroAndNegativeFlag result # Not a signed comparison

     branchIf: (condition, address) ->
         if condition
@@ -629,10 +629,10 @@
     rotateAccumulatorOrMemory: (address, rotation, transferCarry) ->
         if address?
             result = rotation (@readByte address), transferCarry
-            @storeValueIntoMemory address, result
+            @_storeValueIntoMemory address, result
         else
             result = rotation @accumulator, transferCarry
-            @storeValueIntoAccumulator result
+            @_storeValueIntoAccumulator result

     rotateLeft: (value, transferCarry) =>
         value = value << 1 | transferCarry & @carryFlag


Save local changes to server after login.

--- app/client/js/firebase.coffee
+++ app/client/js/firebase.coffee
@@ -15,6 +15,11 @@
     @type {Firebase}
   ###
   userRef: null
+
+  ###*
+    @type {boolean}
+  ###
+  userJustLogged: false

   ###*
     @protected
@@ -62,12 +67,24 @@
   ###
   onUserLogin: (user) ->
     @userRef = @userRefOf user
+    @userJustLogged = true
+    # The problem with Firebase on 'value' is, that this method is dispatched
+    # two times when Firebase.ServerValue.TIMESTAMP is used.
+    # 1. locally made change
+    # 2. server with updated TIMESTAMP value.
     @userRef.on 'value',
       (snap) =>
         # Can be null for new users.
         val = snap.val()
+        # This check is used to ignore local Firebase changes.
+        # TODO: Consider splitting to localUpdated and serverUpdated.
         return if val && val.updated == @userStore.updated
         @userStore.updateFromServer user, val
+        # When user is logged, sync local changes to server.
+        if @userJustLogged
+          @userJustLogged = false
+          @userStore.notify()
+
     , (error) ->
       # TODO: Report to server.
       if goog.DEBUG
@@ -84,6 +101,7 @@
       .child user.uid

   onUserLogout: ->
+    @userJustLogged = false
     @userRef?.off 'value'
     @userStore.onLogout !!@userRef


release the lock if it took too long to acquire it

--- app/coffee/LockManager.coffee
+++ app/coffee/LockManager.coffee
@@ -41,7 +41,10 @@
 				metrics.inc "doc-not-blocking"
 				timeTaken = profile.log("got lock").end()
 				if timeTaken > MAX_REDIS_REQUEST_LENGTH
-					callback err, false # took too long to get the lock, bail out
+					# took too long, so try to free the lock
+					LockManager.releaseLock doc_id, lockValue, (err, result) ->
+						return callback(err) if err? # error freeing lock
+						callback null, false # tell caller they didn't get the lock
 				else
 					callback err, true, lockValue
 			else


added mediator back in temporarily

added mediator back in temporarily

--- app/models/data_source.coffee
+++ app/models/data_source.coffee
@@ -18,12 +18,16 @@
     if @isExternal()
       @get('data').fetch
         success: =>
-          @trigger 'data-received'
+          @onSetData()
     else
       source = @get('tools').find (tool) =>
         tool.get('channel') == @get('source')
       @set('data', source.get('dataSource').get('data'))
-      @trigger 'data-received'
+      @onSetData()
+
+  onSetData: =>
+    @trigger 'data-received'
+    Backbone.Mediator.publish 'data-received' # Temp

   createNewData: =>
     sourceType = @sourceToCollection()


Hide button in frontend

Hide button in frontend

--- resources/assets/coffee/react/beatmap-discussions/nominations.coffee
+++ resources/assets/coffee/react/beatmap-discussions/nominations.coffee
@@ -54,8 +54,6 @@
       hype = _.min([requiredHype, hypeRaw])
       userAlreadyHyped = _.find(@props.currentDiscussions.byFilter.hype.generalAll, user_id: @props.currentUser.id)?

-    userCanNominate = @props.currentUser.is_admin || @props.currentUser.is_bng || @props.currentUser.is_qat
-    userCanDisqualify = @props.currentUser.is_admin || @props.currentUser.is_qat
     mapCanBeNominated = @props.beatmapset.status == 'pending' && hypeRaw >= requiredHype
     mapIsQualified = (@props.beatmapset.status == 'qualified')

@@ -150,16 +148,16 @@
                     " #{nominations.current}/#{nominations.required}"
                 @renderLights(nominations.current, nominations.required)

-              if currentUser.id?
+              if @props.currentUser.id?
                 div className: "#{bn}__row-right",
-                  if userCanDisqualify && mapIsQualified
+                  if mapIsQualified && @userCanDisqualify()
                     el BigButton,
                       modifiers: ['full']
                       text: osu.trans 'beatmaps.nominations.disqualify'
                       icon: 'fas fa-thumbs-down'
                       props:
                         onClick: @focusNewDiscussionForDisqualification
-                  else if userCanNominate && mapCanBeNominated
+                  else if mapCanBeNominated && @userCanNominate()
                     if @props.currentDiscussions.unresolvedIssues > 0
                       # wrapper 'cuz putting a title/tooltip on a disabled button is no worky...
                       div title: osu.trans('beatmaps.nominations.unresolved_issues'),
@@ -313,3 +311,15 @@
       discussion: parsedEvent.link
       message: parsedEvent.message
       user: osu.link laroute.route('users.show', user: parsedEvent.user.id), parsedEvent.user.username
+
+
+  userCanNominate: =>
+    !@userIsOwner() && (@props.currentUser.is_admin || @props.currentUser.is_bng || @props.currentUser.is_qat)
+
+
+  userCanDisqualify: =>
+    !@userIsOwner() && (@props.currentUser.is_admin || @props.currentUser.is_qat)
+
+
+  userIsOwner: =>
+    @props.currentUser? && @props.currentUser.id == @props.beatmapset.user_id


Fix modal behavior.

Fix modal behavior.

--- src/javascript/all.coffee
+++ src/javascript/all.coffee
@@ -1,6 +1,5 @@
 j11 = jQuery.noConflict true
 j11.blockUI.defaults.css = cursor: 'auto'
-
 # control function

 bane =
@@ -30,8 +29,8 @@
 target = null

 pop_widget = (wid) -> (e) ->
-    # TODO: set widget position
-    target = j11 e.target
+    target = j11 @
+    return j11.unblockUI() if 1000 < target.css 'z-index'
     target.css('z-index', 1011)
     wid.css('opacity', 0)
     j11.blockUI
@@ -191,7 +190,8 @@
 (j11 '#initi').click initialize
 (j11 '#save_setting').click ->
     v = (j11 '#formhp').val()
-    document.cookie = 'hp_point=' + v if v
+    document.cookie = 'hp_point=' + v unless isNaN Number v
+    (j11 '#setwindow').modal('hide')

 # prevent bootstrap modal from steal focus.
 (j11 '#setwindow *').bind 'click mouseup mousedown keypress keydown keyup', (e) ->


Gulpfile: Template: drop fullpaths from browserify bundles

--- app/templates/gulpfile.coffee
+++ app/templates/gulpfile.coffee
@@ -60,7 +60,7 @@
   globalBundler  = browserify
     cache        : {}
     packageCache : {}
-    fullPaths    : {}
+    fullPaths    : no
     entries      : [ paths.scripts.source ]
     extensions   : [ '.coffee' ]
     transform    : [ 'coffeeify' ]
@@ -76,7 +76,7 @@
   vendorBundler = browserify
     cache        : {}
     packageCache : {}
-    fullPaths    : {}
+    fullPaths    : no
     require      : 'kd.js'
     debug        : !production


Fix the numPages computed property

Fix the numPages computed property

--- app/assets/javascripts/rglossa/controllers/corpus/result/toolbar_controller.coffee
+++ app/assets/javascripts/rglossa/controllers/corpus/result/toolbar_controller.coffee
@@ -37,7 +37,7 @@
   numPages: (->
     numHits = @get('search.numHits')
     if numHits is 0 then 0 else Math.floor((numHits - 1) / @pageSize) + 1
-  ).property('search')
+  ).property('search.numHits')

   hasMoreThanOnePage: (->
     @get('numPages') > 1


Add real wallet pin

Add real wallet pin

--- app/src/controllers/onboarding/device/onboarding_device_pin_view_controller.coffee
+++ app/src/controllers/onboarding/device/onboarding_device_pin_view_controller.coffee
@@ -10,8 +10,12 @@
     @view.pinCode.setStealsFocus(yes)
     @view.pinCode.once 'complete', (event, value) =>
       ledger.app.wallet.unlockWithPinCode value, (success, retryCount) =>
-        l success
-        l retryCount
+        if success == yes
+          ledger.app.router.go '/onboarding/device/opening'
+        else if retryCount > 0
+          ledger.app.router.go '/onboarding/device/wrongpin', {tries_left: retryCount}
+        else
+          ledger.app.router.go '/onboarding/device/frozen'

   openSupport: ->
     window.open t 'application.support_url'


try to solve mysql problems

try to solve mysql problems

--- lib/adapters.coffee
+++ lib/adapters.coffee
@@ -9,9 +9,7 @@
 				"id int not null auto_increment," +
 				"primary key(id)" +
 				")"
-			@db.query query, (err) ->
-				console.log err
-		console.log @db
+			@db.query query

 	save: (model, callback) ->
 		#@db.query 'INSERT INTO t1 values (2, "stas")'


test name if displayName isn't set

test name if displayName isn't set

component classes use the class name

--- shared/src/helpers/react.coffee
+++ shared/src/helpers/react.coffee
@@ -10,7 +10,7 @@
 kebabCase      = require 'lodash/kebabCase'
 browser        = require 'detect-browser'

-getBaseName = (context) -> kebabCase(context.constructor.displayName)
+getBaseName = (context) -> kebabCase(context.constructor.displayName || context.constructor.name)

 PASSABLE_PROPS = ['className', 'id', 'children', 'target', 'ref', 'tabIndex', 'role']


Remove log statement

Remove log statement

--- src/keymap-manager.coffee
+++ src/keymap-manager.coffee
@@ -234,7 +234,6 @@
           console.warn "Empty command for binding: `#{selector}` `#{keystrokes}` in #{source}"
           return

-        console.log 'adding', keystrokes, command
         if normalizedKeystrokes = normalizeKeystrokes(keystrokes)
           keyBinding = new KeyBinding(source, command, normalizedKeystrokes, selector)
           addedKeyBindings.push(keyBinding)


then true else false is always redundant

--- countUp.coffee
+++ countUp.coffee
@@ -29,7 +29,7 @@

     startVal = Number startVal
     endVal = Number endVal
-    @countDown = if startVal > endVal then true else false
+    @countDown = startVal > endVal # specify direction of count
     decimals = Math.max(0, decimals)
     @dec = Math.pow(10, decimals)
     @frameVal = startVal


Use position: absolute instead of relative for better positioning

@martijn?

--- js-library/app/js/jail_iframe/classes/proxy_message.coffee
+++ js-library/app/js/jail_iframe/classes/proxy_message.coffee
@@ -15,6 +15,6 @@
   frame.$el.css
     top: '10px'
     left: '10px'
-    position: 'relative'
+    position: 'absolute'

   frame.fadeIn()


Use the bbox for offset as well

Use the bbox for offset as well

--- core/app/backbone/factlink/positioned_region.coffee
+++ core/app/backbone/factlink/positioned_region.coffee
@@ -67,8 +67,8 @@
         throw "Invalid options.side: #{@options.side}"

   _bindElPosition: ->
-    elOffset = @$bindEl.offset()
-    containerOffset = @$container.offset()
+    elOffset = @_offsetOf @$bindEl
+    containerOffset = @_offsetOf @$container

     left: elOffset.left - containerOffset.left
     top:  elOffset.top  - containerOffset.top
@@ -95,6 +95,15 @@
       width: $el.outerWidth()
       height: $el.outerHeight()

+  _offsetOf: ($el) ->
+    if bbox = $el[0].getBBox?()
+      containerOffset = $el.parents().filter(-> !@getBBox?).first().offset()
+
+      top: bbox.y + containerOffset.top,
+      left: bbox.x + containerOffset.left
+    else
+      $el.offset()
+
   _checkContainer: ->
     unless @$container.css('position') in ['relative', 'absolute', 'fixed']
       console.error "Container is not positioned", @$container


Finish fixing the build

Finish fixing the build

--- src/languages/html.coffee
+++ src/languages/html.coffee
@@ -233,8 +233,8 @@

   genBounds: (location) ->
     bounds = {
-      start: @positions[location.startOffset]
-      end: @positions[location.endOffset]
+      start: @positions[location.start]
+      end: @positions[location.end]
     }

     return bounds
@@ -307,8 +307,6 @@
           i++

   fixBounds: (node) ->
-    console.log "__location: #{JSON.stringify(node.__location)}"
-
     if not node
       return

@@ -378,9 +376,7 @@
   trimText: (node) ->
     location = node.__location
     location.endOffset = Math.min location.endOffset, @getEndPoint node
-    console.log "calling trimText on node #{node.type}"
     text = @text[location.startOffset...location.endOffset].split '\n'
-    console.log "text length is #{text.length} location is #{JSON.stringify(location)}"
     i = 0
     while text[i].trim().length is 0
       location.startOffset += text[i].length + 1


Improved code quality.

Improved code quality.

--- client/Framework/components/tabs/KDTabView.coffee
+++ client/Framework/components/tabs/KDTabView.coffee
@@ -48,11 +48,11 @@
       @panes.push paneInstance
       tabHandleClass = @getOptions().tabHandleView ? KDTabHandleView
       @addHandle newTabHandle = new tabHandleClass
-        pane    : paneInstance
-        title   : paneInstance.options.name
-        hidden  : paneInstance.options.hiddenHandle
-        view    : paneInstance.options.tabHandleView
-        sortable: @getOptions().sortable
+        pane      : paneInstance
+        title     : paneInstance.options.name
+        hidden    : paneInstance.options.hiddenHandle
+        view      : paneInstance.options.tabHandleView
+        sortable  : @getOptions().sortable

       paneInstance.tabHandle = newTabHandle
       @listenTo
@@ -148,11 +148,9 @@
   showHandleCloseIcons:()->
     @tabHandleContainer.$().removeClass "hide-close-icons"

-
   handleMouseDownDefaultAction:(clickedTabHandle,event)->
-    for handle,index in @handles
-      if clickedTabHandle is handle
-        @handleClicked(index,event)
+    for handle, index in @handles when clickedTabHandle is handle
+      @handleClicked index, event

   # DEFAULT ACTIONS
   handleClicked:(index,event)=>


remove line width for country and regions highlighted on map

--- app/assets/javascripts/protected_area_map.js.coffee
+++ app/assets/javascripts/protected_area_map.js.coffee
@@ -6,11 +6,12 @@

   _addSelectedStyle: (args) ->
-    opacity = args.opacity or .5
+    opacity = if args.opacity? then args.opacity else .5
+    lineWidth = if args.lineWidth? then args.lineWidth else 1
     args.cartocss += """
       ##{args.table}[#{args.attrName} = #{args.attrVal}]{
         line-color:#D41623;
-        line-width:1;
+        line-width:#{lineWidth};
         polygon-fill:#E43430;
         polygon-opacity:#{opacity};}
     """
@@ -33,6 +34,7 @@
       attrName: 'iso_3'
       attrVal: "'#{tileConfig.iso3}'"
       opacity: .2
+      lineWidth: 0

     sublayers.push
       sql: "select * from #{args.table} where iso_3 = '#{tileConfig.iso3}'"
@@ -46,6 +48,7 @@
       attrName: 'continent'
       attrVal: "'#{tileConfig.regionName}'"
       opacity: .2
+      lineWidth: 0

     sublayers.push
       sql: "select * from #{args.table} where continent = '#{tileConfig.regionName}'"


Don't do the image fetching song and dance on the client when submitting a post

--- app/assets/javascripts/sugar/posts/submit.js.coffee
+++ app/assets/javascripts/sugar/posts/submit.js.coffee
@@ -31,86 +31,8 @@
     else
       form.submit()

-  # Prepare post for submissin
-  prepare_submission = (form) ->
-    body = $("#compose-body").val()
-
-    # Abort if the post is empty
-    return false  if body.replace(/\s+/, "") is ""
-
-    if $.browser.msie
-      # Don't do anything fancy in IE, just submit the post
-      # without AJAX.
-      $(Sugar).trigger "posting-status", [ "Posting…" ]
-
-    else
-      $(Sugar).trigger "posting-status", [ "Validating post…" ]
-
-      # Auto-link URLs
-      body = body.replace(/(^|\s)((ftp|https?):\/\/[^\s]+\b\/?)/g, "$1$2")
-
-      # Inject the post in a hidden

-      if $("#hiddenPostVerifier").length < 1
-        $(document.body).append "

"
-      post_verifier = $("#hiddenPostVerifier")
-      post_verifier.show()
-      post_verifier.html body
-      post_verifier.hide()
-
-      # Make links to the same domain relative
-      current_domain = document.location.toString().match(/^(https?:\/\/[\w\d\-\.:]+)/)[1]
-      post_links = post_verifier.find("a")
-      if post_links.length > 0
-        a = 0
-        while a < post_links.length
-          post_links[a].href = post_links[a].href.replace(current_domain, "")
-          a += 1
-        $("#compose-body").val post_verifier.html()
-
-      # Preload images, detect height and width
-      post_images = post_verifier.find("img")
-      loaded_images = []
-      if post_images.length > 0
-
-        # Async loading event
-        post_images.each ->
-          $(this).load ->
-            loaded_images.push this
-
-        # Check loading of images
-        post_verifier.cycles = 0
-        post_verifier.load_interval = setInterval(->
-          post_verifier.cycles += 1
-          $(Sugar).trigger "posting-status", [ "Loading image " + loaded_images.length + " of " + post_images.length + "…" ]
-
-          # Handle failure
-          if post_verifier.cycles >= 80
-            clearInterval post_verifier.load_interval
-            if confirm("One or more of your images timed out. Post anyway?")
-              $(loaded_images).each ->
-                $(this).attr "height", @height
-                $(this).attr "width", @width
-
-              $("#compose-body").val post_verifier.html()
-              submit_post form
-            else
-              $(Sugar).trigger "posting-complete"
-
-          # All images loaded
-          if loaded_images.length is post_images.length
-            post_images.each ->
-              $(this).attr "height", @height
-              $(this).attr "width", @width
-
-            $("#compose-body").val post_verifier.html()
-            clearInterval post_verifier.load_interval
-            submit_post form
-        , 100)
-        false
-      else
-        submit_post form
-        false
-
   # Form event handler
   $("#replyText form").submit ->
-    prepare_submission this
+    unless $(this).find("#compose-body").val().replace(/\s+/, "") is ""
+      submit_post this
+    false


Fixed dropzone scroll bug.

Fixed dropzone scroll bug.

--- app/assets/javascripts/views/clouds/drops.js.coffee
+++ app/assets/javascripts/views/clouds/drops.js.coffee
@@ -38,9 +38,8 @@
     @collection.on 'remove', (model,collection) =>
       @removeDrop(model)

-
     $(@el).on 'scroll', =>
-      if $(window).scrollTop() > $(document).height() - $(window).height() - 100
+      if $(@el).scrollTop() > (@el.scrollHeight - $(@el).innerHeight() - 100)
         @fetchMore() unless @collection.lastPage() or @currentlyLoading

   unbindEvents: ->


Fix permissions picker

Fix permissions picker


improve outdent list on enter

improve outdent list on enter

--- lib/commands.coffee
+++ lib/commands.coffee
@@ -17,26 +17,38 @@

   insertNewLine: ->
     editor = atom.workspace.getActiveTextEditor()
-    line = editor.lineTextForBufferRow(editor.getCursorBufferPosition().row)
-
+    cursor = editor.getCursorBufferPosition()
+
+    # find potential replace line
+    line = editor.lineTextForBufferRow(cursor.row)
     {replaceLine, value} = @_findNewLineValue(line)

+    # hanlde outdent/list label for replace line
+    indentation = editor.indentationForBufferRow(cursor.row)
+    if replaceLine && indentation > 0
+      for row in [(cursor.row - 1)..0]
+        line = editor.lineTextForBufferRow(row)
+        break unless @_isListLine(line)
+        break if editor.indentationForBufferRow(row) == indentation - 1
+      {value} = @_findNewLineValue(line)
+    else value = "\n#{value}"
+
+    # insert new line
     editor.selectToBeginningOfLine() if replaceLine
-    editor.insertText(value)
-    editor.outdentSelectedRows() if replaceLine
+    editor.insertText(value || "\n")

   _findNewLineValue: (line) ->
     if matches = LIST_TL_REGEX.exec(line)
-      value = "\n#{matches[1]}- [ ] "
+      value = "#{matches[1]}- [ ] "
     else if matches = LIST_UL_REGEX.exec(line)
-      value = "\n#{matches[1]}#{matches[2]} "
+      value = "#{matches[1]}#{matches[2]} "
     else if matches = LIST_OL_REGEX.exec(line)
-      value = "\n#{matches[1]}#{parseInt(matches[2], 10) + 1}. "
+      value = "#{matches[1]}#{parseInt(matches[2], 10) + 1}. "

     if matches && !matches[3]
-      return replaceLine: true, value: matches[1] || "\n"
+      return replaceLine: true, value: matches[1]
     else
-      return replaceLine: false, value: value || "\n"
+      return replaceLine: false, value: value || ""

   indentListLine: ->
     editor = atom.workspace.getActiveTextEditor()


add go to previous error

add go to previous error

--- lib/commands.coffee
+++ lib/commands.coffee
@@ -5,13 +5,15 @@
     @subscriptions = new CompositeDisposable
     @subscriptions.add atom.commands.add 'atom-workspace',
       'linter:next-error': => @nextError()
+      'linter:previous-error': => @previousError()
       'linter:toggle': => @toggleLinter()
       'linter:set-bubble-transparent': => @setBubbleTransparent()
       'linter:expand-multiline-messages': => @expandMultilineMessages()
       'linter:lint': => @lint()

     # Default values
-    @messages = null
+    @firstRun = true
+    @index = 0

   toggleLinter: ->
     @linter.getActiveEditorLinter()?.toggleStatus()
@@ -51,10 +53,24 @@
       atom.notifications.addError error.message, {detail: error.stack, dismissable: true}

   nextError: ->
-    if not @messages or (next = @messages.next()).done
-      next = (@messages = @linter.views.getMessages().values()).next()
-    return if next.done # There's no errors
-    message = next.value
+    if @firstRun
+      @firstRun = false
+    else
+      @index++
+    messages = @linter.views.messages
+    message = messages[@index %% messages.length]
+    return unless message.filePath
+    return unless message.range
+    atom.workspace.open(message.filePath).then ->
+      atom.workspace.getActiveTextEditor().setCursorBufferPosition(message.range.start)
+
+  previousError: ->
+    if @firstRun
+      @firstRun = false
+    else
+      @index--
+    messages = @linter.views.messages
+    message = messages[@index %% messages.length]
     return unless message.filePath
     return unless message.range
     atom.workspace.open(message.filePath).then ->


reset form and change route instead of just animating to login as latter does not change the route and recover link does not work anymore (since it thinks it's there already)

--- client/landing/app/MainApp/login/loginview.coffee
+++ client/landing/app/MainApp/login/loginview.coffee
@@ -149,7 +149,9 @@
         new KDNotificationView
           title : "An error occurred: #{err.message}"
       else
-        @animateToForm "login"
+        @recoverForm.reset()
+        {entryPoint} = KD.config
+        KD.getSingleton('router').handleRoute '/Login', {entryPoint}
         new KDNotificationView
           title     : "Check your email"
           content   : "We've sent you a password recovery token."


Set focus on proper inputs when login/register form changes

--- client/landing/app/MainApp/login/loginview.coffee
+++ client/landing/app/MainApp/login/loginview.coffee
@@ -386,6 +386,16 @@
       @emit "LoginViewAnimated", name
       @setClass name

+      switch name
+        when "join"
+          @requestForm.email.input.setFocus()
+        when "register"
+          @registerForm.invitationCode.input.setFocus()
+        when "login"
+          @loginForm.username.input.setFocus()
+        when "recover"
+          @recoverForm.usernameOrEmail.input.setFocus()
+
   getRouteWithEntryPoint:(route)->
     {entryPoint} = KD.config
     if entryPoint and entryPoint.slug isnt 'koding'


Tests: environmnets: fixed for sidebar selector.

--- client/test/lib/helpers/environmenthelpers.coffee
+++ client/test/lib/helpers/environmenthelpers.coffee
@@ -197,7 +197,7 @@

   clickAddVMButton: (browser) ->

-    sidebarTitle = '[testpath=main-sidebar] .activity-sidebar .vms .sidebar-title'
+    sidebarTitle = '[testpath=main-sidebar] .activity-sidebar .my-machines .sidebar-title'

     browser
       .waitForElementVisible   '[testpath=main-sidebar]', 20000
@@ -285,7 +285,7 @@
       .waitForElementVisible  nicknameInput, 20000
       .clearValue             nicknameInput
       .setValue               nicknameInput, name + '\n'
-
+

   reinitVM: (browser) ->


turns out we got bit by coffeescript's change to using @args without the @ in ctors

--- lib/compiler.coffee
+++ lib/compiler.coffee
@@ -306,13 +306,13 @@
                         isNull            : true

                 @llvm_intrinsics =
-                        gcroot: -> module.getOrInsertIntrinsic "@llvm.gcroot"
-
-                @ejs_runtime = runtime.createInterface module, @abi
-                @ejs_binops = runtime.createBinopsInterface module, @abi
-                @ejs_atoms = runtime.createAtomsInterface module
-                @ejs_globals = runtime.createGlobalsInterface module
-                @ejs_symbols = runtime.createSymbolsInterface module
+                        gcroot: => @module.getOrInsertIntrinsic "@llvm.gcroot"
+
+                @ejs_runtime = runtime.createInterface @module, @abi
+                @ejs_binops = runtime.createBinopsInterface @module, @abi
+                @ejs_atoms = runtime.createAtomsInterface @module
+                @ejs_globals = runtime.createGlobalsInterface @module
+                @ejs_symbols = runtime.createSymbolsInterface @module

                 @module_atoms = Object.create null
                 @literalInitializationFunction = @module.getOrInsertFunction "_ejs_module_init_string_literals_#{@filename}", types.void, []


setinterval

setinterval

--- lib/cowriter.coffee
+++ lib/cowriter.coffee
@@ -1,5 +1,5 @@
 CowriterView = require './cowriter-view'
-diff = require 'diff'
+Diff = require 'diff'
 AV = require 'avoscloud-sdk'
 {CompositeDisposable} = require 'atom'
 AV.initialize 'APPID','APPKEY'
@@ -13,17 +13,34 @@
     @cowriterView = new CowriterView(state.cowriterViewState)
     @modalPanel = atom.workspace.addModalPanel(item: @cowriterView.getElement(), visible: false)

-    @textBuffer = ''
-    Acticles = AV.Object.extend 'Acticles'
-    @acticle = new Acticles()
+    # Current document's title
+    @title= 'demo'
+
+    # Save new diff
+    @Acticles = AV.Object.extend 'Acticles'
+
+    # Query for new diff
+    @query = new AV.Query 'Acticles'
+
+    # Base time for syncing
+    @syncTime = new Date()
+
     @editor = atom.workspace.getActiveTextEditor()
+    @oldText = ''
+    @newText = ''

     # Events subscribed to in atom's system can be easily cleaned up with a CompositeDisposable
     @subscriptions = new CompositeDisposable

     # Register command that toggles this view
     @subscriptions.add atom.commands.add 'atom-workspace', 'cowriter:toggle': => @toggle()
+
+    # Server: Sends changes when change stops
     @subscriptions.add @editor.onDidStopChanging => @stop()
+
+    # May suffered from unsafe-eval of CSP
+    # Cilent: Refresh view every 3 seconds
+    @interval = setInterval ( => @getDiff() ), 3000

   deactivate: ->
     @modalPanel.destroy()
@@ -34,16 +51,50 @@
     cowriterViewState: @cowriterView.serialize()

   stop: ->
-    textBuffer = @editor.getText()
-    @save(textBuffer)
-    @cowriterView.setContent(@textBuffer)
+    @newText = @editor.getText()
+    diff = Diff.diffChars(@oldText, @newText)
+    @oldText = @newText
+    @saveCompressedDiff(@compressDiff(diff))
+    console.log(diff)
+    @cowriterView.setContent(diff.toString())

-  save: (text) ->
-    @acticle.save { 'demo': text }, { success: (object) -> alert 'LeanCloud works!' }
+  compressDiff: (diff) ->
+    # Better truncate removed value as well
+    compress = (item) ->
+      if item['added'] == undefined && item['removed'] == undefined
+        item['value'] = null
+      return item
+    # Truncate the values don't change
+    compress item for item in diff
+
+  saveCompressedDiff: (compressedDiff) ->
+    acticle = new @Acticles()
+    acticle.save {
+      'diff': compressedDiff,
+      'document': @document
+      }, {
+      success: (object) ->
+        @syncTime = object.updatedAt
+        console.log 'syncTime ' + object.updatedAt
+      }
+
+  getDiff: ->
+    # Only gets the newest changes
+    @query.greaterThan 'updatedAt', @syncTime
+    @query.equalTo 'document', @title
+    @query.find().then (response) ->
+      console.log 'success'
+      console.log response
+
+  # applyDiff: (diff) ->
+

   toggle: ->
-    console.log 'Cowriter was toggled!'
     if @modalPanel.isVisible()
+      # Clear the interval
+      clearInterval @interval
+      console.log 'Cowriter closed!'
       @modalPanel.hide()
     else
       @modalPanel.show()
+      console.log 'Cowriter opened!'


.

Former-commit-id: 3163ab7bfa3ac9e26113e819a71b5b0d558d61a0 [formerly 29dc83b8e1570a471d4bfd24988ed847b1723c6f] [formerly 605c0f4f48bf3644f022c3d13132c5b548694a5b [formerly d7c8391be91a1f07562e43dfc2ea50b572ae0759]] [formerly ab64ae73f96f4a6a190730bffb9aee8ebd2bdb87 [formerly 3293a8a2d5d611607620c866ed25f2311a30cccc] [formerly 2ef759a9a34220623a0600c6255a4ded982f389a [formerly 2ef759a9a34220623a0600c6255a4ded982f389a [formerly 34086debb1a3003ef1cc3df2b372933e93d0ee12]]]]
Former-commit-id: 3f741e0fbe040638bf8b554872b475df14a4061a [formerly aca072ce2316e31a28ac62242dbe8eb7bf3ccc2e] [formerly 16e931671944c7b8ce8d04595c583ea3e9b91525 [formerly ae3ff0bf331a9b9388c530c8cc54fe07d3bb8927]]
Former-commit-id: 79b09a001b88829d1beb783a40c700ef9996482e [formerly e67091010bbbdf1b0aa48beed907916f034dc276]
Former-commit-id: e2e6511d72959406c62948b3f313fef889449fac
Former-commit-id: a947e3a161a42fba5598610527b53770c06d5fa9

--- @client/franklin.coffee
+++ @client/franklin.coffee
@@ -2500,7 +2500,7 @@
                   L#{guidelines_w},33
                   Z
                  """
-          DI
+          DIV
             style:
               padding: '14px 18px'
               position: 'relative'


Fix paths in app

Fix paths in app

--- src/app.coffee
+++ src/app.coffee
@@ -10,14 +10,14 @@

 # view engine setup

-app.set 'views', path.join(__dirname, 'views')
+app.set 'views', path.join(__dirname, '..', 'views')
 app.set 'view engine', 'jade'
 app.use favicon()
 app.use logger('dev')
 app.use bodyParser.json()
 app.use bodyParser.urlencoded()
 app.use cookieParser()
-app.use express.static(path.join(__dirname, 'public'))
+app.use express.static(path.join(__dirname, '..', 'public'))

 app.use '/', routes


slidingObjectView: bugfix test: incorrect width

css isn't always appended, and its absence was causing troubles. in some
contexts this bug was cancelling out a second bug, which was that a
100px width was being assigned to the wrong element

--- coffee/test/views/sliding_object_view.spec.coffee
+++ coffee/test/views/sliding_object_view.spec.coffee
@@ -11,6 +11,7 @@

   util = athena.lib.util
   test = util.test
+  acorn.util.appendCss()

   defaultOpts = ->
@@ -233,7 +234,9 @@

         for location in locations
           [sov, object] = setupSOV location: location
-          sov.$el.width(100).css 'position', 'relative'
+
+          # these values are set by css, but sometimes appendCss does not work
+          sov.$('.padded-box').width(100).css 'position', 'absolute'

           $player = $('<div>').addClass('acorn-player').width(600).height(400)
               .appendTo('body')


Enhancement to enable code integration with an Iron Router project.  Without this, I found that dragging and dropping files didn't work.

--- sample.coffee
+++ sample.coffee
@@ -19,13 +19,16 @@

 if Meteor.isClient

+   # This assigns a file drop zone to the "file table"
+   # once DOM is ready so jQuery can see it
+   Template.collTest.onRendered ->
+     myData.resumable.assignDrop $('.fileDrop')
+     return
+
    Meteor.startup () ->

       ################################
       # Setup resumable.js in the UI
-
-      # This assigns a file drop zone to the "file table"
-      myData.resumable.assignDrop $(".fileDrop")

       # When a file is added
       myData.resumable.on 'fileAdded', (file) ->


Add a test for buffer as parameter

Add a test for buffer as parameter

--- test/crc.spec.coffee
+++ test/crc.spec.coffee
@@ -6,3 +6,8 @@
     string = '1234567890'
     expected = '0d'
     crc.crc1(string).should.equal expected
+
+  it 'buffer as parameter is also support', ->
+    buffer =  new Buffer '1234567890'
+    expected = '0d'
+    crc.crc1(buffer).should.equal expected


Remove unused methods

Remove unused methods

--- core/app/backbone/factlink/base_controller.coffee
+++ core/app/backbone/factlink/base_controller.coffee
@@ -15,19 +15,16 @@
       @stopListening()
       @openController() unless @started
       @listenTo FactlinkApp.vent, 'controller:switch', @closeController
-      @onAction?()
       @[name](args...)

   # CONSIDER THIS DEPRECATED, as it is only used by CachingController, which is deprecated
   openController: ->
     FactlinkApp.vent.trigger 'controller:switch'
     @started = true
-    @onShow() if @onShow?

   # CONSIDER THIS DEPRECATED, as it is only used by CachingController, which is deprecated
   closeController: ->
     @stopListening()
     @started = false
-    @onClose() if @onClose?

 Backbone.Factlink.BaseController.extend = Backbone.View.extend


Clean up global React

Clean up global React

--- app/main.cjsx
+++ app/main.cjsx
@@ -1,6 +1,6 @@
 # @cjsx React.DOM

-React = window.React = require 'react'
+React = require 'react'
 loginStore = require './data/login'
 MainHeader = require './partials/main-header'
 Route = require './lib/route'
@@ -65,3 +65,7 @@

 login = require './data/login'
 login.check()
+
+# For React DevTools Chrome plugin:
+unless process.env.NODE_ENV is 'production'
+  window.React = React


add -s, --sgml-line-break command-line option

--- src/cli.coffee
+++ src/cli.coffee
@@ -11,17 +11,18 @@
     command.version @_getVersion()
     command
     .option '-o, --output <dir>', 'the output directory for converted b-html'
-    .action (file, { output } = {}) =>
-      @_compileRecursive file, dir: output
+    .option '-s, --sgml-line-break', 'ignore line break following a start tag and before an end tag'
+    .action (file, { output, sgmlLineBreak } = {}) =>
+      @_compileRecursive file, dir: output, removeWhiteSpace: sgmlLineBreak
     command.execute()
     .catch (e) ->
       console.error e

-  _compile: (srcFile, { dir } = {}) ->
+  _compile: (srcFile, { dir, removeWhiteSpace } = {}) ->
     ext = path.extname srcFile
     return if ext isnt '.html'
     data = fs.readFileSync srcFile, encoding: 'utf-8'
-    bhtml = html2bhtml data
+    bhtml = html2bhtml data, { removeWhiteSpace }
     dir ?= path.dirname srcFile
     base = path.basename srcFile, ext
     dstFile = path.join dir, base + '.bhtml'


changing keymap

changing keymap

--- keymaps/javascript-refactoring.cson
+++ keymaps/javascript-refactoring.cson
@@ -8,4 +8,4 @@
 # For more detailed documentation see
 # https://atom.io/docs/latest/advanced/keymaps
 'atom-workspace':
-  'ctrl+f11': 'javascript-refactoring:instrumentAllFunctions'
+  'ctrl-l ctrl-r': 'javascript-refactoring:instrumentAllFunctions'


Fix debug log in tests

Fix debug log in tests

--- test/surveyor.coffee
+++ test/surveyor.coffee
@@ -255,7 +255,6 @@
       model.serviceInfo.put 'a', {healthyCommits: {'1': true}}, ->

         surveyor.calculateRoutingTable (err, routes) ->
-          console.log routes
           assert routes.a
           assert routes.a.maintenance
           done()


add comment

add comment

--- test/testData.coffee
+++ test/testData.coffee
@@ -83,7 +83,7 @@
         0:
           text: "prj2_0"
           show: SHOW.DEFAULT
-    prjOldFormat:
+    prjOldFormat:                                     # version <= 0.5.7
       "http://redmine.com" :
         index: 2
         0:


coffee-scriptize the router comment

coffee-scriptize the router comment

--- lib/generators/templates/router.js.coffee
+++ lib/generators/templates/router.js.coffee
@@ -1,5 +1,5 @@
 # For more information see: http://emberjs.com/guides/routing/

 <%= application_name.camelize %>.Router.map ()->
-  # this.resources('posts')
+  # @resources('posts')


Prevent plunk list from returning from cache

--- assets/lib/plunker.coffee
+++ assets/lib/plunker.coffee
@@ -1,54 +1,57 @@
 $ ->
-  jQuery.getJSON "//#{location.hostname}/api/v1/plunks", (json) ->
-    for plunk in json then do (plunk) ->
-      $li = $("

").addClass("span3").addClass("plunk")
-      $a = $("").attr("href", plunk.url).addClass("thumbnail").appendTo($li)
-      $img = $("")
-        .attr("src", "http://placehold.it/205x154&text=Loading...")
-        .attr("data-original", "http://immediatenet.com/t/l3?Size=1024x768&URL=#{plunk.url}")
-        .attr("alt", plunk.description or "Plunk: #{plunk.id}")
-        .addClass("lazy")
-        .appendTo($a)
-      $caption = $("

")
-        .addClass("caption")
-        .appendTo($a)
-      $title = $("
Plunk: #{plunk.id}
")
-        .addClass("title")
-        .appendTo($caption)
-      $desc = $("
#{plunk.description or 'Untitled'}
")
-        .attr("title", plunk.description or "Untitled")
-        .addClass("description")
-        .appendTo($caption)
-
-      $a.on "click", ->
-        $modal = $("

").addClass("modal")
-        $header = $("
×
#{plunk.description or 'Untitled'}

")
-          .addClass("modal-header")
-          .appendTo($modal)
-        $body = $("

")
-          .addClass("modal-body")
-          .appendTo($modal)
-        $iframe = $("")
-          .attr("src", plunk.url)
-          .addClass("preview")
-          .appendTo($body)
-        $footer = $("

")
-          .addClass("modal-footer")
-          .appendTo($modal)
-        $launch = $(" Fullscreen")
-          .attr("href", plunk.url)
-          .addClass("btn")
-          .addClass("btn-primary")
-          .appendTo($footer)
+  jQuery.ajax "//#{location.hostname}/api/v1/plunks",
+    dataType: "json"
+    cache: false
+    success: (json) ->
+      for plunk in json then do (plunk) ->
+        $li = $("

").addClass("span3").addClass("plunk")
+        $a = $("").attr("href", plunk.url).addClass("thumbnail").appendTo($li)
+        $img = $("")
+          .attr("src", "http://placehold.it/205x154&text=Loading...")
+          .attr("data-original", "http://immediatenet.com/t/l3?Size=1024x768&URL=#{plunk.url}")
+          .attr("alt", plunk.description or "Plunk: #{plunk.id}")
+          .addClass("lazy")
+          .appendTo($a)
+        $caption = $("

")
+          .addClass("caption")
+          .appendTo($a)
+        $title = $("
Plunk: #{plunk.id}
")
+          .addClass("title")
+          .appendTo($caption)
+        $desc = $("
#{plunk.description or 'Untitled'}
")
+          .attr("title", plunk.description or "Untitled")
+          .addClass("description")
+          .appendTo($caption)
+
+        $a.on "click", ->
+          $modal = $("

").addClass("modal")
+          $header = $("
×
#{plunk.description or 'Untitled'}

")
+            .addClass("modal-header")
+            .appendTo($modal)
+          $body = $("

")
+            .addClass("modal-body")
+            .appendTo($modal)
+          $iframe = $("")
+            .attr("src", plunk.url)
+            .addClass("preview")
+            .appendTo($body)
+          $footer = $("

")
+            .addClass("modal-footer")
+            .appendTo($modal)
+          $launch = $(" Fullscreen")
+            .attr("href", plunk.url)
+            .addClass("btn")
+            .addClass("btn-primary")
+            .appendTo($footer)
+
+          $modal.modal().modal("show").on "hidden", ->
+            $modal.remove()
+
+          false

-        $modal.modal().modal("show").on "hidden", ->
-          $modal.remove()
-
-        false
+        $li.appendTo("#recent")

-      $li.appendTo("#recent")
-
-    $("img.lazy").lazyload
-      threshold: 200
-      effect: "fadeIn"
+      $("img.lazy").lazyload
+        threshold: 200
+        effect: "fadeIn"


filter empty reqs

filter empty reqs

--- lib/endpoint.coffee
+++ lib/endpoint.coffee
@@ -235,6 +235,7 @@
     {queryParams} = @$endpoint.options
     filter = _.chain(req.query)
       .pairs()
+      .filter ([k, v]) -> v? and v isnt ''
       .filter ([k, v]) ->  _.some(queryParams, (q) -> minimatch(k, q))
       .map ([k, v]) ->
         return [k, { $exists: true }] if v is '$exists'