Modes; fix for tests.

Modes; fix for tests.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -394,7 +394,8 @@
               @exit()
               @continueBubbling

-        @exit() if visibleInputs.length == 1
+        visibleInputs[selectedInputIndex].element.focus()
+        return @exit() if visibleInputs.length == 1
         hints[selectedInputIndex].classList.add 'internalVimiumSelectedInputHint'

       exit: ->


Tweaks to #1966.

Tweaks to #1966.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -774,7 +774,7 @@
   showing: false

   # This setting is pulled out of local storage. It's false by default.
-  getShowAdvancedCommands: -> Settings.get("helpDialog_showAdvancedCommands")
+  getShowAdvancedCommands: -> Settings.get "helpDialog_showAdvancedCommands"

   init: ->
     return if @container?
@@ -792,7 +792,7 @@
         false)
       @dialogElement.getElementsByClassName("optionsPage")[0].addEventListener("click", (clickEvent) ->
           clickEvent.preventDefault()
-          chrome.runtime.sendMessage({handler: "openOptionsPageInNewTab"})
+          chrome.runtime.sendMessage {handler: "openOptionsPageInNewTab"}
         false)
       @dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].addEventListener("click",
         HelpDialog.toggleAdvancedCommands, false)
@@ -800,19 +800,19 @@
   isReady: -> document.body? and @container?

   show: (html) ->
-    return if HelpDialog.showing or !@isReady()
-    HelpDialog.showing = true
+    return if @showing or !@isReady()
+    @showing = true
     for placeholder, htmlString of html
       @dialogElement.querySelector("#help-dialog-#{placeholder}").innerHTML = htmlString

     document.body.appendChild @container
-    @showAdvancedCommands(@getShowAdvancedCommands())
+    @showAdvancedCommands @getShowAdvancedCommands()

     # Simulating a click on the help dialog makes it the active element for scrolling.
     DomUtils.simulateClick document.getElementById "vimiumHelpDialog"

   hide: ->
-    HelpDialog.showing = false
+    @showing = false
     @container?.parentNode?.removeChild @container

   toggle: (html) ->
@@ -824,16 +824,16 @@
   toggleAdvancedCommands: (event) ->
     event.preventDefault()
     showAdvanced = HelpDialog.getShowAdvancedCommands()
-    HelpDialog.showAdvancedCommands(!showAdvanced)
+    HelpDialog.showAdvancedCommands !showAdvanced
     Settings.set("helpDialog_showAdvancedCommands", !showAdvanced)

   showAdvancedCommands: (visible) ->
-    HelpDialog.dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].innerHTML =
+    @dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].innerHTML =
       if visible then "Hide advanced commands" else "Show advanced commands"

     # Add/remove the showAdvanced class to show/hide advanced commands.
     addOrRemove = if visible then "add" else "remove"
-    HelpDialog.dialogElement.classList[addOrRemove] "showAdvanced"
+    @dialogElement.classList[addOrRemove] "showAdvanced"

 initializePreDomReady()
 DomUtils.documentReady initializeOnDomReady


s/x86-64/x86_64/g

--- lib/ejs.coffee
+++ lib/ejs.coffee
@@ -19,7 +19,7 @@
 temp_files = []

 host_arch = os.arch()
-host_arch = "x86-64" if host_arch is "x64" # why didn't we just standardize on 'amd64'?  sigh
+host_arch = "x86_64" if host_arch is "x64" # why didn't we just standardize on 'amd64'?  sigh
 host_arch = "x86"    if host_arch is "ia32"

 host_platform = os.platform()
@@ -48,7 +48,7 @@
         options.native_module_dirs.push(dir)

 arch_info = {
-        "x86-64": { pointer_size: 64, little_endian: true, llc_arch: "x86-64",  clang_arch: "x86_64" }
+        "x86_64": { pointer_size: 64, little_endian: true, llc_arch: "x86-64",  clang_arch: "x86_64" }
         x86:      { pointer_size: 32, little_endian: true, llc_arch: "x86",     clang_arch: "i386" }
         arm:      { pointer_size: 32, little_endian: true, llc_arch: "arm",     clang_arch: "armv7" }
         aarch64:  { pointer_size: 64, little_endian: true, llc_arch: "aarch64", clang_arch: "aarch64" }
@@ -60,8 +60,7 @@

         # we accept some arch aliases

-        arch = "x86-64" if arch is "amd64"
-        arch = "x86-64" if arch is "x86_64"
+        arch = "x86_64" if arch is "amd64"
         arch = "x86"    if arch is "i386"

         if not arch in arch_info
@@ -77,8 +76,8 @@

 set_target_alias = (alias) ->
         target_aliases = {
-                linux_amd64: { platform: "linux",  arch: "x86-64" },
-                osx:         { platform: "darwin", arch: "x86-64" },
+                linux_amd64: { platform: "linux",  arch: "x86_64" },
+                osx:         { platform: "darwin", arch: "x86_64" },
                 sim:         { platform: "darwin", arch: "x86" },
                 dev:         { platform: "darwin", arch: "arm" },
         }
@@ -150,7 +149,7 @@
         "--arch":
                 handler: set_target_arch
                 handlerArgc: 1
-                help:    "--arch x86-64|x86|arm|aarch64"
+                help:    "--arch x86_64|x86|arm|aarch64"

         "--target":
                 handler: set_target_alias
@@ -249,11 +248,11 @@

         if platform is "linux"
                 # on ubuntu 14.04, at least, clang spits out a warning about this flag being unused (presumably because there's no other arch)
-                return [] if arch is "x86-64"
+                return [] if arch is "x86_64"
                 return args

         if platform is "darwin"
-                return args if arch is "x86-64"
+                return args if arch is "x86_64"
                 if arch is "x86"
                         return args.concat [ "-isysroot", "#{sim_base}/Developer/SDKs/iPhoneSimulator#{options.ios_sdk}.sdk", "-miphoneos-version-min=#{options.ios_min}" ]
                 return args.concat [ "-isysroot", "#{dev_base}/Developer/SDKs/iPhoneOS#{options.ios_sdk}.sdk", "-miphoneos-version-min=#{options.ios_min}" ]
@@ -267,7 +266,7 @@
                 rv = [ "-framework", "Foundation" ]

                 # for osx we only need Foundation and AppKit
-                return rv.concat [ "-framework" , "AppKit" ] if arch is "x86-64"
+                return rv.concat [ "-framework" , "AppKit" ] if arch is "x86_64"

                 # for any other darwin we're dealing with ios, so...
                 return rv.concat [ "-framework", "UIKit", "-framework", "GLKit", "-framework", "OpenGLES", "-framework", "CoreGraphics" ]
@@ -277,7 +276,7 @@
 target_libecho = (platform, arch) ->
         return "../../runtime/libecho.a"    if platform is "linux"
         if platform is "darwin"
-                return "../../runtime/libecho.a" if arch is "x86-64"
+                return "../../runtime/libecho.a" if arch is "x86_64"

                 return "../../runtime/libecho.a.ios"

@@ -288,7 +287,7 @@
         return "../../external-deps/pcre-linux/.libs/libpcre16.a" if platform is "linux"

         if platform is "darwin"
-                return "../../external-deps/pcre-osx/.libs/libpcre16.a" if arch is "x86-64"
+                return "../../external-deps/pcre-osx/.libs/libpcre16.a" if arch is "x86_64"
                 return "../../external-deps/pcre-iossim/.libs/libpcre16.a" if arch is "x86"
                 return "../../external-deps/pcre-iosdev/.libs/libpcre16.a" if arch is "arm"
                 return "../../external-deps/pcre-iosdevaarch64/.libs/libpcre16.a" if arch is "aarch64"


Fix for akonwi/git-plus#322. Pass process.env to BufferedProcess, otherwise package cant find git binary on PATH in Windows OSes.

--- lib/git.coffee
+++ lib/git.coffee
@@ -44,7 +44,7 @@
       reject "no current file"

 module.exports = git =
-  cmd: (args, options={}) ->
+  cmd: (args, options={ env: process.env }) ->
     new Promise (resolve, reject) ->
       output = ''
       try


remove some console logs

remove some console logs

--- tasks/details.coffee
+++ tasks/details.coffee
@@ -27,7 +27,6 @@
   """

   enter: =>
-    console.log 'enter'
     super

   renderTemplate: =>
@@ -43,7 +42,6 @@
     @next

   exit: ->
-    console.log 'exit'
     super

   getChoice: ->
@@ -53,7 +51,6 @@
     @value

   reset: (value) ->
-    console.log 'reset' unless value?
     value ?= @defaults

     @form.find("[name=#{o.name}]").val(o.value) for o in value.details


Response accepts markup

Response accepts markup

--- lib/middlewares/response.coffee
+++ lib/middlewares/response.coffee
@@ -54,14 +54,16 @@
   html: (value, body, headers = {}) ->
     @run value.toString(), body, "text/html", headers

-  page: (file, bindings = {}, partials = [], code, headers = {}) ->
+  page: (file, bindings = {}, partials = [], code, headers = {}, markup = null) ->
     files = {}
     files[partial] = __mustache partial for partial in partials or []
     for key, value of bindings when value? and not value is false
       bindings.if = bindings.if or {}
       bindings.if[key] = true
     bindings.zen = global.ZEN
-    @html mustache.render(__mustache(file), bindings, files), code
+    template = __mustache file
+    if markup then template = __attach markup, template
+    @html mustache.render(template, bindings, files), code

   json: (data = {}, code, headers = {}, audit = true) ->
     for key, value of global.ZEN.headers when not headers[key]
@@ -130,6 +132,10 @@
   else
     __cachedMustache[name] = "
404 - Not found
"

+__attach = (markup, template) ->
+  position =  template.search //
+  template.slice(0, position + "".length) + markup + template.slice(position)
+
 __output = (request, code, type = "", body = "", audit = true) ->
   latence = new Date() - request.at
   color = "red"


Uncomment try/catch

Uncomment try/catch

--- lib/notification-element.coffee
+++ lib/notification-element.coffee
@@ -118,11 +118,11 @@
     "#{info.ProductName} #{info.ProductVersion}"

   macVersionInfo: ->
-    # try
+    try
       text = fs.readFileSync('/System/Library/CoreServices/SystemVersion.plist', 'utf8')
       plist.parse(text)
-    # catch e
-    #   {}
+    catch e
+      {}

   winVersionText: ->
     info = spawnSync('systeminfo').stdout.toString()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/distance.coffee
+++ test/distance.coffee
@@ -1,5 +1,5 @@
 module "Distance"

-test 'it s'
+test 'it should be includa'

 module()


Pause is now a function passed to the onBeforeAction method.

--- client/entry.coffee
+++ client/entry.coffee
@@ -23,14 +23,14 @@
       signUpRoute = Router.routes['entrySignUp']
       signUpRoute.options.template = appConfig.signUpTemplate

-  signInRequired: (router, extraCondition) ->
+  signInRequired: (router, pause, extraCondition) ->
     extraCondition ?= true
     unless Meteor.loggingIn()
       unless Meteor.user() and extraCondition
         Session.set('fromWhere', router.path)
         Router.go('/sign-in')
         Session.set('entryError', t9n('error.signInRequired'))
-        router.pause()
+        pause.call()

 @AccountsEntry = AccountsEntry


Input: Fix missing gamepad support.

Input: Fix missing gamepad support.

--- engine/input.coffee
+++ engine/input.coffee
@@ -373,12 +373,12 @@

     constructor: (context, id) ->
         super context
+        if not navigator.getGamepads?
+            return
         @register_source ['Joy', 'Joystick', 'Gamepad']
         @gamepads = []
         @buttons_as_semi_axes = []
-        if not navigator.getGamepads?
-            return
-        @gamepads = navigator.getGamepads()
+        # @gamepads = navigator.getGamepads()
         window.addEventListener 'gamepadconnected', =>
             console.log "A gamepad has been connected or detected"
             @gamepads = navigator.getGamepads()
@@ -473,7 +473,9 @@

     update_controller: ->
         # NOTE: Looks like Chrome only updates gamepad values if we call this
-        navigator.getGamepads()
+        if @gamepads.length
+            # TODO: Investigate why we had to disable this line in Daydream
+            navigator.getGamepads()
         for pad in @semi_axes
             for label, semi_axis of pad
                 {gamepad, type, index, multiplier} = semi_axis


Spelling check

Spelling check

--- test/shop/api.coffee
+++ test/shop/api.coffee
@@ -74,7 +74,7 @@
       res.should.have.status 422
       done()

-  it "should nofity incorrect data when login with incomplete data", (done) ->
+  it "should notify incorrect data when login with incomplete data", (done) ->
     request.
     post("/shop/login").
     send({email: '', password: ''}).


R~bg

R~bg

--- AppStoreClient.coffee
+++ AppStoreClient.coffee
@@ -215,6 +215,7 @@
           obj
         callback objs
       else errorcallback e
+      return

   ###*


Fix children re-ordering.

Fix children re-ordering.

--- engine/scene.coffee
+++ engine/scene.coffee
@@ -137,7 +137,7 @@
             quat.mul rot, p_rot, rot
         child.parent = parent
         parent.children.push child
-        if @children.indexOf(parent) > @children.indexOf(child)
+        if @auto_updated_children.indexOf(parent) > @auto_updated_children.indexOf(child)
             # When this is set to false, reorder_children() is called
             # in render_manager.draw_viewport
             @_children_are_ordered = false
@@ -155,19 +155,15 @@
         '''Makes sure all scene children are in order for correct matrix calculations'''
         # TODO: Only the objects marked as unordered need to be resolved here!
         #       (make a new list and append to children)
-        children = @children
-
-        reorder = (ob,index)->
-            children[index++] = ob
+        children = @auto_updated_children
+        index = 0
+        reorder = (ob)->
+            if not ob.static
+                children[index++] = ob
             for c in ob.children
-                reorder c, index
-
-        index = 0
-        objects = @objects
-        for name, ob of objects
-            if not ob.parent
-                reorder ob, index
-
+                reorder c
+        for ob of @children when not ob.parent
+            reorder ob
         @_children_are_ordered = true

     load: ->


WebVR: Add set_mirror_zoom and head_is_tracking.

--- engine/webvr.coffee
+++ engine/webvr.coffee
@@ -33,6 +33,7 @@
             mat4.copyArray @sst, @HMD.stageParameters.sittingToStandingTransform
             mat4.invert @sst_inverse, @sst
             mat3.fromMat4 @sst3, @sst
+        @head_is_tracking = false
         # @to_Z_up = mat4.new 1,0,0,0, 0,0,1,0, 0,-1,0,0, 0,0,0,1
         # left eye viewport
         camera = left_cam = @scene.active_camera.clone()
@@ -63,8 +64,27 @@
         @context.canvas_screen.enabled = false
         for behaviour in @context.enabled_behaviours
             behaviour.on_enter_vr? left_cam, right_cam
+        {position, width, height, left, top} = @canvas.style
+        @old_canvas_style = {position, width, height, left, top}
+        if @canvas.style.width == '100vw' and @canvas.style.height == '100vh'
+            @set_mirror_zoom 1.3
+
+    set_mirror_zoom: (zoom) ->
+        {renderWidth, renderHeight} = @HMD.getEyeParameters("left")
+        ratio = renderWidth/renderHeight
+        @canvas.style.position = 'fixed'
+        @canvas.style.width = 200*zoom+'vw'
+        @canvas.style.height = (100*zoom/ratio) + 'vw'
+        @canvas.style.left = "#{-50*zoom+50}vw"
+        @canvas.style.top = "calc( -#{50*zoom}vw + #{50*ratio}vh )"

     destroy: ->
+        {position, width, height, left, top} = @old_canvas_style
+        @canvas.style.position = position
+        @canvas.style.width = width
+        @canvas.style.height = height
+        @canvas.style.left = left
+        @canvas.style.top = top
         @context.vr_screen = null
         @context.screens.splice @context.screens.indexOf(this), 1
         @context.canvas_screen.resize_to_canvas()
@@ -73,7 +93,9 @@
             behaviour.on_exit_vr?()
         return

-    exit: -> @destroy()
+    exit: ->
+        @HMD.exitPresent()
+        @destroy()

     pre_draw: ->
         {HMD} = this
@@ -117,6 +139,9 @@
             if @use_unpredict
                 quat.slerp r0, @left_orientation, r0, unpredict
             quat.copy @left_orientation, r0
+            # TODO: Test with other headsets.
+            @head_is_tracking =
+                not (p0.x == m4.m12 and p0.y == m4.m13 and p0.z == m4.m14)
             vec3.set p0, m4.m12, m4.m13, m4.m14

             mat4.copyArray m4, rightViewMatrix


some spellcheck

some spellcheck


update button bar a bit to have some modes

--- salvus/page/buttonbar.coffee
+++ salvus/page/buttonbar.coffee
@@ -809,8 +809,50 @@
                          f(x) = b * x + sin(a * x)
                          plot(f, (x, -5, 5)).show()
                      """
-
-    julia:
+        magics:
+            insert : "magics()"
+        mode_typeset:
+            insert : "%typeset_mode True"
+        mode_auto:
+            insert : "%auto"
+        mode_cython:
+            insert : "%cython"
+        mode_default_mode:
+            insert : "%default_mode mode_name"
+        mode_exercise:
+            insert : "%exercise"
+        mode_gap:
+            insert : "%gap"
+        mode_gp:
+            insert : "%gp"
+        mode_hide:
+            insert : "%hide"
+        mode_html:
+            insert : "%html"
+        mode_julia:
+            insert : "%julia"
+        mode_javascript:
+            insert : "%javascript\n/* Use print(...) for output */"
+        mode_md:
+            insert : "%md"
+        mode_python:
+            insert : "%python"
+        mode_r:
+            insert : "%r"
+        mode_scilab:
+            insert : "%scilab"
+        mode_sh:
+            wrap:
+                left  : "%sh "
+                right : ""
+        mode_time:
+            wrap:
+                left  : "%time "
+                right : ""
+        mode_timeit:
+            wrap:
+                left  : "%timeit "
+                right : ""
         comment:
             wrap:
                 left : "# "
@@ -1144,6 +1186,82 @@
     """

     codebar  = $(".salvus-editor-codeedit-buttonbar")
+
+    # -- modes (this isn't really code so weird to put here)
+    system_bar = make_bar("salvus-editor-codeedit-buttonbar-system")
+
+    mode_list = ["Modes", "Sage Worksheet Modes",
+        [
+            ["General"],
+            ["Auto execute cell on startup", "#mode_auto"],
+            ["Hide input (or double click output)", "#mode_hide"],
+            ["Set default mode", "#mode_default_mode"],
+            ["Typeset output", "#mode_typeset"],
+            ["Timing"],
+            ["Benchmark code repeatedly", "#mode_timeit"],
+            ["Time code once", "#mode_time"],
+            ["Language modes"],
+            ["Cython", "#mode_cython"],
+            ["Gap", "#mode_gap"],
+            ["PARI/GP", "#mode_gp"],
+            ["HTML", "#mode_html"],
+            ["Javascript", "#mode_javascript"],
+            ["Julia", "#mode_julia"],
+            ["Markdown", "#mode_md"],
+            ["Python", "#mode_python"],
+            ["R", "#mode_r"],
+        ]]
+    add_menu(system_bar, mode_list)
+
+    help_list = [" Help", "Sage Worksheet Help",
+        [
+            ["General help", "#help"],
+            ["Magic mode commands", "#magics"]
+        ]]
+    add_menu(system_bar, help_list)
+    ## MAYBE ADD THESE in another menu:
+    #axiom
+    #capture
+    #coffeescript
+    #command
+    #file
+    #fork
+    #fortran
+    #fricas
+    #gap3
+    #giac
+    #go
+    #hideall
+    #javascript
+    #kash
+    #lie
+    #lisp
+    #load
+    #macaulay2
+    #maxima
+    #octave
+    #pandoc
+    #perl
+    #prun
+    #reset
+    #ruby
+    #runfile
+    #sage0
+    #script
+    #singular
+    #typeset_mode
+    #var
+    #wiki
+    #mode_list = ["More", "More Sage Worksheet Modes",
+    #    [
+    #      ["Axiom", "#mode_axiom"],
+    #      ["Scilab", "#mode_scilab"],
+    #      ["Shell script", "#mode_sh"],
+    #      []
+    #    ]]
+    #add_menu(system_bar, mode_list)
+    codebar.append(system_bar)
+
     # -- python specific --
     pybar    = make_bar("salvus-editor-codeedit-buttonbar-python")
     add_icon(pybar, "#", "#comment", "Comment selected text")
@@ -1158,7 +1276,7 @@
             ["Tuple", "#tuple"],
             ["Properties"],
             ["Length", "#len"]
-        ]]
+           ]]
     add_menu(pybar, py_control)

     # structured dropdown menu data: button text, title info, list of ["button, "#id", "title help (optional)"]
@@ -1176,21 +1294,18 @@
         ]]
     add_menu(pybar, py_control)

-    py_func = ["Functions", "Define Functions",
+    py_func = ["Program", "Define Functions and Classes",
            [
+            ["Functions"],
             ["Function", "#function", "Define a Python function"],
             ["Lambda", "#lambda", "A Python lambda function"]
-        ]]
-
-    add_menu(pybar, py_func)
-
-    py_classes = ["Classes", "Define Classes",
-           [
+            ["Classes"],
             ["Class", "#simple_class", "Define a simple class"],
             ["Class with inheritence", "#class_inheritence", "A class that inherits from other classes"]
         ]]

-    add_menu(pybar, py_classes)
+    add_menu(pybar, py_func)
+
     codebar.append(pybar)

     # -- Cython specific
@@ -1304,7 +1419,6 @@
     add_menu(sagebar, sage_graphs)
     add_menu(sagebar, sage_nt)
     add_menu(sagebar, sage_rings)
-    add_icon(sagebar, " Help", "#help", "Help")

     codebar.append(sagebar)


change wording of test to better english

--- salvus/test/misc-test.coffee
+++ salvus/test/misc-test.coffee
@@ -15,7 +15,7 @@
     it 'checks that x={a:5} merged with {b:7} mutates x to be {a:5,b:7}', ->
         x = {a:5}; merge(x,{b:7})
         expect(x).toEqual({a:5,b:7})
-    it 'and duplicate keys are overwritten by the second entry?', ->
+    it 'checks that duplicate keys are overwritten by the second entry', ->
         a = {x:1, y:2}
         b = {x:3}
         merge(a, b)


testing: misc.call_lock and some negated tests for path_is_in_public_paths

--- salvus/test/misc-test.coffee
+++ salvus/test/misc-test.coffee
@@ -877,10 +877,56 @@
         p("path/name", ["path_name", "path"]).should.be.true()
     it "returns true if path ends with .zip and is within a public path", ->
         p("path/name.zip", ["path_name", "path"]).should.be.true()
+    it "handles path.zip correctly if it is not in the path", ->
+        p("foo/bar.zip", ["foo/baz"]).should.be.false()
     it "returns false if the path is not in the public paths", ->
         p("path", ["path_name", "path/name"]).should.be.false()
-
-
+    it "doesn't allow relativ path trickery", ->
+        p("../foo", ["foo"]).should.be.false()
+
+
+describe "call_lock", =>
+    before =>
+        @clock = sinon.useFakeTimers()
+
+    after =>
+        @clock.restore()
+
+    beforeEach =>
+        @objspy = sinon.spy()
+        @o = obj: @objspy, timeout_s: 5
+
+    it "adds a call lock to a given object", =>
+        misc.call_lock(@o)
+        @objspy.should.have.properties ["_call_lock", "_call_unlock", "_call_with_lock"]
+
+        fspy = sinon.spy()
+        @objspy._call_with_lock(fspy)
+        fspy.should.have.callCount 1
+
+        fspy2 = sinon.spy()
+        cbspy2 = sinon.spy()
+        @objspy._call_with_lock(fspy2, cbspy2)
+
+        # check that the cb has been called with the error message
+        cbspy2.getCall(0).args[0].should.eql "error -- hit call_lock"
+        # and the function hasn't been called
+        fspy2.should.have.callCount 0
+
+    it "unlocks after the given timeout_s time", =>
+        misc.call_lock(@o)
+
+        fspy = sinon.spy()
+        @objspy._call_with_lock(fspy)
+
+        # turn clock 6 secs ahead
+        @clock.tick 6*1000
+        fspy3 = sinon.spy()
+        cbspy3 = sinon.spy()
+        @objspy._call_with_lock(fspy3, cbspy3)
+
+        cbspy3.should.have.callCount 0
+        fspy3.should.have.callCount 1

 describe "encode_path", ->
     e = misc.encode_path


Small refactor

Small refactor

--- assets/javascripts/views/layout/resizer.coffee
+++ assets/javascripts/views/layout/resizer.coffee
@@ -35,7 +35,7 @@
     @style.removeAttribute('disabled')
     event.dataTransfer.effectAllowed = 'link'
     event.dataTransfer.setData('Text', '')
-    window.addEventListener("dragover", @onDrag);
+    $.on(window, 'dragover', @onDrag)
     return

   onDrag: (event) =>
@@ -48,7 +48,7 @@
     return

   onDragEnd: (event) =>
-    window.removeEventListener("dragover", @onDrag);
+    $.off(window, 'dragover', @onDrag)
     value = event.pageX or (event.screenX - window.screenX)
     if @lastDragValue and not (@lastDragValue - 5 < value < @lastDragValue + 5) # https://github.com/Thibaut/devdocs/issues/265
       value = @lastDragValue


Added test for @ack

Added test for @ack

--- tests/sockets.coffee
+++ tests/sockets.coffee
@@ -55,7 +55,21 @@

     c.emit 'shout', foo: 'bar'

-  'server ack': ->
+  'server ack': (t) ->
+    t.expect 'got-foo', 'acked', 'data'
+    t.wait 3000
+
+    zapp = zappa port++, ->
+      @on foo: ->
+        t.reached 'got-foo'
+        @ack foo:'bar'
+
+    c = t.client(zapp.app)
+    c.connect()
+
+    c.emit 'foo', bar:'foo', (data) ->
+      t.reached 'acked'
+      t.equal 'data', data.foo, 'bar'

   'server join': ->


Cleaned up checkbox test

Cleaned up checkbox test

--- test/checkbox.coffee
+++ test/checkbox.coffee
@@ -3,29 +3,36 @@
     input(type='checkbox' checked=@checked)
   """

-  describe "simple boolean checked value", ->
-    it "should be checked", ->
-      model =
-        checked: true
+  it "should be checked", ->
+    model =
+      checked: true

-      behave template(model), ->
-        assert.equal Q("input").checked, true
+    input = template(model)
+    assert.equal input.checked, true

-    it "should not be checked", ->
-      model =
-        checked: false
+  it "should not be checked", ->
+    model =
+      checked: false

-      behave template(model), ->
-        assert.equal Q("input").checked, false
+    input = template(model)
+    assert.equal input.checked, false

-  describe "observable checked attribute", ->
-    it "should track changes in the observable", ->
-      model =
-        checked: Observable false
+  it "should track changes in the observable", ->
+    model =
+      checked: Observable false

-      behave template(model), ->
-        assert.equal Q("input").checked, false, "Should not be checked"
-        model.checked true
-        assert.equal Q("input").checked, true, "Should be checked"
-        model.checked false
-        assert.equal Q("input").checked, false, "Should not be checked again"
+    input = template(model)
+
+    assert.equal input.checked, false, "Should not be checked"
+    model.checked true
+    assert.equal input.checked, true, "Should be checked"
+    model.checked false
+    assert.equal input.checked, false, "Should not be checked again"
+
+    input.checked = true
+    input.onchange()
+    assert.equal model.checked(), true, "Value of observable should be checked when input changes"
+
+    input.checked = false
+    input.onchange()
+    assert.equal model.checked(), false, "Value of observable should be unchecked when input changes"


cooldown finilazation

cooldown finilazation

--- test/cooldown.coffee
+++ test/cooldown.coffee
@@ -99,7 +99,7 @@
   equals obj.I.age, 1, "should successfully update"

 # TODO: tests to make sure value isn't overwritten if the instance variable already exists
-# TODO: tests to make sure value is defaulted to 0, but only if the instance variable doesn't exist
+
 test "initialize property to 0 if no current value", ->
   obj = GameObject()


Switching to JS ;_;

Switching to JS ;_;

--- app/hello.coffee
+++ app/hello.coffee
@@ -1,115 +0,0 @@
-# This program hosts a Hello World on port 9001.
-console.log( "Initializing." )
-
-# This is our framework! Also we have a version of handlebars designed to work with it.
-express = require( 'express' )
-expressHandlebars = require( 'express-handlebars' )
-
-# This is for parsing Soundcloud URLs.
-url = require( 'url' )
-
-# This gets our configuration out of the file:
-fs = require( 'fs' )
-config = JSON.parse( fs.readFileSync( "./config.json" ) )
-
-# This is our application library for getting Soundcloud URLs.
-soundcloud = require( './lib/soundcloud' )
-soundcloud.setApiKey( config.clientId )
-
-# Our entire express app is stored in 'app'
-app = express()
-
-# set handlebars as our templating engine:
-app.engine( 'handlebars', expressHandlebars( { defaultLayout: 'main' } ) )
-app.set( 'view engine', 'handlebars' );
-
-# Sets all folders in /static to be served from the root
-app.use( express.static( 'static' ) );
-
-# For requests to the root, render home
-app.get( "/", ( req, res ) ->
-	page = {}
-
-	page.title = "SoundVane"
-
-	res.render( 'home', page ) )
-
-# And for requests to url/track, do this:
-app.get( "/url/*", ( req, res ) ->
-
-	link = url.parse( req.originalUrl )
-	soundcloudUrl = link.pathname.substr(5)
-
-	page = {}
-	console.log( "stopit")
-	soundcloud.getIdRecsList( soundcloudUrl ).then(
-		( results ) ->
-			console.log( results )
-			page.tracks = sortByIncidence( results )
-
-			if ( link.host != "soundcloud.com" )
-				page.title = "Whoops."
-			else
-				page.title = "Recommendations"
-			console.log( page )
-			res.render( 'recommendations' , page ) )
-	)
-
-sortByIncidence = ( array ) ->
-	frequency = {}
-	value = 0
-	for i in [1..array.length]
-		value = array[i]
-		if value in frequency
-			frequency[value]++
-		else
-			frequency[value] = 1
-
-	unique = []
-	for value in frequency
-		unique.push( value )
-
-	compareTo = (a, b) ->
-		return frequency[b] - frequency[a]
-
-	return unique.sort(compareTo)
-
-###
-var frequency = {}, value;
-for(var i = 0; i < array.length; i++) {
-    value = array[i];
-    if(value in frequency) {
-        frequency[value]++;
-    }
-    else {
-        frequency[value] = 1;
-    }
-}
-
-var unique = [];
-for(value in frequency) {
-    unique.push(value);
-}
-
-function compareTo(a, b) {
-    return frequency[b] - frequency[a];
-}
-###
-# About sends you to the about view.
-app.get( "/about", ( req, res ) ->
-
-	page = {}
-
-	page.title = "About Us"
-
-	res.render( 'about' , page ) )
-
-# REV THIS BITCH UP
-server = app.listen( 9001, ->
-	host = server.address().address
-	port = server.address().port
-
-
-
-	#console.log( "Listening at " + host + ":" + port ) )
-	)


Use helper

Use helper

--- app/index.coffee
+++ app/index.coffee
@@ -39,7 +39,7 @@

     done = @async()

-    @githubUserInfo @githubUser, (err, res) =>
+    helpers.githubUserInfo @githubUser, (err, res) =>
       @realname = res.name
       @email = res.email
       @githubUrl = res.html_url


opinion filters should also filter out includers

--- @client/point.coffee
+++ @client/point.coffee
@@ -504,6 +504,7 @@
     save(hist)

   buildIncluders : ->
+    filter_out = fetch 'filtered'
     point = @data()
     #author_has_included = _.contains point.includers, point.user

@@ -520,6 +521,9 @@
       selected_users = (fetch(o).user for o in selected_opinions)
       includers = _.intersection includers, selected_users
       #author_has_included = _.contains selected_users, point.user
+
+    if filter_out.users
+      includers = (i for i in includers if !filter_out.users[i])

     if true #author_has_included
       includers = _.without includers, point.user


Removed symbols from scope name. Caused comment toggle glitch.

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -422,7 +422,7 @@
   }
   controlSymbol: {
     comment: 'Mostly covered by escapedCharacter, but this is a catch all for any control symbols'
-    name: 'keyword.control.symbol.$1.latex'
+    name: 'keyword.control.symbol.latex'
     match: '\\\\([^a-zA-Z@]|@[^a-zA-A@])'
   }
   controlWord: {


Set user role in integration update too

Set user role in integration update too

--- packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee
+++ packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee
@@ -12,7 +12,8 @@
 		if integration.channel[0] not in ['@', '#']
 			throw new Meteor.Error 'invalid_channel', '[methods] updateIncomingIntegration -> channel should start with # or @'

-		if not RocketChat.models.Integrations.findOne(integrationId)?
+		currentIntegration = RocketChat.models.Integrations.findOne(integrationId)
+		if not currentIntegration?
 			throw new Meteor.Error 'invalid_integration', '[methods] updateIncomingIntegration -> integration not found'

 		record = undefined
@@ -36,6 +37,9 @@
 		if record is undefined
 			throw new Meteor.Error 'channel_does_not_exists', "[methods] updateIncomingIntegration -> The channel does not exists"

+		user = RocketChat.models.Users.findOne({username: currentIntegration.username})
+		Roles.addUsersToRoles user._id, 'bot', 'bot'
+
 		RocketChat.models.Integrations.update integrationId,
 			$set:
 				name: integration.name


Include mata functions from old atom-stata-language package

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -464,12 +464,37 @@
   {
     'begin': '^\\s*mata:?\\s*$'
     'comment': 'won\'t match single-line Mata statements'
-    'contentName': 'source.mata'
     'end': '^\\s*end\\s*$\\n?'
     'name': 'meta.embedded.block.mata'
     'patterns': [
       {
-        'include': 'source.mata'
+        'match': '(?<![^$\\s])(version|pragma|if|else|for|while|do|break|continue|goto|return)(?=\\s)'
+        'name': 'keyword.control.mata'
+      }
+      {
+        'captures':
+          '1':
+            'name': 'storage.type.eltype.mata'
+          '4':
+            'name': 'storage.type.orgtype.mata'
+        'match': '\\b(transmorphic|string|numeric|real|complex|(pointer(\\([^)]+\\))?))\\s+(matrix|vector|rowvector|colvector|scalar)\\b'
+        'name': 'storage.type.mata'
+      }
+      {
+        'comment': 'need to end with whitespace character here or last group doesn\'t match'
+        'match': '\\b(transmorphic|string|numeric|real|complex|(pointer(\\([^)]+\\))?))\\s'
+        'name': 'storage.type.eltype.mata'
+      }
+      {
+        'match': '\\b(matrix|vector|rowvector|colvector|scalar)\\b'
+        'name': 'storage.type.orgtype.mata'
+      }
+      {
+        'match': '\\!|\\+\\+|\\-\\-|\\&|\\\'|\\?|\\\\|\\:\\:|\\,|\\.\\.|\\||\\=|\\=\\=|\\>\\=|\\<\\=|\\<|\\>|\\!\\=|\\#|\\+|\\-|\\*|\\^|\\/'
+        'name': 'keyword.operator.mata'
+      }
+      {
+        'include': '$self'
       }
     ]
   }


Require user email and user name to be unique

--- grunt/sqlite.coffee
+++ grunt/sqlite.coffee
@@ -23,8 +23,8 @@
         tablesCreated = q.ninvoke db, 'exec', '''
             CREATE TABLE tUser (
                 id INTEGER PRIMARY KEY AUTOINCREMENT,
-                email TEXT,
-                name TEXT,
+                email TEXT UNIQUE,
+                name TEXT UNIQUE,
                 ulevel INTEGER,
                 pass TEXT
             );


YamlUtils: return contentObject alongside with the content

--- client/admin/lib/views/stacks/yamlutils.coffee
+++ client/admin/lib/views/stacks/yamlutils.coffee
@@ -27,8 +27,9 @@
     catch err
       console.error '[JsonToYaml]', err  unless silent

-    return { content, contentType, err }
+    contentObject or= {}

+    return { content, contentType, contentObject, err }

   yamlToJson: (content, silent = no) ->
@@ -44,6 +45,8 @@
     catch err
       console.error '[YamlToJson]', err  unless silent

-    return { content, contentType, err }
+    contentObject or= {}
+
+    return { content, contentType, contentObject, err }

 }


Clicking on the heading no longer reloads the page.

--- scripts/views/workspace/menu/toolbar-aloha.coffee
+++ scripts/views/workspace/menu/toolbar-aloha.coffee
@@ -9,6 +9,7 @@
     tagName: 'span'

     onRender: ->
+      @$el.find('.btn.currentHeading').on 'click', (e) -> e.preventDefault()
       # Wait until Aloha is started before enabling the toolbar
       @$el.addClass('disabled')
       Aloha.ready => @$el.removeClass('disabled')


Remove console.log used for debugging

Remove console.log used for debugging

--- scripts/views/workspace/sidebar/toc-branch.coffee
+++ scripts/views/workspace/sidebar/toc-branch.coffee
@@ -23,9 +23,8 @@
         @renderChildren()
       else
         @$el.removeClass('editor-node-expanded')
-
+
       # Add DnD options to content
-      console.log @$el.children().children('*[data-media-type]')
       enableContentDragging(@model, @$el.children().children('*[data-media-type]'))

       return @


Added image to broken build

Added image to broken build

--- scripts/brokethebuild.coffee
+++ scripts/brokethebuild.coffee
@@ -3,6 +3,7 @@

 images = [
   "http://i.qkme.me/1rei.jpg",
+	"http://memegenerator.net/cache/instances/400x/11/11544/11821190.jpg",
   "http://troll.me/images/success-kid/broke-the-build-someone-else-fixed-it.jpg",
   "http://www.ucalgary.ca/internphoto/files/internphoto/images/BrooksRileyHat_0.jpg",
   "http://www.finalbuilder.com/Portals/0/ArticleImages/BlogImages/penance-of-doughnuts.jpg",


Adjust resizing.

Adjust resizing.

--- coffee/ruban.coffee
+++ coffee/ruban.coffee
@@ -38,9 +38,9 @@
     $(window).on('hashchange', @checkHash)

   resize: ->
-    [width, height] = [$(window).width(), $(window).height()]
-    if width > height
-      min = height
+    [outerWidth, outerHeight] = [$(window).width(), $(window).height()]
+    if outerWidth > @options.ratio * outerHeight
+      min = outerHeight
       paddingV = @options.minPadding
       @$sections.css(
         'font-size':      "#{min * 0.4}%"
@@ -48,13 +48,14 @@
         'padding-bottom': paddingV
       )
       height = @$current.height()
-      paddingH = "#{(width - @options.ratio*height)/2}px"
+      width = @options.ratio * height
+      paddingH = "#{(outerWidth - width)/2}px"
       @$sections.css(
         'padding-left':  paddingH
         'padding-right': paddingH
       )
     else
-      min = width
+      min = outerWidth / @options.ratio
       paddingH = @options.minPadding
       @$sections.css(
         'font-size':      "#{min * 0.4}%"
@@ -62,7 +63,8 @@
         'padding-right': paddingH
       )
       width = @$current.width()
-      paddingV = "#{(height - width/@options.ratio)/2}px"
+      height = width / @options.ratio
+      paddingV = "#{(height - height)/2}px"
       @$sections.css(
         'padding-top':    paddingV,
         'padding-bottom': paddingV


Fix new start or end time may not save on key ENTER

--- client/app/views/calendar_popover_event.coffee
+++ client/app/views/calendar_popover_event.coffee
@@ -215,6 +215,10 @@
         if event.keyCode is 13 or event.which is 13 #ENTER
             # Forces the combobox to blur to save the calendar if it has changed
             @calendar.onBlur()
+            # Update start and end too.
+            @onSetStart()
+            @onSetEnd()
+
             @addButton.click()
         else if event.keyCode is 27 # ESC
             @selfclose()


Remove mention of Classic signin

Remove mention of Classic signin

--- client/code/view/profile/reset-password.coffee
+++ client/code/view/profile/reset-password.coffee
@@ -38,7 +38,7 @@
           _gaq.push ['_trackEvent', 'set-password', 'success', query]
         error: (jqxhr, textStatus, errorThrown) =>
           if jqxhr.status == 404
-            msg = """
Hmmm. That username could not be found. Maybe you’re trying to reset a ScraperWiki Classic password?
"""
+            msg = """
Hmmm. That username could not be found.
"""
           else
             msg = """
Hmmm. Something went wrong. Email hello@scraperwiki.com and we’ll email you a password reset link manually.
"""
           $('form', @$el).prepend msg


IDE.OnboardingModal: base on EnvironmentsModalView

--- client/ide/views/modals/onboardingmodal.coffee
+++ client/ide/views/modals/onboardingmodal.coffee
@@ -1,4 +1,4 @@
-class IDE.OnboardingModal extends IDE.ModalView
+class IDE.OnboardingModal extends EnvironmentsModalView

   constructor: (options = {}, data) ->


StackEditor: use VariablesController for custom variables editor

--- client/new-stack-editor/lib/views/index.coffee
+++ client/new-stack-editor/lib/views/index.coffee
@@ -10,9 +10,12 @@
 Editor = require './editor'
 Statusbar = require './statusbar'

+VariablesController = require '../controllers/variables'
+

 module.exports = class StackEditor extends kd.View

+  EDITORS = ['editor', 'readme', 'variables', 'logs']

   constructor: (options = {}, data = {}) ->

@@ -51,6 +54,9 @@
       @statusbar
     }

+    @variablesController = new VariablesController
+      editor: @variables
+
     @readme = new Editor {
       cssClass: 'readme'
       title: 'Readme'
@@ -62,9 +68,8 @@

   setTemplateData: (data) ->

-    if data
-      @setData data
-      @toolbar.setData data
+    @setData data
+    @toolbar.setData data

     { _id: id, title, description, template } = @getData()
     unless id or description or template
@@ -77,6 +82,8 @@

       @editor.setContent Encoder.htmlDecode template.rawContent
       @readme.setContent description
+      @variables.setContent ''
+      @variablesController.setData data
       @logs.setContent 'Stack template loaded'

       @_saveSnapshot id
@@ -90,7 +97,7 @@
     return no  unless id
     return no  unless snapshot = @_snapshots[id]

-    for view in ['editor', 'readme', 'logs']
+    for view in EDITORS
       @[view]._restore snapshot[view]
     @_current = id

@@ -102,7 +109,7 @@
     return  unless id

     @_snapshots[id] ?= {}
-    for view in ['editor', 'readme', 'logs']
+    for view in EDITORS
       @_snapshots[id][view] = @[view]._dump()


Revert "fix(// Generated by CoffeeScript 1.6.2)"

This reverts commit 8d113d7b80cf0ff36fbfd65d0dc924c0faf96ceb.

--- app/coffeescripts/react_files/components/RestrictedDialogForm.coffee
+++ app/coffeescripts/react_files/components/RestrictedDialogForm.coffee
@@ -63,10 +63,6 @@

     setRestrictedAccess: ->
       attributes = @refs.restrictedSelection.extractFormValues()
-      if Date.parse(attributes.unlock_at) and Date.parse(attributes.lock_at)
-        if attributes.unlock_at >= attributes.lock_at
-          return $.flashError(I18n.t('There was an error setting availability dates.'))
-
       promises = @props.models.map (item) ->
         # Calling .save like this (passing data as the 'attrs' property on
         # the 'options' argument instead of as the first argument) is so that we just send


fix typo

fix typo

--- scripts/github-notify.coffee
+++ scripts/github-notify.coffee
@@ -58,7 +58,7 @@
         announcePullRequest data, (what) ->
           robot.messageRoom room, what
       catch error
-        robot.messageRoom room, "Whoa, I got an error: #{error}"
+        robot.messageRoom room, "GitHub 通知処理中にエラーが発生しました: #{error}"
         console.log "github pull request notifier error: #{error}. Request: #{req.body}"

     res.end ""
@@ -84,7 +84,7 @@
       mentioned = mentioned.map (nick) -> nick[2].trim()
       mentioned = unique mentioned
       mentioned = mentioned.map (nick) ->
-        nick = nick.match(/@([\w\-\/]+/)[1]
+        nick = nick.match(/@([\w\-\/]+)/)[1]
         for _uid, user of robot.brain.users
           if user.githubLogin == nick
             nick = user.name


render mask before controls

render mask before controls

Otherwise the controls have it's opacity

--- shared/src/components/exercise-preview/index.cjsx
+++ shared/src/components/exercise-preview/index.cjsx
@@ -115,10 +115,10 @@
       header={@props.header}
       footer={@renderFooter() if @props.children}
     >
+      {
 if @props.isSelected}
+
       <ControlsOverlay exercise={@props.exercise}
         actions={@props.overlayActions} onClick={@props.onOverlayClick} />
-
-      {
 if @props.isSelected}


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/tweening.coffee
+++ test/tweening.coffee
@@ -13,6 +13,5 @@
     equals o.I.x, i

-
 # Clear out the module
 module()


preserve-3d on active class

preserve-3d on active class

--- oridomi.coffee
+++ oridomi.coffee
@@ -254,6 +254,7 @@
     border:          'none'
     outline:         'none'
     position:        'relative'
+    transformStyle:  p3d

   addStyle elClasses.clone,
     margin:    '0'
@@ -265,7 +266,6 @@
     position:       'absolute'
     transform:      'translateY(-100%)'
     transformStyle: p3d
-

   addStyle elClasses.stage,
     width:          '100%'


Temporarily surround every Chinese character by spaces to make sure that they are always split one by one (no word segmentation in the corpus for now)

--- app/assets/javascripts/rglossa/components/centre/search_inputs/cwb_simple_input.jsx.coffee
+++ app/assets/javascripts/rglossa/components/centre/search_inputs/cwb_simple_input.jsx.coffee
@@ -25,9 +25,12 @@
       query = ''
     else
       attr = if @isPhonetic() then 'phon' else 'word'
-      terms = for term in e.target.value.split(/\s/)
+      # Surround every Chinese character by space when constructing a cqp query,
+      # to treat it as if it was an individual word:
+      chineseCharsRange = '[\u4E00-\u9FFF\u3400-\u4DFF\uF900-\uFAFF]'
+      terms = for term in e.target.value.replace(///(#{chineseCharsRange})///g, ' $1 ').split(/\s/)
         if term is '' then '' else "[#{attr}=\"#{term}\" %c]"
-      query = terms.join(' ')
+      query = terms.join(' ').replace(///\s(\[\w+="#{chineseCharsRange}"(?:\s+%c)?\])\s///g, "$1")

     @props.handleQueryChanged
       lang: @props.searchQuery.lang


discussion snapshot title markdown removed

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemDiscussion.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemDiscussion.coffee
@@ -112,7 +112,7 @@
         appManager.tell "Activity", "createContentDisplay", @getData()

   applyTextExpansions:(str = "")->
-    str = @utils.expandUsernames @utils.applyMarkdown str
+    str = @utils.expandUsernames str

     if str.length > 500
       visiblePart = str.substr 0, 500


Hide "No keys" field when updating key list.

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee
@@ -9,6 +9,8 @@
       newKeys = @getItemsOrdered().map (item)-> item.getData()
       if newKeys.length is 0
         @addCustomItem "You have no SSH keys."
+      else
+        @customItem?.destroy()
       KD.remote.api.JUser.setSSHKeys newKeys, ->
         console.log "Saved keys."

@@ -21,6 +23,7 @@

   loadItems: ()->
     @removeAllItems()
+    @customItem?.destroy()
     @showLazyLoader no

     KD.remote.api.JUser.getSSHKeys (keys)=>


Update UI after editing title and key.

Update UI after editing title and key.

--- client/landing/app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee
+++ client/landing/app/Applications/Account.kdapplication/account/accSettingsDevSshKeys.coffee
@@ -144,9 +144,10 @@
     @data =
       key   : @form.keyTextarea.getValue()
       title : @form.titleInput.getValue()
+
     if @data.key and @data.title
-      @info.$('div.title').text @data.title
-      @info.$('div.key').text @data.key
+      @info.$('span.title').text @data.title
+      @info.$('span.key').text @data.key
       @swappable.swapViews()
       controller.emit "UpdatedItems"
     else


fix(specs)

fix(specs)

--- spec/stores/focused-perspective-store-spec.coffee
+++ spec/stores/focused-perspective-store-spec.coffee
@@ -75,8 +75,9 @@
       expect(FocusedPerspectiveStore.trigger).toHaveBeenCalled()
       expect(FocusedPerspectiveStore.current().categories()).toEqual([@userCategory])

-    it "should do nothing if the category is already focused", ->
-      FocusedPerspectiveStore._onFocusPerspective(@inboxPerspective)
-      spyOn(FocusedPerspectiveStore, '_setPerspective')
-      FocusedPerspectiveStore._onFocusPerspective(@inboxPerspective)
-      expect(FocusedPerspectiveStore._setPerspective).not.toHaveBeenCalled()
+  describe "_setPerspective", ->
+    it "should not trigger if the perspective is already focused", ->
+      FocusedPerspectiveStore._setPerspective(@inboxPerspective)
+      FocusedPerspectiveStore.trigger.reset()
+      FocusedPerspectiveStore._setPerspective(@inboxPerspective)
+      expect(FocusedPerspectiveStore.trigger).not.toHaveBeenCalled()


activity: collect all getters together

activity: collect all getters together

--- client/activity/lib/components/createpublicchannelmodal/index.coffee
+++ client/activity/lib/components/createpublicchannelmodal/index.coffee
@@ -53,6 +53,22 @@
   getDefaultPlaceholder: -> 'type a @username and hit enter'

+  getParticipantsWrapperClassnames: -> classnames
+    'delete-mode'                       : @state.deleteMode
+    'CreateChannel-participantsWrapper' : yes
+
+
+  getNameFieldClassnames: -> classnames
+    'Reactivity-formfield' : yes
+    'invalid'              : @state.invalidName
+
+
+  getDropboxFieldClassnames: -> classnames
+    'Reactivity-formfield' : yes
+    'dropdown'             : yes
+    'invalid'              : @state.invalidParticipants
+
+
   setName: (event) ->

     value = event.target.value
@@ -214,11 +230,6 @@
           </div>
         </ProfileLinkContainer>
       </div>
-
-
-  getParticipantsWrapperClassnames: -> classnames
-    'delete-mode'                       : @state.deleteMode
-    'CreateChannel-participantsWrapper' : yes

   renderAddParticipantInput: ->
@@ -254,17 +265,6 @@
       selectedIndex   = { @state.selectedIndex }
       onItemConfirmed = { @bound 'onDropdownItemConfirmed' }
     />
-
-
-  getNameFieldClassnames: -> classnames
-    'Reactivity-formfield' : yes
-    'invalid'              : @state.invalidName
-
-
-  getDropboxFieldClassnames: -> classnames
-    'Reactivity-formfield' : yes
-    'dropdown'             : yes
-    'invalid'              : @state.invalidParticipants

   render: ->


Account: refactored account sublist addition

--- client/landing/app/Applications/Account.kdapplication/AppView.coffee
+++ client/landing/app/Applications/Account.kdapplication/AppView.coffee
@@ -44,18 +44,22 @@

     data = @getData()

-    @addSubView @header = new KDHeaderView type : "medium",title : data.item.listHeader
+    @addSubView @header = new KDHeaderView type : "medium", title : data.item.listHeader
+    id    = if data.section?.id   then data.section.id    or 'default'
+    type  = if data.item.listType then data.item.listType or 'view'

-    @list = new listClasses[data.section.id][data.item.listType]
-      cssClass : "#{data.section.id}-#{data.item.listType}"
+    ListView = if listClasses[id]?[type]
+    then listClasses[id][type]
+    else KDListView

-    listControllerClass = listClasses[data.section.id]["#{data.item.listType}Controller"] or KDListViewController
-    listController = new listControllerClass
-      view : @list
+    Controller = if listClasses[id]?["#{type}Controller"]
+    then listClasses[id]["#{type}Controller"]
+    else KDListViewController

-    @addSubView listController.getView()
+    controller = new Controller
+      view     : new ListView cssClass : "#{id}-#{type}"

-    @list.on "passwordDidChange",()-> log "password"
+    @addSubView controller.getView()

 class AccountsSwappable extends KDView
   constructor:(options,data)->


ENHANCE: Add support for additional web file types

Add support for: scss, yaml, xml, json, ts

--- src/app/common/file-uploader/file-uploader.coffee
+++ src/app/common/file-uploader/file-uploader.coffee
@@ -47,7 +47,8 @@
         icon:       'fa-file-excel-o'
         name:       'CSV'
       code:
-        extensions: ['pas', 'cpp', 'c', 'cs', 'h', 'java', 'py', 'js', 'html', 'coffee', 'rb', 'css']
+        extensions: ['pas', 'cpp', 'c', 'cs', 'h', 'java', 'py', 'js', 'html', 'coffee', 'rb', 'css',
+                    'scss', 'yaml', 'yml', 'xml', 'json', 'ts']
         icon:       'fa-file-code-o'
         name:       'code'
       image:


Fix typo for receive

Fix typo for receive

--- server/commons/errors.coffee
+++ server/commons/errors.coffee
@@ -39,6 +39,6 @@
   res.send 504, message
   res.end()

-module.exports.clientTimeout = (res, message="The server did not recieve the client response in a timely manner") ->
+module.exports.clientTimeout = (res, message="The server did not receive the client response in a timely manner") ->
   res.send 408, message
   res.end()


bugfix - unselectable but no Noselect

bugfix - unselectable but no Noselect

--- server/models/account.coffee
+++ server/models/account.coffee
@@ -277,7 +277,11 @@
         async.eachSeries toFetch, (box, cb) ->
             box.imap_fetchMails limitByBox, (err) ->
                 # dont interrupt the loop if one fail
-                reporter.onError err if err
+                # @TODO : Figure out how to distinguish a mailbox that
+                # is not selectable but not marked as such. In the meantime
+                # dont pop the error the client
+                if err and -1 is err.message?.indexOf "Mailbox doesn't exist"
+                    reporter.onError err
                 reporter.addProgress 1
                 cb null


correction bug on contacts

correction bug on contacts

--- server/models/contact.coffee
+++ server/models/contact.coffee
@@ -16,7 +16,7 @@
     if @_attachments?.picture
         stream = @getFile 'picture', (err) ->
             log.error "Contact #{contact.id} getting picture", err if err?
-        stream_to_buffer_array stream (err, parts) =>
+        stream_to_buffer_array stream, (err, parts) =>
             return callback err if err
             base64 = Buffer.concat(parts).toString('base64')
             avatar = "data:image/jpeg;base64," + base64


Hiding FS ads after landing page

Hiding FS ads after landing page

Change-Id: I97091753c5eacab24ac58567a8f3cb8c2b961c7e

--- app/assets/javascripts/ajax.js.coffee
+++ app/assets/javascripts/ajax.js.coffee
@@ -156,7 +156,7 @@

 #****Private Functions****
 BestBuyLandingElements = ->
-  bb_divs = $("#pagecontentmain2 > [id^=ctl00_CP], #pagecontentmain2 > .std-bottommargin, #pagecontentmain2 .articles-container, #pagecontentmain2 .ui-tabcontrol, #contentleft1 [id^=ctl00_CC], #contentleft1 .department-headline")
+  bb_divs = $("#pagecontentmain2 > [id^=ctl00_CP], #pagecontentmain2 > .std-bottommargin, #pagecontentmain2 .articles-container, #pagecontentmain2 .ui-tabcontrol, #contentleft1 [id^=ctl00_CC], #contentleft1 .department-headline, #contentleft1 .tech-community, #contentleft1 .btm-space")
   if ($("#landingpage_indicator").length == 0)
     # If they exist, hide the Best Buy landing page elements
     if (bb_divs.length != 0) # Make sure they exist


Refactor.

Refactor.

--- app/client/js/react/pages/song.coffee
+++ app/client/js/react/pages/song.coffee
@@ -43,14 +43,17 @@
             "<sup>#{chord}</sup>"

       componentDidMount: ->
-        goog.dom.classlist.add document.body, 'active-song'
+        @toggleActive true
         @setLyricsMaxFontSize()
         @viewportMonitor = new goog.dom.ViewportSizeMonitor
         @viewportMonitor.listen 'resize', => @setLyricsMaxFontSize()

       componentWillUnmount: ->
-        goog.dom.classlist.remove document.body, 'active-song'
+        @toggleActive false
         @viewportMonitor.dispose()
+
+      toggleActive: (enabled) ->
+        goog.dom.classlist.enable document.body, 'active-song', enabled

       componentDidUpdate: ->
         # TODO(steida): Implement fontSize increase and decrease.


Fix bug to allow autocomplete for all words

--- settings/language-stata.cson
+++ settings/language-stata.cson
@@ -1825,5 +1825,5 @@
           'set scheme'
         ]
       '':
-        selector: '.source.'
+        selector: '.source'
         typePriority: 1


fix(taskboard): save attachments and restore after patch

--- app/coffee/modules/issues/list.coffee
+++ app/coffee/modules/issues/list.coffee
@@ -591,8 +591,15 @@
             $el.find(".pop-status").popover().close()
             updateIssueStatus($el, issue, $scope.issueStatusById)

+            attachments = issue.attachments
+
             $scope.$apply () ->
                 $repo.save(issue).then (response) ->
+                    issue.attachments = attachments
+                    issue._isModified = false
+                    issue._attrs = _.extend(issue.getAttrs(), issue)
+                    issue._modifiedAttrs = {}
+
                     $rootscope.$broadcast("status:changed", response)

         taiga.bindOnce $scope, "project", (project) ->
@@ -652,7 +659,13 @@
         $el.on "click", ".issue-assignedto", (event) ->
             onClose = (assignedUsers) =>
                 issue.assigned_to = assignedUsers.pop() || null
+                attachments = issue.attachments
                 $repo.save(issue).then ->
+                    issue.attachments = attachments
+                    issue._isModified = false
+                    issue._attrs = _.extend(issue.getAttrs(), issue)
+                    issue._modifiedAttrs = {}
+
                     updateIssue(issue)
                     $rootscope.$broadcast("assigned-to:changed", issue)


[feat] unwind-protect now works. Tracked down the last bad reference.

--- chapter3g/interpreter.coffee
+++ chapter3g/interpreter.coffee
@@ -389,7 +389,7 @@

 definitial "funcall", new Primitive "funcall", (args, env, kont) ->
     if not nilp cdr args
-      @kont.invoke (car args), (cdr args)
+      kont.invoke (env.lookup (car args)), (cdr args)
     else
       throw new LispInterpreterError "Invoke requires a function name and arguments"


List & App Fixes

List & App Fixes

--- app/views.coffee
+++ app/views.coffee
@@ -44,18 +44,19 @@
       withArgs  : "ls ~/Applications"
       (err, res) =>
         if err? then notify err.message; return
-        kdAppNames = res.split('\n')[..-1]
+        kdAppNames = res.split('\n')[...-1]
         kdAppNameOpt = []
         for appname in kdAppNames
           if appname is 'appaid.kdapp' then continue
           kdAppNameOpt.push {title: appname, value: appname}
         appSelectBox.setSelectOptions kdAppNameOpt
         # Don't forget to add our targetApp Default
-        @options.targetApp.appName = kdAppNames[0]
+        @options.targetApp.appName = appSelectBox.getValue()

     appLoadBtn = new KDButtonView
       title     : 'Load App'
       callback  : =>
+        @options.targetApp.appName = appSelectBox.getValue()
         @loadApp (err) ->
           if err?
             notify "Error during Load: #{err.message}"
@@ -121,7 +122,7 @@
   #
   loadApp: (callback=->) ->
     console.log "Wtf?"
-    console.log @options
+    console.log @options.targetApp
     {
       appName
       vmName
@@ -129,7 +130,7 @@
     notify "Loading '#{appName}'..."

     @appIndexHelper = FSHelper.createFileFromPath(
-      "[#{vmName}]~/Applications/#{appName}"
+      "[#{vmName}]~/Applications/#{appName}/index.js"
     )
     @appIndexHelper.exists (err, exists) =>
       if exists


'parse' objOpts.globalIdToThis added

'parse' objOpts.globalIdToThis added

--- parser.coffee
+++ parser.coffee
@@ -15,7 +15,7 @@
 		return false
 	true

-exports.parse = (val, isPublicId, opts=0) ->
+exports.parse = (val, isPublicId, opts=0, objOpts={}) ->
 	binding = ['']

 	# split to types
@@ -48,7 +48,7 @@
 		if id is 'Renderer'
 			elem.shift()
 			[id] = elem
-		if id is 'parent' or id is 'nextSibling' or id is 'previousSibling' or id is 'target'
+		if id is 'parent' or id is 'nextSibling' or id is 'previousSibling' or id is 'target' or objOpts.globalIdToThis?[id]
 			elem.unshift "this"
 		else if opts & BINDING_THIS_TO_TARGET_OPTS and id is 'this'
 			elem.splice 1, 0, 'target'


fixed error where & caused favicon api to crash

--- app/scripts/directives/d3Donut.coffee
+++ app/scripts/directives/d3Donut.coffee
@@ -15,7 +15,8 @@
         if scope.contributor
           scope.percent = (scope.contributor.total_amount / scope.scale)
           # get favicon url from contributor name
-          ApiGet.own "favicon?company=\"#{scope.contributor.name}\"", scope.draw_favicon, this
+          company = scope.contributor.name.replace(/&/i, "and")
+          ApiGet.own "favicon?company=\"#{company}\"", scope.draw_favicon, this
           scope.drawD3()

       # on window resize, redraw d3 canvas


Check for user-provided path to `go` tool.

--- lib/linter/gc.coffee
+++ lib/linter/gc.coffee
@@ -96,8 +96,12 @@
     .map (file) ->
       path.join(here, file)

+    gotool = atom.config.get('atom-lint.gc.path')
+    if not gotool?
+      gotool = "go"
+
     [
-      "go"
+      gotool
       "tool"
       @GOCHAR + 'g'
       "-L" # use full file paths


:art: PP(Personal Preference)

:art: PP(Personal Preference)

--- lib/operators.coffee
+++ lib/operators.coffee
@@ -248,29 +248,30 @@
     @editor.transact =>
       for selection in @editor.getSelections()
         cursor = selection.cursor
-        if type is 'linewise'
-          if selection.isEmpty()
-            if @location is 'before'
-              cursor.moveToBeginningOfLine()
+        switch type
+          when 'linewise'
+            if selection.isEmpty()
+              if @location is 'before'
+                cursor.moveToBeginningOfLine()
+                selection.insertText("\n")
+                cursor.moveUp()
+              else
+                cursor.moveToEndOfLine()
+                selection.insertText("\n")
+
+              text = text.replace(/\n$/, '')
+              range = selection.insertText(text)
+              cursor.setBufferPosition(range.start)
+              cursor.moveToFirstCharacterOfLine()
+            else
               selection.insertText("\n")
-              cursor.moveUp()
-            else
-              cursor.moveToEndOfLine()
-              selection.insertText("\n")
-
-            text = text.replace(/\n$/, '')
+              range = selection.insertText(text)
+              cursor.setBufferPosition(range.start)
+          when 'character'
+            if @location is 'after' and selection.isEmpty()
+              cursor.moveRight()
             range = selection.insertText(text)
-            cursor.setBufferPosition(range.start)
-            cursor.moveToFirstCharacterOfLine()
-          else
-            selection.insertText("\n")
-            range = selection.insertText(text)
-            cursor.setBufferPosition(range.start)
-        else # character
-          if @location is 'after' and selection.isEmpty()
-            cursor.moveRight()
-          range = selection.insertText(text)
-          cursor.setBufferPosition(range.end.translate([0, -1]))
+            cursor.setBufferPosition(range.end.translate([0, -1]))
     @vimState.activateNormalMode()

 class PutAfter extends PutBefore


just check

just check

--- spec/insert-mode-spec.coffee
+++ spec/insert-mode-spec.coffee
@@ -19,16 +19,31 @@
   describe "Copy from line above/below", ->
     beforeEach ->
       set
-        text: "12345\n\nabcd\nefghi"
+        text: """
+        12345
+
+        abcd
+        efghi
+        """
         cursorBuffer: [1, 0]
         addCursor: [3, 0]
       keystroke 'i'

     describe "the ctrl-y command", ->
       it "copies from the line above", ->
-        ensure [ctrl: 'y'], text: '12345\n1\nabcd\naefghi'
+        ensure [ctrl: 'y'], text: """
+        12345
+        1
+        abcd
+        aefghi
+        """
         editor.insertText ' '
-        ensure [ctrl: 'y'], text: '12345\n1 3\nabcd\na cefghi'
+        ensure [ctrl: 'y'], text: '''
+        12345
+        1 3
+        abcd
+        a cefghi
+        """

       it "does nothing if there's nothing above the cursor", ->
         editor.insertText 'fill'


Add spec for encoding ctor param

Add spec for encoding ctor param

--- spec/text-buffer-spec.coffee
+++ spec/text-buffer-spec.coffee
@@ -1820,6 +1820,17 @@
             expect(buffer.getText()).toBe "\ninitialtexthello\n1\n2\n"

   describe "character set encoding support", ->
+    it "allows the encoding to be set on creation", ->
+      filePath = join(__dirname, 'fixtures', 'win1251.txt')
+      buffer = new TextBuffer({filePath, load: true, encoding: 'win1251'})
+
+      waitsFor ->
+        buffer.loaded
+
+      runs ->
+        expect(buffer.getEncoding()).toBe 'win1251'
+        expect(buffer.getText()).toBe 'тест 1234 абвгдеёжз'
+
     describe "when the buffer is unmodified", ->
       describe "when the encoding of the buffer is changed", ->
         beforeEach ->
@@ -1829,7 +1840,7 @@
           waitsFor ->
             buffer.loaded

-        fit "reloads the contents from the disk", ->
+        it "reloads the contents from the disk", ->
           expect(buffer.getEncoding()).toBe 'utf8'
           expect(buffer.getText()).not.toBe 'тест 1234 абвгдеёжз'


:fire: blank line

:fire: blank line

--- lib/vim-state.coffee
+++ lib/vim-state.coffee
@@ -143,7 +143,6 @@
     @searchHistory.reset()
     @hover.reset()
     @operationStack.reset()
-

   # Display cursor in visual mode.
   # ----------------------------------


Properly receive feature toggles as published by core.

--- js-library/app/js/util/modal.coffee
+++ js-library/app/js/util/modal.coffee
@@ -51,3 +51,6 @@
       $(val).contents().unwrap()

   trigger: (e) -> Factlink.trigger(e)
+
+  setFeatureToggles: (featureToggles) ->
+    Factlink.can_haz = featureToggles


(PLATFORM-110) Return promise from deleteObject

--- js/src/service/StorageClient.coffee
+++ js/src/service/StorageClient.coffee
@@ -292,7 +292,8 @@
       if not validateUuid(objectId)
         return Promise.resolve(null)

-      @objectApi.deleteObject(objectId)
-      return
+      return Promise.resolve(
+        @objectApi.deleteObject(objectId)
+      )

   return StorageClient


Created the initial gui, and hooked up the three main buttons.

--- lib/atom-slime-profiler-view.coffee
+++ lib/atom-slime-profiler-view.coffee
@@ -5,34 +5,43 @@
 class ProfilerView extends ScrollView
   @content: ->
     @div outlet:"main", class:"atom-slime-profiler padded", =>
-      @h1 outlet:"errorTitle", =>
-        @text "Error description"
-      @h2 outlet:"errorType", class:"text-subtle", "   Error sub-text"
-      @h3 "Restarts:"
+      @h1 outlet:"profiler-toggle-func-title", =>
+          @text "Toggle profiling of a function"
+      @input outlet:"profiler-function-input", class:"input-text", type:"text", placeholder:"<function name>"
+      @h1 outlet:"profiler-package-title", =>
+          @text "Profile all functions in a package"
+      @input outlet:"profiler-package-input", class:"input-text", type:"text", placeholder:"<package name>"
+      @h1 outlet:"commands-title", =>
+          @text "Profiler Commands"
       @div class:"select-list", =>
-        @ol outlet:"restarts", class:'list-group mark-active', =>
+        @ol outlet:"profiler-command-list", class:'list-group', =>
           @li class:"", =>
-            @button class:"inline-block-tight btn", "Option 1"
-            @text "Description of option 1"
+            @button id:"profiler-unprofile-button", class:"inline-block-tight btn btn-lg", "Unprofile"
+            @text "Unprofile all functions"
           @li class:"", =>
-            @button class:"inline-block-tight btn", "Option 2"
-            @text "Description of option 2"
+            @button id:"profiler-report-button", class:"inline-block-tight btn btn-lg", "Report"
+            @text "Report the profiler data"
           @li class:"", =>
-            @button class:"inline-block-tight btn", "Option 3"
-            @text "Description of option 3"
-          @li class:"", =>
-            @button class:"inline-block-tight btn", "Option 3"
-            @text "Description of option 3"
-
+            @button id:"profiler-reset-button", class:"inline-block-tight btn btn-lg", "Reset"
+            @text "Reset the profiler data"

   setup: (@swank) ->
+    this.find('#profiler-unprofile-button').on 'click', (event) =>
+      @unprofile_click_handler event
+    this.find('#profiler-report-button').on 'click', (event) =>
+      @report_click_handler event
+    this.find('#profiler-reset-button').on 'click', (event) =>
+      @reset_click_handler event
     return

-  restart_click_handler: (event) ->
-    restartindex = event.target.getAttribute('restartindex')
-    level = event.target.getAttribute('level')
-    thread = event.target.getAttribute('thread')
-    @swank.debug_invoke_restart(level, restartindex, thread)
+  unprofile_click_handler: (event) ->
+    atom.notifications.addSuccess('Unprofiling all functions', detail:'Coming soon...')
+
+  report_click_handler: (event) ->
+    atom.notifications.addSuccess('Showing profiler report', detail:'Coming soon...')
+
+  reset_click_handler: (event) ->
+    atom.notifications.addSuccess('Reseting the profiler data', detail:'Coming soon...')

   getTitle: -> "Profiler"


serialize id in bucket model

serialize id in bucket model

--- src/node_modules/bucket-model/bucket-model.coffee
+++ src/node_modules/bucket-model/bucket-model.coffee
@@ -76,6 +76,7 @@

     serialize: ->
       {
+        id: @id
         name: @name
         description: @description
         userId: @user.id


Fix build error.

Fix build error.

--- src/BunyanDebugStream.coffee
+++ src/BunyanDebugStream.coffee
@@ -65,7 +65,7 @@
         super {objectMode: true}

         # Enable colors for non-tty stdout
-        if options.forceColor then colors.enabled = true
+        if @options.forceColor then colors.enabled = true

         # Compile color options
         @_colors = {}


use tools.objects.process instead of for loops

--- tools/objects.coffee
+++ tools/objects.coffee
@@ -573,50 +573,48 @@

     else if objects.isArray source

-        for item in source
-
-            if objects.isObject(item)
-
-                value = null
-                if item.id
-                    for _item in target
-                        if item.id is _item.id
-                            value = _item
-                            break;
-                ## removed this to prevent element merging if id attribute is not present
-                ##else
-                ##    t_index ?= 0
-                ##    if value = target[t_index++]
-                ##
-                ##        while value.id
-                ##            value = target[t_index++]
-
-                if !value
-                    value = if objects.isArray(item) then [] else {}
-                    target.push value
-
-                _extend value, item
-
-            else
-                target.push item
-
+        objects.process source,
+            each: (item, next)->
+
+                if objects.isObject(item)
+
+                    value = null
+                    if item.id
+                        for _item in target
+                            if item.id is _item.id
+                                value = _item
+                                break;
+
+                    if !value
+                        value = if objects.isArray(item) then [] else {}
+                        target.push value
+
+                    _extend value, item
+
+                else
+                    target.push item
+
+                next()
+
     else
-
-        for key, item of source
-            if objects.isObject(item) || objects.isArray(item)
-                if typeof target?[key] isnt typeof item
-                    delete target[key]
-
-                if objects.isBuffer item
+        objects.process source,
+            each: (key, item, next)=>
+                if objects.isObject(item) || objects.isArray(item)
+                    if typeof target?[key] isnt typeof item
+                        delete target[key]
+
+                    if objects.isBuffer item
+                        target[key] = item
+                    else
+                        target[key] ?= if objects.isArray(item) then [] else {}
+
+                        _extend target[key], item
+
+                else
+
                     target[key] = item
-                else
-                    target[key] ?= if objects.isArray(item) then [] else {}
-
-                    _extend target[key], item
-
-            else
-
-                target[key] = item
+
+                next()

 ##
 ##


Tryin some changes

Tryin some changes

--- lib/markdown-table-formatter.coffee
+++ lib/markdown-table-formatter.coffee
@@ -2,7 +2,7 @@
     subscriptions: []
     #regex: /((.+?)\|)+?(.+)?\r?\n(([:\-\|]+?)\|)+?([:\-\|]+)?[ ]*(\r?\n((.+?)\|)+?(.+)?)+/mg
     regex: /((.+?)\|)+?(.+)?\r?\n(([\s:\-\|]+?)\|)+?([\s:\-\|]+)?[ ]*(\r?\n((.+?)\|)+?(.+)?)+/mg
-
+
     constructor: ->
         atom.workspace.observeTextEditors (editor) =>
             subscription = editor.getBuffer().onWillSave =>
@@ -73,18 +73,7 @@

         formatline = lines[1]
         formatrow = 1
-        for line, i in lines
-            if !/\w/.exec(line)
-                formatline = line
-                formatrow = i
-                # console.log(formatline)
-                # console.log(formatrow)
-                break
-
-        removeFormatRow = (s) ->
-             return /\w/.exec(s)
-
-        lines = lines.filter(removeFormatRow)
+        lines.splice(1,1) # Remove the index 1 of the array
         # console.log(lines)

         formatline = formatline.trim().replace(/(^\||\|$)/g,"")


Make the first found item to be automatically selected

This is a regression caused by docquery integration (56821bccbc0294a3b9803d6f8a1c1011155233b0). indexof always returns -1. Since the selected item is always the first filtered item, we can safely set it to 1.

--- lib/notational-velocity-view.coffee
+++ lib/notational-velocity-view.coffee
@@ -136,8 +136,7 @@
         @list.append(itemView)

       if selectedItem
-        n = filteredItems.indexOf(selectedItem) + 1
-        @selectItemView(@list.find("li:nth-child(#{n})"))
+        @selectItemView(@list.find("li:nth-child(#{1})"))

     else
       @setError(@getEmptyMessage(@docQuery.documents.length, filteredItems.length))


@nvh review suggestions

@nvh review suggestions

--- framer/Layer.coffee
+++ framer/Layer.coffee
@@ -53,7 +53,7 @@

 			# We try to not send any events while we run the constructor, it just
 			# doesn't make sense, because no one can listen to use yet.
-			return if @__constructing
+			return if @__constructor

 			@emit("change:#{name}", value)
 			@emit("change:point", value) if name in ["x", "y"]
@@ -84,9 +84,9 @@
 	constructor: (options={}) ->

 		# Make sure we never call the constructor twice
-		throw Error("Layer.constructor #{@toInspect()} called twice") if @__constructed
-		@__constructed = true
-		@__constructing = true
+		throw Error("Layer.constructor #{@toInspect()} called twice") if @__constructorCalled
+		@__constructorCalled = true
+		@__constructor = true

 		# Set needed private variables
 		@_properties = {}
@@ -142,7 +142,7 @@
 		@_stateMachine = new LayerStateMachine(@)
 		@_context.emit("layer:create", @)

-		delete @__constructing
+		delete @__constructor

 	##############################################################
 	# Properties


Making behaviour for ignoring clicks while dragging better

--- framer/Layer.coffee
+++ framer/Layer.coffee
@@ -73,7 +73,6 @@

 		# Private setting for canceling of click event if wrapped in moved draggable
 		@_cancelClickEventInDragSession = true
-		@_cancelClickEventInDragSessionTolerance = 4

 		# We have to create the element before we set the defaults
 		@_createElement()
@@ -943,11 +942,7 @@

 		if @_cancelClickEventInDragSession
 			if eventName is Events.Click
-				parentDraggableLayer = @_parentDraggableLayer()
-				if parentDraggableLayer
-					offset = parentDraggableLayer.draggable.offset
-					return if Math.abs(0 - offset.x) > @_cancelClickEventInDragSessionTolerance
-					return if Math.abs(0 - offset.y) > @_cancelClickEventInDragSessionTolerance
+				return if @_parentDraggableLayer()?.draggable.isMoving

 		# Always scope the event this to the layer and pass the layer as
 		# last argument for every event.


Smarter cache disabling for images

Smarter cache disabling for images

--- framer/Layer.coffee
+++ framer/Layer.coffee
@@ -364,7 +364,7 @@
 			# imageUrl = Config.baseUrl + imageUrl

 			# If the file is local, we want to avoid caching
-			if Utils.isLocal()
+			if Utils.isLocal() and not (_.startsWith(imageUrl, "http://") or _.startsWith(imageUrl, "https://"))
 				imageUrl += "?nocache=#{Date.now()}"

 			# As an optimization, we will only use a loader


Fix error 'wrong regexp' when unwanted characters

--- lib/services/php-file-parser.coffee
+++ lib/services/php-file-parser.coffee
@@ -264,6 +264,9 @@
   getVariableType: (editor, bufferPosition, element) ->
     idx = 1

+    if not element.match(/[\$][a-zA-Z0-9_]+/g)
+      return null
+
     # Regex variable definition
     regexElement = new RegExp("\\#{element}[\\s]*=[\\s]*([^;]+);", "g")
     while bufferPosition.row - idx > 0


Err includes message in it, so check on it

--- client/app/MainApp/fs/fsfolder.coffee
+++ client/app/MainApp/fs/fsfolder.coffee
@@ -25,7 +25,7 @@
     , (err, response)=>
       # log "------------------------------------------------------------------"
       # log "l flag response in: #{Date.now()-a} msec."
-      if not err or /ls\:\scannot\saccess/.test err
+      if not err or /ls\:\scannot\saccess/.test err.message
         files = FSHelper.parseLsOutput [@path], response
         @emit "fs.fetchContents.finished", files
         callback? files


fix perf : when search is empty, useless span were created

--- client/app/utils/message_utils.coffee
+++ client/app/utils/message_utils.coffee
@@ -57,6 +57,7 @@
     # Highlight search pattern in a string
     highlightSearch: (text) ->
         return [] unless text
+        return [text] if SearchStore.getCurrentSearch() is ''

         search  = new RegExp SearchStore.getCurrentSearch(), 'gi'
         substrs = text.match search


Fix spelling

Fix spelling

--- client/components/ReviewResult.coffee
+++ client/components/ReviewResult.coffee
@@ -234,7 +234,7 @@
                                         </ButtonGroup>
                                         }
                                     </FormGroup>
-                                    <Button onClick={@downloadSubmits} bsSize="xsmall">re-download sumits</Button>
+                                    <Button onClick={@downloadSubmits} bsSize="xsmall">re-download submits</Button>
                                 </div>
                             }
                         </div>


Revert ":atom: Configure wrap guides for Git commit messages"

I was hoping ccb4ac95fc would have the multiple wrap guides appear only
in Git commit messages, but that hasn't been the case. 🙈 So, let's
revert ccb4ac95fc.

--- atom/config.cson
+++ atom/config.cson
@@ -90,5 +90,5 @@
   welcome:
     showOnStartup: false
 ".git-commit.text":
-  'wrap-guide':
-    'columns': [50, 72]
+  editor:
+    preferredLineLength: 72


:atom: Update config.cson for Atom

:atom: Update config.cson for Atom

--- atom/config.cson
+++ atom/config.cson
@@ -107,6 +107,7 @@
   tabs:
     enableVcsColoring: true
   teletype:
+    askBeforeJoiningPortalViaExternalApp: false
     dev: {}
   welcome:
     showOnStartup: false


Make updates and comment corrections to keymap

--- atom/keymap.cson
+++ atom/keymap.cson
@@ -12,9 +12,9 @@
   'ctrl-shift-L': 'unset!'
   'shift-cmd-L': 'grammar-selector:show'
   # Toggles invisible characters and guides
-  'shift-cmd-I': 'window:toggle-invisibles'
-  'alt-shift-cmd-I': 'editor:toggle-indent-guide'
-  # Execute and view output from scripts within the editor
+  'cmd-i': 'window:toggle-invisibles'
+  'shift-cmd-I': 'editor:toggle-indent-guide'
+  # Execute and view output from scripts within editor
   'shift-cmd-R': 'script:run'
   'alt-shift-cmd-R': 'script:run-options'
   # Toggles character encoding selection panel
@@ -22,12 +22,12 @@
   'cmd-shift-U': 'encoding-selector:show'
   # Toggles line jump panel
   'cmd-j': 'go-to-line:toggle'
-  # Rebind "Delete Line" key key binding to something more convenient
+  # Deletes an entire line without copying it
   'ctrl-shift-K': 'unset!'
   'shift-cmd-X': 'editor:delete-line'
-  # Selects all occurences of the current selection (complements cmd-d)
+  # Selects all occurences of current selection (complements cmd-d)
   'alt-cmd-d': 'find-and-replace:select-all'
-  # Selects all text between the outer matching pair of parens/brackets
+  # Selects all text between outer matching pair of parens/brackets
   'alt-cmd-b': 'bracket-matcher:select-inside-brackets'

 'atom-text-editor':
@@ -46,26 +46,29 @@
   'alt-f': 'unset!'
   'alt-shift-F': 'unset!'
   'alt-h': 'unset!'
+  'alt-shift-S': 'unset!'

-# Toggle list of snippets that apply to current document
 'atom-text-editor:not([mini])':
-  'alt-shift-S': 'unset!'
+  # Toggles list of snippets that apply to current document
   'ctrl-cmd-s': 'snippets:available'
+  # Advances to next Linter error in document
   'alt-cmd-l': 'linter:next-error'
+  # Expands/contracts selection to next outermost/innermost set of tokens
   'alt-up': 'expand-region:expand'
   'alt-down': 'expand-region:shrink'

-# Disable Emmet's key binding for merging lines
 '.platform-darwin atom-text-editor:not([mini])':
+  # Aligns values to same column if list of key-value pairs is selected
   'ctrl-cmd-a': 'unset!'
   'shift-cmd-A': 'atom-alignment:alignMultiple'
   # Toggles Markdown Preview (even if editor is unfocused)
   'shift-cmd-M': 'markdown-preview:toggle'
   'ctrl-w': 'unset!'
+  # Expands Emmet HTML abbreviations
   'cmd-e': 'emmet:expand-abbreviation'
   'shift-cmd-E': 'emmet:wrap-with-abbreviation'
 '.platform-darwin atom-workspace':
-  # Open URLs in the browser if the insertion point is within the URL
+  # Opens inline URL in default web browser if cursor is within URL
   'ctrl-shift-O': 'unset!'
   'alt-cmd-o': 'link:open'


Drop SpacePen exports from ‘atom’ module

--- exports/atom.coffee
+++ exports/atom.coffee
@@ -24,57 +24,6 @@
   module.exports.Task = require '../src/task'
   module.exports.TextEditor = require '../src/text-editor'

-  if includeDeprecatedAPIs
-    {$, $$, $$$, View} = require '../src/space-pen-extensions'
-
-    Object.defineProperty module.exports, 'Workspace', get: ->
-      deprecate """
-        Requiring `Workspace` from `atom` is no longer supported.
-        If you need this, please open an issue on
-        https://github.com/atom/atom/issues/new
-        And let us know what you are using it for.
-      """
-      require '../src/workspace'
-
-    Object.defineProperty module.exports, '$', get: ->
-      deprecate """
-        Requiring `$` from `atom` is no longer supported.
-        If you are using `space-pen`, please require `$` from `atom-space-pen-views`. Otherwise require `jquery` instead:
-          `{$} = require 'atom-space-pen-views'`
-          or
-          `$ = require 'jquery'`
-        Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
-        Or add `"jquery": "^2"` to your package dependencies.
-      """
-      $
-
-    Object.defineProperty module.exports, '$$', get: ->
-      deprecate """
-        Requiring `$$` from `atom` is no longer supported.
-        Please require `atom-space-pen-views` instead:
-          `{$$} = require 'atom-space-pen-views'`
-        Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
-      """
-      $$
-
-    Object.defineProperty module.exports, '$$$', get: ->
-      deprecate """
-        Requiring `$$$` from `atom` is no longer supported.
-        Please require `atom-space-pen-views` instead:
-          `{$$$} = require 'atom-space-pen-views'`
-        Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
-      """
-      $$$
-
-    Object.defineProperty module.exports, 'View', get: ->
-      deprecate """
-        Requiring `View` from `atom` is no longer supported.
-        Please require `atom-space-pen-views` instead:
-          `{View} = require 'atom-space-pen-views'`
-        Add `"atom-space-pen-views": "^2.0.3"` to your package dependencies.
-      """
-      View
-
 if includeDeprecatedAPIs
   Object.defineProperty module.exports, 'Git', get: ->
     deprecate "Please require `GitRepository` instead of `Git`: `{GitRepository} = require 'atom'`"


avstreams: Print created stream name

avstreams: Print created stream name

--- avstreams.coffee
+++ avstreams.coffee
@@ -206,7 +206,9 @@

   get: (streamId) ->
     if streamGenerators[streamId]?
-      return streamGenerators[streamId].generate()
+      stream = streamGenerators[streamId].generate()
+      logger.debug "created stream #{stream.id}"
+      return stream
     else
       return streams[streamId]


minor tweaking to atom conf, still in early stages

--- atom.cson
+++ atom.cson
@@ -1,13 +1,14 @@
-welcome:
-  showOnStartup: false
-core:
-  autoHideMenuBar: true
-  projectHome: "/home/walther/git"
-editor:
-  invisibles: {}
-  fontFamily: "DejaVu Sans Mono for Powerline"
-  scrollPastEnd: true
-  showInvisibles: true
-  showIndentGuide: true
-  softWrap: true
-
+"*":
+  welcome:
+    showOnStartup: false
+  core:
+    autoHideMenuBar: true
+    themes: [
+      "one-dark-ui"
+      "monokai"
+    ]
+  editor:
+    fontFamily: "DejaVu Sans Mono for Powerline"
+    scrollPastEnd: true
+    showIndentGuide: true
+    softWrap: true


only need to load rootFolder from project

--- services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
+++ services/web/app/coffee/Features/Project/ProjectEntityHandler.coffee
@@ -171,7 +171,7 @@
 				return cb(null, project_or_id)
 			else # id
 				# need to retrieve full project structure to check for duplicates
-				return ProjectGetter.getProject project_or_id, {}, cb
+				return ProjectGetter.getProject project_or_id, {rootFolder:true, name:true}, cb
 		getProject (error, project) ->
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add doc"
@@ -208,7 +208,7 @@
 			ProjectEntityHandler.addDoc project_id, null, name, lines, callback

 	addFileWithoutUpdatingHistory: (project_id, folder_id, fileName, path, userId, callback = (error, fileRef, folder_id, path, fileStoreUrl) ->)->
-		ProjectGetter.getProject project_id, {}, (err, project) ->
+		ProjectGetter.getProject project_id, {rootFolder:true, name:true}, (err, project) ->
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add file"
 				return callback(err)
@@ -341,7 +341,7 @@
 				callback(null, folders, lastFolder)

 	addFolder: (project_id, parentFolder_id, folderName, callback) ->
-		ProjectGetter.getProject project_id, {}, (err, project)=>
+		ProjectGetter.getProject project_id, {rootFolder:true, name:true}, (err, project)=>
 			if err?
 				logger.err project_id:project_id, err:err, "error getting project for add folder"
 				return callback(err)


small cleanup

small cleanup

--- examples/reload-http-server/http-server.coffee
+++ examples/reload-http-server/http-server.coffee
@@ -1,3 +1,6 @@
 http = require 'http'
-server = http.createServer (req, res) -> res.end "hai\n"
+
+server = http.createServer (req, res) ->
+  res.end "hello chi.js()\n"
+
 server.listen 2121, -> console.log "listening on localhost:2121"


Fix issue with TileMap not being updated when a map changed in the MapView.

--- src/adventure/mapView.coffee
+++ src/adventure/mapView.coffee
@@ -88,6 +88,9 @@
   shadowOverlay : null

   constructor: (gurk) ->
+    @tileMap = new TileMap(gurk.game.map)
+    @tileMapView = new TileMapView gurk.screen.canvas, @tileMap
+    @tileMapView.featureVisible = @featureVisible
     super(gurk, gurk.game.map)
     @name = "MapView"
     @offsetX = -Screen.HALF_UNIT
@@ -107,9 +110,6 @@
         @shadows[y + Screen.CENTER_OFFSET][x + Screen.CENTER_OFFSET] = false
     @centerBanner = true
     @move(0, 0)
-    @tileMap = new TileMap(gurk.game.map)
-    @tileMapView = new TileMapView gurk.screen.canvas, @tileMap
-    @tileMapView.featureVisible = @featureVisible

   featureVisible: (feature) =>
     if @game.getFeatures(feature.x, feature.y)
@@ -407,6 +407,7 @@

   setMap : (mapName, x, y) =>
     super(mapName, x, y)
+    @tileMap.setMap(mapName)
     if (@map.music)
       @gurk.playMusic(@map.music)


Workspace: Add slug to scheme.

Workspace: Add slug to scheme.

--- workers/social/lib/social/models/workspace.coffee
+++ workers/social/lib/social/models/workspace.coffee
@@ -1,5 +1,5 @@
-{ Model }  = require 'bongo'
-{ Module } = require 'jraphical'
+{Inflector}  = require 'bongo'
+{Module}     = require 'jraphical'

 module.exports = class JWorkspace extends Module

@@ -7,12 +7,13 @@
   @share()

   @set
-    schema            :
-      name            : String
-      machineUId      : String
-      rootPath        : String
-      owner           : String
-      layout          : Object
+    schema         :
+      name         : String
+      slug         : String
+      machineUId   : String
+      rootPath     : String
+      owner        : String
+      layout       : Object

     sharedMethods  :
       static       :


Fix grammars to support OCaml

Fix grammars to support OCaml

Removes "Command not configured for OCaml!" issue, since the grammars had a typo that made it not recognize OCaml files.

--- lib/grammars.coffee
+++ lib/grammars.coffee
@@ -346,7 +346,7 @@
         command: "bash"
         args: (context) -> ['-c', "xcrun clang++ -fcolor-diagnostics -Wc++11-extensions -Wall -include stdio.h -include iostream -framework Cocoa " + context.filepath + " -o /tmp/objc-cpp.out && /tmp/objc-cpp.out"]

-  ocaml:
+  OCaml:
     "File Based":
       command: "ocaml"
       args: (context) -> [context.filepath]


Fixing spawnSync. When we set cwd to @rootPath it stops working. Removing cwd option since we already pass the repository/file path as an hg command argument.

--- lib/hg-utils.coffee
+++ lib/hg-utils.coffee
@@ -245,8 +245,7 @@

     return '' unless @isCommandForRepo(params)

-    options = { cwd: @rootPath }
-    child = spawnSync('hg', params, options)
+    child = spawnSync('hg', params)
     if child.status != 0
       if child.stderr
         throw new Error(child.stderr.toString())


Improved input command and file path patterns (still need work)

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -699,31 +699,41 @@
     patterns: [{ include: '$self'}]
   }
   inputFile: {
-    comment: 'Matches the input/include command and allows custom path colours. Technically a single letter file is valid, but I think it unlikely someone legitimately means it.'
-    begin: '\\\\(input|include)(?=[^a-zA-Z@])'
-    beginCaptures:
-      0: name: 'keyword.control.$1.latex'
-    end: '(?<=\\})|(^\\s*$)'
-    endCaptures:
-      1: name: 'invalid.illegal.latex'
-    patterns:[
-      { include: '#awaitingArgumentBrackets' }
-      {
-        comment: 'Only this one necessary because escaped characters will be picked up by awaitingArgumentBrackets.'
-        include: '#lineComment'
-      }
-      { include: '#filePathScope' }
+    patterns: [
+      {
+        comment: 'Matches the input/include command and allows custom path colours. Braces are technically optional, but the command will only be recognised if present.'
+        contentName: 'variable.parameter.arguments.latex'
+        begin: '((\\\\)(input|include))\\s*(\\{)'
+        beginCaptures:
+          1: name: 'keyword.control.$1.latex'
+          2: name: 'punctuation.definition.function.latex'
+          4: name: 'punctuation.definition.arguments.begin.latex'
+        end: '(\\})'
+        endCaptures:
+          1: name: 'punctuation.definition.arguments.end.latex'
+        patterns:[
+          { include: '#filePathScope' }
+        ]
+      }
+      {
+        comment: 'For alternative syntax without braces'
+        match: '((\\\\)(input|include))\\s*(.*?)(?:\\s|$)'
+        captures:
+          1: name: 'keyword.control.$1.latex'
+          2: name: 'punctuation.definition.function.latex'
+          4: patterns: [
+            { include: '#escapedCharacter' }
+            { include: '#controlWord' }
+            { include: '#controlSymbol' }
+            { include: '#lineComment' }
+            { include: '#filePathScope' }
+            { include: '$self' }
+          ]
+      }
     ]
   }
   filePathScope: {
     comment: 'Matches a file path (UNIX only, add Windows yourself reader).'
-    contentName: 'variable.parameter.arguments.latex'
-    begin: '\\{'
-    beginCaptures:
-      0: name: 'punctuation.definition.arguments.begin.latex'
-    end: '\\}'
-    endCaptures:
-      0: name: 'punctuation.definition.arguments.end.latex'
     patterns: [
       {
         name: 'support.filepath.back.latex'
@@ -739,11 +749,15 @@
       }
       {
         name: 'support.filepath.directory.latex'
-        match: '[^(\\.+\\/)].*?\\/'
+        match: '[^(?:\\.+\\/)]([^%]*?)\\/'
+        captures:
+          1: patterns: [{ include: '$self' }]
       }
       {
         name: 'support.filepath.file.latex'
-        match: '[^}]*'
+        match: '([^}%]*)'
+        captures:
+          1: patterns: [{ include: '$self' }]
       }
     ]
   }


Make sure direction updates

Make sure direction updates