Activation waits for no-one

Activation waits for no-one

--- lib/one-tab.coffee
+++ lib/one-tab.coffee
@@ -1,16 +1,17 @@
 {CompositeDisposable} = require 'atom'

 class OneTab
-    activate: ->
-        atom.packages.onDidActivateInitialPackages =>
-            @subscriptions = new CompositeDisposable
-            @subscriptions.add atom.workspace.observePanes (pane) =>
-                @initPane pane
+    activate: (state) ->
+        @subscriptions = new CompositeDisposable
+        @subscriptions.add atom.workspace.observePanes (pane) =>
+            @initPane pane

     deactivate: ->
         @subscriptions.dispose()

     initPane: (pane) ->
+        @updateTabBarVisibility pane
+
         subscription = new CompositeDisposable
         subscription.add pane.onDidDestroy ->
             subscription.dispose()
@@ -21,8 +22,6 @@
         subscription.add pane.onDidRemoveItem =>
             @updateTabBarVisibility pane

-        @updateTabBarVisibility pane
-
     updateTabBarVisibility: (pane) ->
         paneView = atom.views.getView pane


add gc_add_root

add gc_add_root

--- lib/runtime.coffee
+++ lib/runtime.coffee
@@ -54,6 +54,7 @@
         string_concat:         -> @abi.createExternalFunction @module, "_ejs_string_concat",             types.EjsValue, [types.EjsValue, types.EjsValue]
         init_string_literal:   -> @abi.createExternalFunction @module, "_ejs_string_init_literal",       types.void, [types.string, types.EjsValue.pointerTo(), types.EjsPrimString.pointerTo(), types.jschar.pointerTo(), types.int32]

+        gc_add_root:           -> @abi.createExternalFunction @module, "_ejs_gc_add_root",               types.void, [types.EjsValue.pointerTo()]
         typeof_is_object:      -> returns_ejsval_bool only_reads_memory @abi.createExternalFunction @module, "_ejs_op_typeof_is_object",       types.EjsValue, [types.EjsValue]
         typeof_is_function:    -> returns_ejsval_bool only_reads_memory @abi.createExternalFunction @module, "_ejs_op_typeof_is_function",     types.EjsValue, [types.EjsValue]
         typeof_is_string:      -> returns_ejsval_bool only_reads_memory @abi.createExternalFunction @module, "_ejs_op_typeof_is_string",       types.EjsValue, [types.EjsValue]


no need to log this data

no need to log this data

--- js/src/http/UserDirectoryApi.coffee
+++ js/src/http/UserDirectoryApi.coffee
@@ -53,7 +53,6 @@
           method : 'GET'
         })
       .then (response) ->
-        log.info('response', response)
         uuid = response.data
         if uuid is 'null' or !uuid
           return undefined
@@ -76,7 +75,6 @@
       .then (axiosResponse) ->
         if axiosResponse? and axiosResponse.data?
           user = axiosResponse.data
-          log.info('getUser', user)
           Cache.store(Cache.USERS, uuid, user)
           return user
         else
@@ -101,7 +99,6 @@
         })
       .then (response) ->
         users = response.data
-        log.info('getUsers', users)
         if users is 'null' or !users
           return undefined
         for user in users


implemented updating browser url for working hours statistics

--- app/assets/javascripts/statistics.js.coffee
+++ app/assets/javascripts/statistics.js.coffee
@@ -12,6 +12,7 @@

 updateWorkingDaysStatistics = (start_date, end_date, users) ->
   base_url = $("#base-url").val()
+  history.pushState {}, '', base_url+'?start_date='+start_date+'&end_date='+end_date+'&users='+users
   $.get base_url + '/content/',
     start_date: start_date
     end_date: end_date


Prepare for major reformatting

Prepare for major reformatting

--- grammars/latex.cson
+++ grammars/latex.cson
@@ -27,9 +27,10 @@
   metaControl: {
     comment: 'All these commands begin with a backslash.'
     patterns: [
-      { include: '#doubleBackslash' }
+      { include: '#doubleBackslash' } # appears first to prevent the second slash being used
       { include: '#escapedCharacter' }
-      { include: '#displayMathMode' }
+      { include: '#displayMathMode'}
+      { include: '#inlineMathMode' }
       { include: '#documentclass' }
       { include: '#usepackage' }
       { include: '#inputFile' }
@@ -41,11 +42,18 @@
       { include: '#makeatsomething' }
       { include: '#verbatim' }
       { include: '#item' }
-      { include: '#displayMathMode'}
-      { include: '#inlineMathMode' }
-      { include: '#metaPrimitives'}
+      { include: '#metaPrimitives' }
       { include: '#controlSymbol' }
       { include: '#controlWord' }
+
+
+      # { include: '#metaDollar' } # Because of \( and \[. Must appear below escaped characters, to prevent
+      # { include: '#metaEnvironments' }
+      # { include: '#metaCommonControlSequences' }
+      # # The following rules are "catch alls" for any control sequences not explicitly addressed above.
+      # { include: '#metaPrimitives' }
+      # { include: '#controlSymbol' }
+      # { include: '#controlWord' }
     ]
   }
   metaPercent: {
@@ -165,7 +173,7 @@
     match: '\\\\(\\&|\\%|\\$|\\#|\\_|\\{|\\}|(textascii(tilde|circum)|textbackslash)(?=[^a-zA-Z@]))'
   }
   controlSymbol: {
-    comment: 'Mostly covered by escapedCharacter, but this is a catch all for any contol symbols'
+    comment: 'Mostly covered by escapedCharacter, but this is a catch all for any control symbols'
     name: 'keyword.control.symbol.latex'
     match: '\\\\[^a-zA-Z]'
   }


Color * in syntax command as operator, not comment (at start of line)

--- grammars/stata.cson
+++ grammars/stata.cson
@@ -346,7 +346,25 @@
             'name': 'entity.name.type.class.stata'
           }
           {
-            'include': '$self'
+            'include': '#constants'
+          }
+          {
+            'include': '#operators'
+          }
+          {
+            'include': '#string-compound'
+          }
+          {
+            'include': '#string-regular'
+          }
+          {
+            'include': '#macro-local'
+          }
+          {
+            'include': '#macro-global'
+          }
+          {
+            'include': '#builtin_variables'
           }
         ]
       }
@@ -399,7 +417,25 @@
                     'name': 'support.type.stata'
               }
               {
-                'include': '$self'
+                'include': '#constants'
+              }
+              {
+                'include': '#operators'
+              }
+              {
+                'include': '#string-compound'
+              }
+              {
+                'include': '#string-regular'
+              }
+              {
+                'include': '#macro-local'
+              }
+              {
+                'include': '#macro-global'
+              }
+              {
+                'include': '#builtin_variables'
               }
             ]
           }
@@ -409,7 +445,25 @@
             'name': 'entity.name.type.class.stata'
           }
           {
-            'include': '$self'
+            'include': '#constants'
+          }
+          {
+            'include': '#operators'
+          }
+          {
+            'include': '#string-compound'
+          }
+          {
+            'include': '#string-regular'
+          }
+          {
+            'include': '#macro-local'
+          }
+          {
+            'include': '#macro-global'
+          }
+          {
+            'include': '#builtin_variables'
           }
         ]
       }


Add generic directive/component for lightbox blocking message input.

--- app/coffee/modules/common/lightboxes.coffee
+++ app/coffee/modules/common/lightboxes.coffee
@@ -148,6 +148,46 @@

 module.directive("tgLbBlock", ["lightboxService", BlockLightboxDirective])

+
+#############################################################################
+## Generic Lightbox Blocking-Message Input Directive
+#############################################################################
+
+BlockingMessageInputDirective = ($log) ->
+    template = _.template("""
+    <fieldset class="blocked-note hidden">
+        <textarea name="blocked_note"
+            placeholder="Why is this user story blocked?"
+            ng-model="<%- ngmodel %>">
+        </textarea>
+    </fieldset>
+    """)
+
+    link = ($scope, $el, $attrs, $model) ->
+        if not $attrs.watch
+            return $log.error "No watch attribute on tg-blocking-message-input directive"
+
+        $scope.$watch $attrs.watch, (value) ->
+            return if value is undefined
+
+            if value == true
+                $el.find(".blocked-note").show(400)
+            else
+                $el.find(".blocked-note").hide(400)
+
+    templateFn = ($el, $attrs) ->
+        return template({ngmodel: $attrs.ngModel})
+
+    return {
+        template: templateFn
+        link: link
+        require: "ngModel"
+        restrict: "EA"
+    }
+
+module.directive("tgBlockingMessageInput", ["$log", BlockingMessageInputDirective])
+
+
 #############################################################################
 ## Create/Edit Userstory Lightbox Directive
 #############################################################################


Remove a log no longer relevant to modern browsers

--- app/collections/ThangNamesCollection.coffee
+++ app/collections/ThangNamesCollection.coffee
@@ -9,8 +9,6 @@
   constructor: (@ids) ->
     super()
     @ids.sort()
-    if @ids.length > 55
-      console.error 'Too many ids, we\'ll likely go over the GET url kind-of-limit of 2000 characters.'

   fetch: (options) ->
     options ?= {}


debackbone behavior fixed

debackbone behavior fixed

--- app/controllers/templates_controller.coffee
+++ app/controllers/templates_controller.coffee
@@ -106,10 +106,10 @@

 #delete
 action 'delete', ->
-	if req.query.id?
+	if params.id?
 		requests = []
 		requests.push (callback) -> #0 -> delete
-				ds.deleteById callback, req.query.id
+				ds.deleteById callback, params.id
 		async.parallel requests, (error, results) ->
 				jsonRes = []
 				if error


Remove debugger statement

Remove debugger statement

--- bokehjs/src/coffee/models/annotations/label.coffee
+++ bokehjs/src/coffee/models/annotations/label.coffee
@@ -85,7 +85,6 @@

   render: () ->
     [@sx, @sy] = @_map_data()
-    debugger;
     if @mget('render_mode') == 'canvas'
       @_canvas_text()
     else


Invitations: Fix permission error log.

Invitations: Fix permission error log.

--- workers/social/lib/social/models/invitation.coffee
+++ workers/social/lib/social/models/invitation.coffee
@@ -120,27 +120,30 @@
   # some selects result set for invitations, it adds group name automatically
   @some$: permit 'send invitations',
     success: (client, selector, options, callback) ->
-      { groupSlug } = selector
-      groupName     = client.context.group or 'koding'
-      @canFetchInvitationsAsSuperAdmin client, (err, isSuperAdmin) ->
-        selector           or= {}
-        selector.groupName   = groupName # override group name in any case
-        selector.status    or= 'pending'
-
-        # allow only koding super admin to update groupName in query
-        if isSuperAdmin and groupSlug and client.context.group is 'koding'
-          selector.groupName = groupSlug
-
-        # delete groupSlug to prevent suspicious queries
+
+      { groupSlug }        = selector
+      groupName            = client.context.group or 'koding'
+      selector           or= {}
+      selector.status    or= 'pending'
+      selector.groupName   = groupName # override group name in any case
+      fetchInvitations     = ->
         delete selector.groupSlug

         { limit }       = options
         options.sort  or= { createdAt : -1 }
+        options.skip   ?= 0
         options.limit or= 25
         options.limit   = Math.min options.limit, 25 # admin can fetch max 25 record
-        options.skip   ?= 0

         JInvitation.some selector, options, callback
+
+      if groupSlug and client.context.group is 'koding'
+        @canFetchInvitationsAsSuperAdmin client, (err, isSuperAdmin) ->
+          selector.groupName = groupSlug  if isSuperAdmin
+          fetchInvitations()
+      else
+        fetchInvitations()
+

   # search searches database with given query string, adds `starting
   # with regex` around query param


groups: invoke `JGroup#finalizeMemberApproval` in `JUser::finishRegistration`

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -831,7 +831,18 @@
               account.update $set: { firstName, lastName }, (err) ->
                 return callback err  if err

-                callback null, { account, replacementToken }
+                client.connection.delegate = account
+
+                account.fetchGroups client, (err, groups) ->
+                  queue = groups.map ({group}) ->
+                    ->
+                      return queue.fin()  unless group
+                      return queue.fin()  if group.slug in ["koding", "guests"]
+                      group.finalizeMemberApproval account, ->
+                        queue.fin()
+
+                  dash queue, ->
+                    callback null, { account, replacementToken }

   @removeUnsubscription:({email}, callback)->
     JUnsubscribedMail = require '../unsubscribedmail'


Tidy accessibility tests

Tidy accessibility tests

--- test/src/system/accessibility_test.coffee
+++ test/src/system/accessibility_test.coffee
@@ -1,45 +1,31 @@
 {assert, test, testGroup, triggerEvent} = Trix.TestHelpers

 testGroup "Accessibility attributes", template: "editor_default_aria_label", ->
-  test "sets the role to textbox", (done) ->
+  test "sets the role to textbox", ->
     editor = document.getElementById("editor-without-labels")
+    assert.equal editor.getAttribute("role"), "textbox"

-    assert.equal editor.getAttribute("role"), "textbox"
-    done()
+  test "does not set aria-label when the element has no  elements", ->
+    editor = document.getElementById("editor-without-labels")
+    assert.equal editor.hasAttribute("aria-label"), false

-  test "does not set aria-label when the element has no  elements", (done) ->
-    editor = document.getElementById("editor-without-labels")
+  test "does not override aria-label when the element declares it", ->
+    editor = document.getElementById("editor-with-aria-label")
+    assert.equal editor.getAttribute("aria-label"), "ARIA Label text"

-    assert.equal editor.hasAttribute("aria-label"), false
-    done()
-
-  test "does not override aria-label when the element declares it", (done) ->
-    editor = document.getElementById("editor-with-aria-label")
-
-    assert.equal editor.getAttribute("aria-label"), "ARIA Label text"
-    done()
-
-  test "does not set aria-label when the element declares aria-labelledby", (done) ->
+  test "does not set aria-label when the element declares aria-labelledby", ->
     editor = document.getElementById("editor-with-aria-labelledby")
-
     assert.equal editor.hasAttribute("aria-label"), false
     assert.equal editor.getAttribute("aria-labelledby"),"aria-labelledby-id"
-    done()

-  test "assigns aria-label to the text of the element's  elements", (done) ->
+  test "assigns aria-label to the text of the element's  elements", ->
     editor = document.getElementById("editor-with-labels")
+    assert.equal editor.getAttribute("aria-label"), "Label 1 Label 2 Label 3"

-    assert.equal editor.getAttribute("aria-label"), "Label 1 Label 2 Label 3"
-    done()
-
-  test "updates the aria-label on focus", (done) ->
+  test "updates the aria-label on focus", ->
     editor = document.getElementById("editor-with-modified-label")
     label = document.getElementById("modified-label")

-    assert.equal editor.getAttribute("aria-label"), "Original Value"
-
     label.innerHTML = "New Value"
     triggerEvent(editor, "focus")
-
     assert.equal editor.getAttribute("aria-label"), "New Value"
-    done()


social: preserve email address before user deletion

--- workers/social/lib/social/models/user/index.coffee
+++ workers/social/lib/social/models/user/index.coffee
@@ -235,18 +235,22 @@

       userValues = {
-        email           : email
-        sanitizedEmail  : email
-        status          : 'deleted'
-        sshKeys         : []
-        username        : username
-        password        : createId()
-        foreignAuth     : {}
-        onlineStatus    : 'offline'
-        registeredAt    : new Date 0
-        lastLoginDate   : new Date 0
-        passwordStatus  : 'autogenerated'
-        emailFrequency  : {}
+        email               : email
+        sanitizedEmail      : email
+        # here we have a trick, emailBeforeDeletion is not in the schema but we
+        # are setting it to the db. it is not in the schema because we dont want
+        # it to be seen in the codebase and it wont be mapped to a JUser
+        emailBeforeDeletion : user.email
+        status              : 'deleted'
+        sshKeys             : []
+        username            : username
+        password            : createId()
+        foreignAuth         : {}
+        onlineStatus        : 'offline'
+        registeredAt        : new Date 0
+        lastLoginDate       : new Date 0
+        passwordStatus      : 'autogenerated'
+        emailFrequency      : {}
       }
       modifier = { $set: userValues, $unset: { oldUsername: 1 } }
       # update the user with empty data


Reject and remove activation deferral on deactivation

--- src/atom-package.coffee
+++ src/atom-package.coffee
@@ -185,6 +185,8 @@
         console.error "Error serializing package '#{@name}'", e.stack

   deactivate: ->
+    @activationDeferred.reject()
+    @activationDeferred = null
     @unsubscribeFromActivationEvents()
     @deactivateResources()
     @deactivateConfig()


DOM

DOM

- Fixed "isInDOM" to work also on non HTMLElements, like SVG.

--- src/base/DOM/DOM.coffee
+++ src/base/DOM/DOM.coffee
@@ -941,7 +941,7 @@
 		if not docElem
 			return null

-		assert(docElem instanceof HTMLElement, "CUI.DOM.isInDOM", "docElem needs to be instanceof HTMLElement.", docElem: docElem)
+		assert(docElem instanceof Node, "CUI.DOM.isInDOM", "docElem needs to be instanceof Node.", docElem: docElem)
 		if @closestUntil(docElem, document.documentElement)
 			true
 		else


Limit ranking 5

Limit ranking 5

--- view/coffee/game/station_modal.coffee
+++ view/coffee/game/station_modal.coffee
@@ -18,13 +18,13 @@
       @getDistances()
     getTimes: ->
       API.getJSON "/api/game/#{@mission.mission.id}/ranking/time", (json) =>
-        @times = json
+        @times = json.slice(0, 5)
     getMoneys: ->
       API.getJSON "/api/game/#{@mission.mission.id}/ranking/money", (json) =>
-        @moneys = json
+        @moneys = json.slice(0, 5)
     getDistances: ->
       API.getJSON "/api/game/#{@mission.mission.id}/ranking/distance", (json) =>
-        @distances = json
+        @distances = json.slice(0, 5)
   watch: ->
     'mission.id': ->
       @getTimes()


[Browser] Fix missing entry point requiring

--- src/browser/main.coffee
+++ src/browser/main.coffee
@@ -8,8 +8,7 @@
 path = require "path"

 app = require "app"
-
-App = require "./App"
+App = require "./app/App"

 parseCommandLine = ->
     yargs = require("yargs")


Teambuilder: Blanking out moves counts as a change.

--- client/app/js/views/teambuilder_view.coffee
+++ client/app/js/views/teambuilder_view.coffee
@@ -274,8 +274,10 @@
     @filterMovesBy("")
     $(".table-moves .active").removeClass("active")

-    return  if $input.val().length == 0
-    @insertMove($input, moveName)
+    if $input.val().length == 0
+      @recordMoves()
+    else
+      @insertMove($input, moveName)

   clickMoveName: (e) =>
     $this = $(e.currentTarget)
@@ -290,9 +292,11 @@
     return  if !@buttonify($input, moveName)
     $moves = @getActivePokemonView().find('.selected_moves')
     $moves.find('input').first().focus()
-
-    # Record moves
+    @recordMoves()
+
+  recordMoves: =>
     movesArray = []
+    $moves = @getActivePokemonView().find('.selected_moves')
     $moves.find('.move-button').each ->
       moveName = $(this).text().trim()
       if moveName != ""


test/teamshelpers: wait until private stack created helper

--- client/test/lib/helpers/teamshelpers.coffee
+++ client/test/lib/helpers/teamshelpers.coffee
@@ -461,6 +461,21 @@
       .setValue stackTemplateNameArea, stackName
       .click saveButtonSelector, =>
         @waitUntilToCreatePrivateStack browser, done
+
+
+  waitUntilToCreatePrivateStack: (browser, done) ->
+
+    stackEditorHeader = '.StackEditorView--header'
+    makeTeamDefaultButton = "#{stackEditorHeader} .kdbutton.GenericButton.set-default.w-loader"
+
+    browser
+      .pause 3000
+      .element 'css selector', makeTeamDefaultButton, (result) =>
+        if result.status is 0
+           browser.url (res) ->
+            done res
+
+        else @waitUntilToCreatePrivateStack browser, done

   defineCustomVariables: (browser) ->


quick fix fro bug caused by lodash update


Convert to spaces

Convert to spaces

--- paths.coffee
+++ paths.coffee
@@ -4,95 +4,95 @@

 module.exports =

-	allPosts: ->
-		returnObj = {}
-		posts = _.map @postReq().keys(), (name) =>
-			[
-				name
-				@postReq() name
-			]
+  allPosts: ->
+    returnObj = {}
+    posts = _.map @postReq().keys(), (name) =>
+      [
+        name
+        @postReq() name
+      ]

-		# Include drafts if we're not in prod
-		drafts = if process.env.NODE_ENV isnt 'production'
-			_.map @draftReq().keys(), (name) =>
-				[
-					name
-					_. assign draft: true, @draftReq() name
-				]
-		else []
+    # Include drafts if we're not in prod
+    drafts = if process.env.NODE_ENV isnt 'production'
+      _.map @draftReq().keys(), (name) =>
+        [
+          name
+          _. assign draft: true, @draftReq() name
+        ]
+    else []

-		# Build some nice objects from the files
-		_.each posts.concat(drafts), (fileArr) ->
+    # Build some nice objects from the files
+    _.each posts.concat(drafts), (fileArr) ->

-			# Name is on format ./YYYY-MM-DD-url_title.md
-			# TODO Configurable file name standard
+      # Name is on format ./YYYY-MM-DD-url_title.md
+      # TODO Configurable file name standard

-			fileName = fileArr[0].slice 2 # Remove the "./"
-			file = fileArr[1]
+      fileName = fileArr[0].slice 2 # Remove the "./"
+      file = fileArr[1]

-			processedFile = processPost file, fileName
+      processedFile = processPost file, fileName

-			returnObj[processedFile.url] = processedFile
-		returnObj
+      returnObj[processedFile.url] = processedFile
+    returnObj

-	allPages: ->
-		# TODO allow hooks on page processing
-		req = @pageReq()
-		pages = {}
-		_.each req.keys(), (name) ->
-			# Name is on format ./url_title.ext
+  allPages: ->
+    # TODO allow hooks on page processing
+    req = @pageReq()
+    pages = {}
+    _.each req.keys(), (name) ->
+      # Name is on format ./url_title.ext

-			file = req name # Require the file
-			fileName = name.slice 2 # Remove the "./"
+      file = req name # Require the file
+      fileName = name.slice 2 # Remove the "./"

-			url = _.kebabCase fileName.split('.')[0] # url is filename minus extention
-			title = _.capitalize url.replace /\-/g , ' ' # Title is the capitalized url
+      url = _.kebabCase fileName.split('.')[0] # url is filename minus extention
+      title = _.capitalize url.replace /\-/g , ' ' # Title is the capitalized url

-			if url is 'index' then url = '/' # Rewrite index file
-			pages[url] =
-			{
-				url
-				fileName
-				title
-			}
-		pages
+      if url is 'index' then url = '/' # Rewrite index file
+      pages[url] =
+      {
+        url
+        fileName
+        title
+      }
+    pages

-	postForPath: (path) ->
-		@allPosts()[path]
+  postForPath: (path) ->
+    @allPosts()[path]

-	pageForPath: (path) ->
-		@allPages()[path]
+  pageForPath: (path) ->
+    @allPages()[path]

-	pageReq: ->
-		require.context 'pages', false
+  pageReq: ->
+    require.context 'pages', false

-	postReq: ->
-		require.context 'posts', false, /^\.\/.*\.md$/
+  postReq: ->
+    require.context 'posts', false, /^\.\/.*\.md$/

-	draftReq: ->
-		require.context 'drafts', false, /^\.\/.*\.md$/
+  draftReq: ->
+    require.context 'drafts', false, /^\.\/.*\.md$/

-	parseContent: (content) ->
-		MdHelper.parse content
+  parseContent: (content) ->
+    MdHelper.parse content

 processPost = (file, fileName) ->
-		# TODO Implement nicer hooks to configurable functions
+    # TODO Implement nicer hooks to configurable functions

-		#Clean the filename to get the url
-		url = themeFunctions?.url?(file, fileName) or fileName.slice 0, fileName.length - 3
+    #Clean the filename to get the url
+    url = themeFunctions?.url?(file, fileName) or fileName.slice 0, fileName.length - 3

-		# Get the date from the file name if it's not in the frontmatter
-		date = themeFunctions?.date?(file, fileName) or (file.date or fileName.slice 0, 10)
+    # Get the date from the file name if it's not in the frontmatter
+    date = themeFunctions?.date?(file, fileName) or (file.date or fileName.slice 0, 10)

-		# Get the content
-		content = MdHelper.parse file.__content
+    # Get the content
+    content = MdHelper.parse file.__content

-		# Generate the preview
-		preview = themeFunctions?.preview?(file, fileName) or (file.preview or MdHelper.getContentPreview file.__content)
+    # Generate the preview
+    preview = themeFunctions?.preview?(file, fileName) or (file.preview or MdHelper.getContentPreview file.__content)

-		_.assign {}, file, {
-			url
-			content
-			date
-			preview
-		}
+    _.assign {}, file, {
+      url
+      content
+      date
+      preview
+    }


Leave the _closePromise in place

Leave the _closePromise in place

--- drivers/javascript/net.coffee
+++ drivers/javascript/net.coffee
@@ -543,17 +543,7 @@
         # callback to the current promise
         if @_closePromise?
             return @_closePromise.nodeify(cb)
-        else if not @open
-            # if we're closed, we still need to return a promise. So
-            # we create a dummy promise that resolves on the next tick
-            # of the event loop and will invoke all of the callbacks
-            # attached to it.
-            return new Promise((resolve, reject) =>
-                if cb?
-                    cb(null , @)
-                else
-                process.nextTick(resolve)
-            )
+
         # Next we set `@closing` to true. It will be set false once
         # the promise that `.close` returns resolves (see below). The
         # `isOpen` method takes this variable into account.
@@ -604,7 +594,6 @@
                 @open = false
                 @closing = false
                 @cancel()
-                @_closePromise = null
                 if err?
                     reject err
                 else


project page: fixing scrollTop restoration after using smc-vfill flex layout for the "editor_inner_container" element -- #2780

--- src/smc-webapp/project_page.cjsx
+++ src/smc-webapp/project_page.cjsx
@@ -18,6 +18,8 @@
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 ###############################################################################
+
+$ = window.$

 ###
 project page react component
@@ -242,11 +244,11 @@
     restore_scroll_position: ->
         saved_scroll = @props.opened_file?.get('component')?.scroll_position
         if saved_scroll?
-            @refs.editor_inner_container.scrollTop = saved_scroll
+            $(@refs.editor_inner_container).children()[0].scrollTop = saved_scroll

     save_scroll_position: ->
         if @refs.editor_inner_container? and @props.save_scroll?
-            val = @refs.editor_inner_container.scrollTop
+            val = $(@refs.editor_inner_container).children()[0].scrollTop
             @props.save_scroll(val)

     render_editor: (path) ->


input tag becomes open after adding "Watch"

--- lib/Components/CallStackPane.coffee
+++ lib/Components/CallStackPane.coffee
@@ -223,6 +223,7 @@
       log "TreeViewWatchItem.load #{state.expression()}"
       if state.expression() is ""
         return new Promise (resolve) ->
+          state.editMode.set(true)
           t = TreeViewItem("<expression not set - double click to edit>", handlers: { dblclick: () => state.editMode.set(true) })
           state.value.set([t])
           resolve(state)


Closes #1888; Add mimetye image/vnd.microsoft.icon to mimtype list

--- packages/rocketchat-assets/server/assets.coffee
+++ packages/rocketchat-assets/server/assets.coffee
@@ -1,5 +1,7 @@
 sizeOf = Npm.require 'image-size'
 mime = Npm.require 'mime-types'
+
+mime.extensions['image/vnd.microsoft.icon'] = ['ico']

 @RocketChatAssetsInstance = new RocketChatFile.GridFS
 	name: 'assets'


Check if searching for an id

Check if searching for an id

--- server/handlers/user_handler.coffee
+++ server/handlers/user_handler.coffee
@@ -718,8 +718,13 @@
       host: config.sphinxServer
       port: 9306
     connection.connect()
-    q = req.body.search;
-    mysqlq = "SELECT *, WEIGHT() as skey FROM user WHERE MATCH(?);"
+
+    q = req.body.search
+    if isID q
+      mysqlq = "SELECT *, WEIGHT() as skey FROM user WHERE mongoid = ? LIMIT 100;"
+    else
+      mysqlq = "SELECT *, WEIGHT() as skey FROM user WHERE MATCH(?)  LIMIT 100;"
+
     connection.query mysqlq, [q], (err, rows, fields) =>
       return @sendDatabaseError res, err if err
       ids = rows.map (r) -> r.mongoid


Activity: minor: unnecessary fat arrow removed

--- client/Social/Activity/views/embedboxwidget.coffee
+++ client/Social/Activity/views/embedboxwidget.coffee
@@ -61,7 +61,7 @@

     fn = @bound 'checkInputForUrls'

-    input.on 'keydown', (event) =>
+    input.on 'keydown', (event) ->
       fn()  if event.which in [9, 13, 32]

     input.on 'paste', fn
@@ -264,4 +264,4 @@
   pistachio:->
     """
     {{> @settingsButton}}
-    """
+    """


Environment: Define new action types

Environment: Define new action types

--- client/app/lib/flux/environment/actiontypes.coffee
+++ client/app/lib/flux/environment/actiontypes.coffee
@@ -16,9 +16,11 @@

   'WORKSPACE_CREATED'
   'WORKSPACE_DELETED'
-  'WORKSPACE_COULD_NOT_CREATE'
+  'WORKSPACE_SELECTED'
   'SHOW_ADD_WORKSPACE_VIEW'
   'HIDE_ADD_WORKSPACE_VIEW'
   'WORKSPACE_DELETED_FAIL'
-  'WORKSPACE_SELECTED'
+  'WORKSPACE_COULD_NOT_CREATE'
+  'SHOW_DELETE_WORKSPACE_WIDGET'
+  'HIDE_DELETE_WORKSPACE_WIDGET'
 }


Adjust pixelRectForScreenRange to return absolute values

--- src/text-editor-component.coffee
+++ src/text-editor-component.coffee
@@ -416,17 +416,12 @@
     @presenter.screenPositionForPixelPosition(pixelPosition)

   pixelRectForScreenRange: (screenRange) ->
-    if screenRange.end.row > screenRange.start.row
-      top = @pixelPositionForScreenPosition(screenRange.start).top
-      left = 0
-      height = (screenRange.end.row - screenRange.start.row + 1) * @lineHeight
-      width = @scrollWidth
-    else
-      {top, left} = @pixelPositionForScreenPosition(screenRange.start, false)
-      height = @lineHeight
-      width = @pixelPositionForScreenPosition(screenRange.end, false).left - left
-
-    {top, left, width, height}
+    rect = @presenter.pixelRectForScreenRange(screenRange)
+    rect.top += @presenter.getScrollTop()
+    rect.bottom += @presenter.getScrollTop()
+    rect.left += @presenter.getScrollLeft()
+    rect.right += @presenter.getScrollLeft()
+    rect

   pixelRangeForScreenRange: (screenRange, clip=true) ->
     {start, end} = Range.fromObject(screenRange)


collaboration: removed video collab controller

--- client/ide/lib/videocollaborationcontroller.coffee
+++ client/ide/lib/videocollaborationcontroller.coffee
@@ -1,233 +0,0 @@
-kd                              = require 'kd'
-bowser                          = require 'bowser'
-isKoding                        = require 'app/util/isKoding'
-showError                       = require 'app/util/showError'
-socialHelpers                   = require './collaboration/helpers/social'
-isVideoFeatureEnabled           = require 'app/util/isVideoFeatureEnabled'
-VideoCollaborationModel         = require 'app/videocollaboration/model'
-LimitedVideoCollaborationModal  = require './views/collaboration/limitedvideocollaborationmodal'
-
-
-generatePayloadFromModel = (model) ->
-  return {
-    activeParticipant   : model.getActiveParticipant()
-    selectedParticipant : model.getSelectedParticipant()
-    participants        : model.getParticipants()
-  }
-
-
-# If you want to limit {X} plan, you can add here and `LimitedVideoCollaborationModal.coffee`
-PLAN_PARTICIPANT_LIMITS = {
-  free : 2
-}
-
-
-module.exports = VideoCollaborationController =
-
-
-  prepareVideoCollaboration: ->
-
-    if bowser.safari or bowser.msie or bowser.msedge
-      browser = if bowser.safari then 'Safari' else 'Internet Explorer'
-      showError """
-        The video component is not supported for #{browser}.<br />
-        To enable this functionality, please use Google Chrome or Firefox.
-      """
-      return
-
-    @videoModel = new VideoCollaborationModel
-      channel : @socialChannel
-      view    : @chat.getVideoView()
-
-    @videoModel
-      .on 'SessionConnected',              @bound 'handleVideoSessionConnected'
-      .on 'CameraAccessQuestionAsked',     @bound 'handleVideoAccessQuestionAsked'
-      .on 'CameraAccessQuestionAnswered',  @bound 'handleVideoAccessQuestionAnswered'
-      .on 'VideoCollaborationActive',      @bound 'handleVideoActive'
-      .on 'VideoCollaborationEnded',       @bound 'handleVideoEnded'
-      # .on 'ParticipantConnected',          @bound 'handleVideoParticipantConnected'
-      # .on 'ParticipantDisconnected',       @bound 'handleVideoParticipantDisconnected'
-      # .on 'ParticipantJoined',             @bound 'handleVideoParticipantJoined'
-      # .on 'ParticipantLeft',               @bound 'handleVideoParticipantLeft'
-      .on 'ActiveParticipantChanged',      @bound 'handleVideoActiveParticipantChanged'
-      .on 'SelectedParticipantChanged',    @bound 'handleVideoSelectedParticipantChanged'
-      .on 'ParticipantAudioStateChanged',  @bound 'handleVideoParticipantAudioStateChanged'
-      .on 'ParticipantCameraStateChanged', @bound 'handleVideoParticipantCameraStateChanged'
-      .on 'ParticipantStartedTalking', (participant) =>
-        @handleVideoParticipantTalkingStateChanged participant, on
-      .on 'ParticipantStoppedTalking', (participant) =>
-        @handleVideoParticipantTalkingStateChanged participant, off
-
-    participantEvents = [
-      'SelectedParticipantChanged'
-      'ParticipantConnected'
-      'ParticipantJoined'
-      'ParticipantLeft'
-      'ParticipantDisconnected'
-    ]
-
-    @videoModel.on participantEvents, @bound 'handleVideoParticipantAction'
-
-    @on 'CollaborationDidCleanup', =>
-      @videoModel.session?.disconnect()
-
-
-  fetchVideoParticipants: (callback) ->
-
-    callback @videoModel.getParticipants()
-
-
-  startVideoCollaboration: ->
-
-    @canUserStartVideo =>
-      @videoModel.start()
-
-
-  endVideoCollaboration: -> @videoModel.end()
-
-
-  joinVideoCollaboration: -> @videoModel.join()
-
-
-  leaveVideoCollaboration: -> @videoModel.leave()
-
-
-  muteParticipant: (nickname) -> @videoModel.muteParticipant nickname
-
-
-  toggleVideoControl: (type, activeState) ->
-
-    switch type
-      when 'audio'   then @videoModel.requestAudioStateChange activeState
-      when 'video'   then @videoModel.requestVideoStateChange activeState
-      when 'speaker' then @videoModel.requestSpeakerStateChange activeState
-      when 'end'     then @endVideoCollaboration()
-      when 'leave'   then @leaveVideoCollaboration()
-
-
-  switchToUserVideo: (nickname) ->
-
-    @videoModel.changeSelectedParticipant nickname
-
-
-  hasParticipantWithAudio: (nickname, callback) ->
-
-    @videoModel.hasParticipantWithAudio nickname, callback
-
-
-  handleVideoSessionConnected: (session, videoActive) ->
-
-    isVideoFeatureEnabled (enabled) =>
-      return  unless enabled
-
-      if videoActive
-        @emitToViews 'VideoSessionConnected', { action: 'join' }
-      else
-        if @amIHost
-          @emitToViews 'VideoSessionConnected', { action: 'start' }
-
-
-  handleVideoAccessQuestionAsked: ->
-
-
-  handleVideoAccessQuestionAnswered: ->
-
-
-  handleVideoEnded: ->
-    @emitToViews 'VideoCollaborationEnded'
-
-
-  handleVideoActive: (publisher) ->
-    @emitToViews 'VideoCollaborationActive'
-
-
-  handleVideoParticipantAction: ->
-
-    payload = generatePayloadFromModel @videoModel
-    @emitToViews 'VideoParticipantsDidChange', payload
-
-
-  handleVideoParticipantConnected: (participant) ->
-    @emitToViews 'VideoParticipantDidConnect', participant
-
-
-  handleVideoParticipantDisconnected: (participant) ->
-    @emitToViews 'VideoParticipantDidDisconnect', participant
-
-
-  handleVideoParticipantJoined: (participant) ->
-    @emitToViews 'VideoParticipantDidJoin', participant
-
-
-  handleVideoParticipantLeft: (participant) ->
-    @emitToViews 'VideoParticipantDidLeave', participant
-
-
-  handleVideoSelectedParticipantChanged: (nickname, isOnline) ->
-
-    unless nickname
-      @emitToViews 'VideoSelectedParticipantDidChange', null, null, isOnline
-      return
-
-    socialHelpers.fetchAccount nickname, (err, account) =>
-      return console.error err  if err
-      @emitToViews 'VideoSelectedParticipantDidChange', nickname, account, isOnline
-
-
-  handleVideoActiveParticipantChanged: (nickname) ->
-    socialHelpers.fetchAccount nickname, (err, account) =>
-      return console.error err  if err
-      @emitToViews 'VideoActiveParticipantDidChange', nickname, account
-
-
-  handleVideoParticipantAudioStateChanged: (participant, state) ->
-    @emitToViews 'VideoParticipantAudioStateDidChange', participant
-
-
-  handleVideoParticipantCameraStateChanged: (participant, state) ->
-    @emitToViews 'VideoParticipantCameraStateDidChange', participant
-
-
-  handleVideoParticipantTalkingStateChanged: (participant, state) ->
-    @emitToViews 'VideoParticipantTalkingStateDidChange', participant, state
-
-
-  emitToViews: (args...) ->
-    @statusBar?.emit args...
-    @chat?.emit args...
-
-
-  isVideoActive: (callback) ->
-
-    state = @videoModel.state.active
-
-    callback? state
-    return state
-
-
-  canUserStartVideo: (callback = kd.noop) ->
-
-    { paymentController } = kd.singletons
-
-    return callback()  unless isKoding()
-
-    @whenRealtimeReady =>
-
-      paymentController.subscriptions (err, plan) =>
-
-        return showError err  if err
-
-        { planTitle }     = plan
-
-        # If there isn't any limit according to current plan.
-        return callback()  unless PLAN_PARTICIPANT_LIMITS[planTitle]
-
-        limit             = PLAN_PARTICIPANT_LIMITS[planTitle]
-        participantsCount = @participants.asArray().length
-        isVideoActive     = @videoModel.state.active
-
-        if participantsCount > limit or (participantsCount is 2 and isVideoActive)
-          @emit 'UserReachedVideoLimit'
-          return new LimitedVideoCollaborationModal plan: planTitle
-
-        callback()


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -7,4 +7,4 @@

   self.bind "update", ->
     I.x = I.x.clamp(I.width / 2, App.width - I.width / 2)
-    I.y = I.y.clamp(I.height / 2, App.height - I.h)
+    I.y = I.y.clamp(I.height / 2, App.height - I.height /2 )


removed unused function "rm()"

removed unused function "rm()"

--- proxy.coffee
+++ proxy.coffee
@@ -14,7 +14,6 @@
     return
 log new Date().toISOString()

-rm = (a, x) -> i = a.indexOf x; (if i != -1 then a.splice i, 1); return
 b64 = (s) -> Buffer(s).toString 'base64'
 b64d = (s) -> '' + Buffer s, 'base64'
 tag = (tagName, xml) -> (///^[^]*<#{tagName}>([^<]*)</#{tagName}>[^]*$///.exec xml)?[1]


resurrection.activity: sanitize input if it's content is not empty

--- client/Social/Activity/views/inputview.coffee
+++ client/Social/Activity/views/inputview.coffee
@@ -48,8 +48,10 @@
     {prefix} = @activeRule
     value = @tokenInput.textContent.substring prefix.length
     words = value.split /\W/, 3
-    @tokenInput.textContent = prefix + words.join "-"
-    @utils.selectEnd @tokenInput
+    if words.join("") isnt ""
+      newval = prefix + words.join "-"
+      @tokenInput.textContent = newval
+      @utils.selectEnd @tokenInput

   selectToken: ->
     return  unless @menu


Check that only one splat is used

Check that only one splat is used


ClampBounds docs

ClampBounds docs

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -1,6 +1,7 @@
 ###*
 The ClampBounds module adds a check to make sure
-that the including GameObject doesn't move out
+that the including GameObject doesn't move outside
+the

 # Health regeneration


Refactor

Refactor

--- app/assets/javascripts/app/select2/view.coffee
+++ app/assets/javascripts/app/select2/view.coffee
@@ -84,7 +84,7 @@
       @model.get('related').update(addedElement)
       @$edit.show() if @$edit
     else if e.removed
-      $(@$item[1]).attr('value', '')
+      @$item.val('')
       @model.get('related').clear()
       @$edit.hide() if @$edit


Fix TypeError

Fix TypeError

--- lib/ghc-mod/ghc-modi-process.coffee
+++ lib/ghc-mod/ghc-modi-process.coffee
@@ -141,7 +141,7 @@
         else
           []
     runArgs.dir ?= @getRootDir(runArgs.buffer) if runArgs.buffer?
-    runArgs.options ?= Util.getProcessOptions(runArgs.dir.getPath())
+    runArgs.options ?= Util.getProcessOptions(runArgs.dir?.getPath?())
     qe = (qn) =>
       q = @commandQueues[qn]
       q.getQueueLength() + q.getPendingLength() is 0


The button toggles modal, not just opens

--- resources/assets/coffee/forum-topic-cover.coffee
+++ resources/assets/coffee/forum-topic-cover.coffee
@@ -22,7 +22,7 @@

   constructor: ->
-    $(document).on 'click', '.js-forum-topic-cover--open-modal', @openModal
+    $(document).on 'click', '.js-forum-topic-cover--open-modal', @toggleModal
     $(document).on 'click', '.js-forum-topic-cover--remove', @remove
     $(document).on 'click', @closeModal

@@ -35,8 +35,10 @@
   closeModal: (e) =>
     return unless @header.length && @header[0]._open

-    return if $(e.target).closest('.js-forum-topic-cover--modal').length
-    return if $(e.target).closest('.js-forum-topic-cover--open-modal').length
+    if e
+      return if $(e.target).closest('.js-forum-topic-cover--open-modal').length
+      return if $(e.target).closest('.js-forum-topic-cover--modal').length
+
     return if $('#overlay').is(':visible')

     $('.blackout').css display: 'none'
@@ -49,9 +51,16 @@
     return @uploadButton[0].getAttribute('data-method') != 'post'

-  openModal: (e) =>
+  toggleModal: (e) =>
     e.preventDefault()

+    if @header[0]._open
+      @closeModal()
+    else
+      @openModal()
+
+
+  openModal: =>
     $('.blackout').css display: 'block'
     @header[0]._open = true
     @header[0].classList.add 'forum-category-header--cover-modal'


Update author image to be https

Update author image to be https

Update author image to be https

--- docpad.coffee
+++ docpad.coffee
@@ -29,7 +29,7 @@
       ]
     author:
       name: 'Matt Kotsenas'
-      img: 'http://gravatar.com/avatar/13e6e96d176cd18ef232d054b8e65f55'
+      img: 'https://gravatar.com/avatar/13e6e96d176cd18ef232d054b8e65f55'
       url: '/'
       location: 'Seattle, WA',
       bio: ''


List blog posts by filename prefix.

List blog posts by filename prefix.

--- docpad.coffee
+++ docpad.coffee
@@ -129,13 +129,12 @@
       return docsCollection.models[docsCollection.length-1]

   # =================================
-  # Collections
-  # These are special collections that our website makes available to us

   collections:

     blog: (database) ->
-      database.findAllLive({layout:$has:'blog-post'}, [date:1]).on 'add', (document) ->
+      sorting = [filename:-1]
+      database.findAllLive({layout:$has:'blog-post'}, sorting).on 'add', (document) ->
         a = document.attributes
         contentPreview = a.content.substring(0,150)
         contentPreview = contentPreview + " ..."


add label to no internet view

add label to no internet view


clean out some copy-pasted cruft

clean out some copy-pasted cruft

--- src/command/revoke.iced
+++ src/command/revoke.iced
@@ -43,25 +43,6 @@

   #----------

-  sign : (cb) ->
-    eng = new KeybasePushProofGen { @km }
-    await eng.run defer err, @sig
-    cb err
-
-  #----------
-
-  push : (cb) ->
-    args =
-      is_primary : 1
-      sig : @sig.pgp
-      sig_id_base : @sig.id
-      sig_id_short : @sig.short_id
-      public_key : @km.key.toString('utf8')
-    await req.post { endpoint : "key/add", args }, defer err
-    cb err
-
-  #----------
-
   get_the_go_ahead : (cb) ->
     err = null
     unless @argv.force


Make settings-view backwards compatible with old apm

Older apm versions don't show git packages so settings
view shows an empty list

Signed-off-by: Michelle Tilley <19f7a7eb6786def4c39d6d86c40af5dbc6589663@github.com>

--- lib/installed-packages-panel.coffee
+++ lib/installed-packages-panel.coffee
@@ -105,7 +105,7 @@
     packages.user = packages.user.filter ({theme}) -> not theme
     packages.deprecated = packages.user.filter ({name, version}) -> atom.packages.isDeprecatedPackage(name, version)
     packages.core = packages.core.filter ({theme}) -> not theme
-    packages.git = packages.git.filter ({theme}) -> not theme
+    packages.git = (packages.git or []).filter ({theme}) -> not theme

     for pack in packages.core
       pack.repository ?= "https://github.com/atom/#{pack.name}"


#813 - A user can modify the 'appearance' field of a question with a dropdown selector

--- jsapp/xlform_model_view/view.rowDetail.coffee
+++ jsapp/xlform_model_view/view.rowDetail.coffee
@@ -108,6 +108,15 @@
     checkbox: (cid, key, key_label = key, input_label = 'Yes') ->
       @field """<input type="checkbox" name="#{key}" id="#{cid}"/> #{input_label}""", cid, key_label

+    dropdown: (cid, key, values, key_label = key) ->
+      select = """<select id="#{cid}">"""
+
+      for value in values
+        select += """<option value="#{value}">#{value}</option>"""
+
+      select += "</select>"
+
+      @field select, cid, key_label
     field: (input, cid, key_label) ->
       """

@@ -238,17 +247,43 @@

   viewRowDetail.DetailViewMixins.appearance =
     html: ->
-      @$el.addClass("card__settings__fields--active")
-      if @model._parent.constructor.key == 'group'
-        viewRowDetail.Templates.checkbox @cid, @model.key, 'Appearance (advanced)', 'Show all questions in this group on the same screen'
+      types =
+        text: ['multiline']
+        select_one: ['minimal', 'quick', 'horizontal-compact', 'horizontal', 'likert', 'compact', 'quickcompact', 'label', 'list-nolabel']
+        select_multiple: ['minimal', 'horizontal-compact', 'horizontal', 'compact', 'label', 'list-nolabel']
+        image: ['signature', 'draw']
+        date: ['month-year', 'year']
+        group: ['select', 'field-list', 'table-list', 'other']
+
+      @$el.addClass("card__settings__fields--active")
+      if @model_is_group()
+        return viewRowDetail.Templates.dropdown @cid, @model.key, types.group, 'Appearance'
       else
-        viewRowDetail.Templates.textbox @cid, @model.key, 'Appearance (advanced)', 'text'
-    afterRender: ->
-      if @model._parent.constructor.key == 'group'
-        $checkbox = @$('input[type=checkbox]').eq(0)
-        value_lookup = ['', 'field-list']
-        $checkbox.on 'change', () =>
-          @model.set('value', value_lookup[+$checkbox.prop('checked')])
+        appearances = types[@model._parent.getValue('type').split(' ')[0]]
+        if appearances?
+          appearances.push 'other'
+          appearances.unshift 'select'
+          return viewRowDetail.Templates.dropdown @cid, @model.key, appearances, 'Appearance'
+        else
+          return viewRowDetail.Templates.textbox @cid, @model.key, 'Appearance', 'text'
+
+    model_is_group: () ->
+      @model._parent.constructor.key == 'group'
+
+    afterRender: ->
+      $select = @$('select')
+      if $select.length > 0
+        $input = $('<input/>', {class:'text', type: 'text', width: 'auto'})
+        $select.change () =>
+          if $select.val() == 'other'
+            @model.set 'value', ''
+            @$('.settings__input').append $input
+            @listenForInputChange el: $input
+          else if $select.val() == 'select'
+            @model.set 'value', ''
+          else
+            @model.set 'value', $select.val()
+            $input.remove()
       else
         @listenForInputChange()


Don't show index when "index" field is not available

--- bokehjs/src/coffee/widget/data_table.coffee
+++ bokehjs/src/coffee/widget/data_table.coffee
@@ -123,7 +123,7 @@
         checkboxSelector = new CheckboxSelectColumn(cssClass: "bk-cell-select")
         columns.unshift(checkboxSelector.getColumnDefinition())

-      if @mget("row_headers")
+      if @mget("row_headers") and @mget("source").get_column("index")?
         columns.unshift(@newIndexColumn())

       width = @mget("width")


Fix incorrect version in CoffeeScript portion.

--- src/coffee/index.coffee
+++ src/coffee/index.coffee
@@ -1,7 +1,7 @@
 leveldb = exports = module.exports = require './leveldb/handle'
 binding = require '../build/Release/leveldb.node'

-leveldb.version = '0.7.0'
+leveldb.version = '0.7.1'
 leveldb.bindingVersion = "#{binding.majorVersion}.#{binding.minorVersion}"

 leveldb.Batch = require('./leveldb/batch').Batch


more declarative style for tools that extend ToolView

--- src/coffee/tools.coffee
+++ src/coffee/tools.coffee
@@ -90,25 +90,43 @@
       @eventSink.trigger("#{@options.eventBasename}:DragEnd")

-class PanToolView extends Bokeh.PlotWidget
+
+class ToolView extends Bokeh.PlotWidget
   initialize : (options) ->
     super(options)
   bind_events : (plotview) ->
     eventSink = plotview.eventSink
-    evgen = new TwoPointEventGenerator(
-      eventBasename:"PanTool", keyName:"shiftKey", buttonText:"Pan Tool")
+    @plotview = plotview
+
+
+    evgen_options = { eventBasename:@cid }
+
+    evgen_options2 = _.extend(evgen_options, @evgen_options)
+    evgen = new @eventGeneratorClass(evgen_options2)
     evgen.bind_events(plotview, eventSink)
-    eventSink.on('PanTool:UpdatingMouseMove', (e) =>
-      @_drag(e.foo, e.foo, e, e.layerX, e.layerY))
-    eventSink.on('PanTool:SetBasepoint', (e) =>
-      @_set_base_point(e, e.layerX, e.layerY))
+
+    _.each(@tool_events, (handler_f, event_name) =>
+      full_event_name = "#{@cid}:#{event_name}"
+      wrap = (e) =>
+        @[handler_f](e)
+      eventSink.on(full_event_name, wrap))
+
+
+class PanToolView extends ToolView
+
+
+  eventGeneratorClass : TwoPointEventGenerator
+  evgen_options : {keyName:"shiftKey", buttonText:"Pan Tool"}
+  tool_events : {
+    UpdatingMouseMove: "_drag",
+    SetBasepoint : "_set_base_point"}

   mouse_coords : (e, x, y) ->
     [x_, y_] = [@plot_model.rxpos(x), @plot_model.rypos(y)]
     return [x_, y_]

-  _set_base_point : (e, x, y) ->
-    [@x, @y] = @mouse_coords(e, x, y)
+  _set_base_point : (e) ->
+    [@x, @y] = @mouse_coords(e, e.layerX, e.layerY)
     xmappers = (@model.resolve_ref(x) for x in @mget('xmappers'))
     ymappers = (@model.resolve_ref(x) for x in @mget('ymappers'))

@@ -123,12 +141,11 @@
       'end' : end
     }, {'local' : true})

-  _drag : (xdiff, ydiff, e, x__, y__) ->
-    if _.isUndefined(xdiff) or _.isUndefined(ydiff)
-      [x, y] = @mouse_coords(e, x__, y__)
-      xdiff = x - @x
-      ydiff = y - @y
-      [@x, @y] = [x, y]
+  _drag : (e) ->
+    [x, y] = @mouse_coords(e, e.layerX, e.layerY)
+    xdiff = x - @x
+    ydiff = y - @y
+    [@x, @y] = [x, y]
     xmappers = (@model.resolve_ref(x) for x in @mget('xmappers'))
     ymappers = (@model.resolve_ref(x) for x in @mget('ymappers'))
     for xmap in xmappers
@@ -137,7 +154,7 @@
       @_drag_mapper(ymap, ydiff)

-class SelectionToolView extends Bokeh.PlotWidget
+class SelectionToolView extends ToolView
   initialize : (options) ->
     super(options)
     select_callback = _.debounce((() => @_select_data()),50)
@@ -153,20 +170,14 @@
       safebind(this, renderer.get_ref('xmapper'), 'change', select_callback)
       safebind(this, renderer.get_ref('ymapper'), 'change', select_callback)

-  bind_events : (plotview) ->
-    @plotview = plotview
-    eventSink = plotview.eventSink
-    evgen = new TwoPointEventGenerator(
-      eventBasename:"SelectionTool", keyName:"ctrlKey", buttonText:"Selection Tool")
-    evgen.bind_events(plotview, eventSink)
-    eventSink.on('SelectionTool:UpdatingMouseMove', (e) =>
-      @_selecting(e, e.layerX, e.layerY))
-
-    eventSink.on('SelectionTool:SetBasepoint', (e) =>
-      @_start_selecting(e, e.layerX, e.layerY))
-
-    eventSink.on('SelectionTool:deactivated', (e) =>
-      @_stop_selecting())
+
+  eventGeneratorClass : TwoPointEventGenerator
+  evgen_options : {keyName:"ctrlKey", buttonText:"Selection Tool"}
+  tool_events : {
+    UpdatingMouseMove: "_selecting",
+    SetBasepoint : "_start_selecting",
+    deactivated : "_stop_selecting"}
+

   mouse_coords : (e, x, y) ->
     [x, y] = [@plot_model.rxpos(x), @plot_model.rypos(y)]
@@ -188,8 +199,8 @@
       @shading.remove()
       @shading = null

-  _start_selecting : (e, x_, y_) ->
-    [x, y] = @mouse_coords(e, x_, y_)
+  _start_selecting : (e) ->
+    [x, y] = @mouse_coords(e, e.layerX, e.layerY)
     @mset({'start_x' : x, 'start_y' : y, 'current_x' : null, 'current_y' : null})
     for renderer in @mget('renderers')
       data_source = @model.resolve_ref(renderer).get_ref('data_source')
@@ -211,7 +222,7 @@
     return [xrange, yrange]

   _selecting : (e, x_, y_) ->
-    [x, y] = @mouse_coords(e, x_, y_)
+    [x, y] = @mouse_coords(e, e.layerX, e.layerY)
     @mset({'current_x' : x, 'current_y' : y})
     return null


event propagaiton prevention code a bit too aggressive

--- src/coffee/tools.coffee
+++ src/coffee/tools.coffee
@@ -40,25 +40,21 @@
     $(document).bind('keydown', (e) =>
       if e[@options.keyName]
         @_start_drag()
-        return false
     )

     $(document).bind('keyup', (e) =>
       if not e[@options.keyName]
         @_stop_drag()
-        return false
     )

     @plotview.main_can_wrapper.bind('mousedown', (e) =>
       if @button_activated
         @_start_drag()
-        return false
     )
     @plotview.main_can_wrapper.bind('mouseup', (e) =>
       if @button_activated
         @_stop_drag()
-        return false
     )
     @pan_button = $("<button> #{@options.buttonText} </button>")
     @plotview.$el.find('.button_bar').append(@pan_button)
@@ -120,8 +116,6 @@

 class PanToolView extends ToolView
-
-
   eventGeneratorClass : TwoPointEventGenerator
   evgen_options : {keyName:"shiftKey", buttonText:"Pan"}
   tool_events : {
@@ -134,11 +128,9 @@

   _set_base_point : (e) ->
     [@x, @y] = @mouse_coords(e, e.originalEvent.layerX, e.originalEvent.layerY)
-    xmappers = (@model.resolve_ref(x) for x in @mget('xmappers'))
-    ymappers = (@model.resolve_ref(x) for x in @mget('ymappers'))
+    return null

   _drag_mapper : (mapper, diff) ->
-    console.log(diff)
     screen_range = mapper.get_ref('screen_range')
     data_range = mapper.get_ref('data_range')
     screenlow = screen_range.get('start') - diff


refactored replaceWith to wrap/unwrap for better compatibility

--- jquery-badyl.coffee
+++ jquery-badyl.coffee
@@ -1,11 +1,11 @@
 ###
 @name jquery-badyl
 @description Meet Badyl – bootstrap affix-like wheel reinvent.
-@version 1.7.58
+@version 1.8.0
 @author Se7enSky studio <info@se7ensky.com>
 ###

-###! jquery-badyl 1.7.58 http://github.com/Se7enSky/jquery-badyl###
+###! jquery-badyl 1.8.0 http://github.com/Se7enSky/jquery-badyl###

 plugin = ($) ->

@@ -50,6 +50,7 @@

 		badylize: ->
 			return if @badylized
+			@$originalElement = @$el
 			@containerInnerWidth = @measureInnerWidth @$originalParent
 			@originalHeight = @$el.height()

@@ -63,17 +64,19 @@
 				@$refEl.css height: "#{@badylInnerHeight}px"
 				@badylHeight = @$refEl.height() + @config.offsetTop + @config.offsetBottom

-			@$el.replaceWith @$badylContainer = $("""
""")
+			@$el.wrap $("""
""")
 				.css
 					position: 'relative'
 					height: "#{@badylHeight}px"
 					margin: "-#{@config.offsetTop}px 0 -#{@config.offsetBottom}px"
-				.append @$badylInner = $("""
""")
-					.css
-						width: "#{@containerInnerWidth}px"
-						height: "#{@badylInnerHeight}px"
-						padding: "#{@config.offsetTop}px 0 #{@config.offsetBottom}px"
-					.append @$originalElement = @$el.clone()
+			@$el.wrap $("""
""")
+				.css
+					width: "#{@containerInnerWidth}px"
+					height: "#{@badylInnerHeight}px"
+					padding: "#{@config.offsetTop}px 0 #{@config.offsetBottom}px"
+
+			@$badylContainer = @$originalParent.find ".badyl__container"
+			@$badylInner = @$originalParent.find ".badyl__inner"

 			@$originalElement.data "badyl", @
 			@$badylContainer.data "badyl", @
@@ -127,7 +130,8 @@
 			return unless @badylized
 			clearTimeout @smartResizeTimeout if @smartResizeTimeout
 			@unbindEvents()
-			@$badylContainer.replaceWith @$el = @$originalElement
+			@$originalElement.unwrap().unwrap()
+			@$el = @$originalElement
 			@$el.data "badyl", @
 			@badylized = no
 			@state = null


Remove erroneous spaces

Remove erroneous spaces

--- app/assets/javascripts/data-tables-init.coffee
+++ app/assets/javascripts/data-tables-init.coffee
@@ -1,7 +1,7 @@
 $(document).on "page:change", ->
   $(".data-table").each ->
     table = $(@)
-
+
     return if $.fn.dataTable.isDataTable(table)

     fnFooterCallback = (row, data, start, end, display) ->
@@ -37,4 +37,4 @@
     if table.hasClass("no-paging")
       options["paging"] = false

-    table.dataTable(options)+    table.dataTable(options)


select nodes/paths on click and show info on them.

--- app/assets/javascripts/plugins/graph.js.coffee
+++ app/assets/javascripts/plugins/graph.js.coffee
@@ -75,13 +75,29 @@

   $("g.node").on "click", (e) ->
     e.preventDefault()
+    node_data = d3.select(this).data()[0]
     if window.selected_node != this
       $(window.selected_node).find("circle").css("stroke", '')
       $(window.selected_node).find("circle").css("fill", '')
     window.selected_node = this
     $(this).find("circle").css("stroke", "#f00")
     $(this).find("circle").css("fill", "#f00")
-    $("div#d3_context").html("Node: #{$(this).data('label')}")
+    $("div#d3_context").html(
+      "
"+
+      "
Node: #{node_data.info.name}
"+
+      "
IRI: #{node_data.info.iri}
"+
+      "
")
+
+  $("g > path").on "click", (e) ->
+    e.preventDefault()
+    path_data = d3.select(this).data()[0]
+    console.log(path_data)
+    $("div#d3_context").html(
+      "
"+
+      "
Mapping: "+
+      "#{path_data.source.info.name} --> "+
+      "#{path_data.target.info.name}
"+
+      "
")

   node.append("circle").
     attr("r", (d) ->


daily

daily

--- lib/cli/generators/fsharp.coffee
+++ lib/cli/generators/fsharp.coffee
@@ -47,33 +47,74 @@
   run: (flags...) ->

     sb = []
-    ex = []
+    ext = {}
     sys = {}
+    s1 = ext['Entity'] = []
+    s2 = ext['Matcher'] = []
+    s3 = ext['World'] = []

     sb.push "namespace #{config.namespace}"
-    sb.push ""
     sb.push "(**"
     sb.push " * Entitas Generated Components for #{config.namespace}"
     sb.push " *"
     sb.push " * do not edit this file"
     sb.push " *)"
+    sb.push "[<AutoOpen>]"
+    sb.push "module ComponentExtensions ="
     sb.push ""
-    sb.push "open Entitas"
-    sb.push "open System"
-    sb.push "open System.Collections.Generic"
-
-    ex.push "module #{config.namespace}Extensions"
-    ex.push ""
-    ex.push "(**"
-    ex.push " * Entitas Generated Extensions for #{config.namespace}"
-    ex.push " *"
-    ex.push " * do not edit this file"
-    ex.push " *)"
-    ex.push ""
-    ex.push "open Entitas"
-    ex.push "open #{config.namespace}"
-    ex.push "open System"
-    ex.push "open System.Collections.Generic"
+    sb.push "    open Entitas"
+    sb.push "    open System"
+    sb.push "    open System.Collections.Generic"
+    sb.push ""
+
+    s1.push "namespace #{config.namespace}"
+    s1.push "(**"
+    s1.push " * Entitas Generated Entity Extensions for #{config.namespace}"
+    s1.push " *"
+    s1.push " * do not edit this file"
+    s1.push " *)"
+    s1.push "[<AutoOpen>]"
+    s1.push "module EntityExtensions ="
+    s1.push ""
+    s1.push "    open Entitas"
+    s1.push "    open System"
+    s1.push "    open System.Collections.Generic"
+    s1.push ""
+    s1.push "    let isNull x = match x with null -> true | _ -> false"
+    s1.push "    let notNull x = match x with null -> false | _ -> true"
+    s1.push ""
+
+    s2.push "namespace #{config.namespace}"
+    s2.push "(**"
+    s2.push " * Entitas Generated Matcher Extensions for #{config.namespace}"
+    s2.push " *"
+    s2.push " * do not edit this file"
+    s2.push " *)"
+    s2.push "[<AutoOpen>]"
+    s2.push "module MatcherExtensions ="
+    s2.push ""
+    s2.push "    open Entitas"
+    s2.push "    open System"
+    s2.push "    open System.Collections.Generic"
+    s2.push ""
+
+    s3.push "namespace #{config.namespace}"
+    s3.push "(**"
+    s3.push " * Entitas Generated World Extensions for #{config.namespace}"
+    s3.push " *"
+    s3.push " * do not edit this file"
+    s3.push " *)"
+    s3.push "[<AutoOpen>]"
+    s3.push "module WorldExtensions ="
+    s3.push ""
+    s3.push "    open Entitas"
+    s3.push "    open System"
+    s3.push "    open System.Collections.Generic"
+    s3.push ""
+    s3.push "    let isNull x = match x with null -> true | _ -> false"
+    s3.push "    let notNull x = match x with null -> false | _ -> true"
+    s3.push ""
+

     ###
      * Components Type Definitions
@@ -81,16 +122,16 @@
     for Name, properties of config.components
       name = Name[0].toLowerCase()+Name[1...]
       sb.push ""
-      sb.push "[<AllowNullLiteral>]"
-      sb.push "type #{Name}Component() ="
-      sb.push "    inherit Component()"
+      sb.push "    [<AllowNullLiteral>]"
+      sb.push "    type #{Name}Component() ="
+      sb.push "        inherit Component()"
       if properties is false
-        sb.push "    member val active = false with get, set"
+        sb.push "        member val active = false with get, set"
       else
         for p in properties
           name = p.split(':')[0]
           value = getDefault(p.split(':')[1])
-          sb.push "    member val #{name} = #{value} with get, set"
+          sb.push "        member val #{name} = #{value} with get, set"

     ###
      * Systems Type Definitions
@@ -130,161 +171,166 @@
     sy.push ""

     ###
-     * Entity Extensions
-    ###
-    ex.push ""
-    ###
      * Components List
     ###
-    ex.push "let isNull x = match x with null -> true | _ -> false"
-    ex.push "let notNull x = match x with null -> false | _ -> true"
-    ex.push ""
-    ex.push "type Component with "
+    sb.push ""
+    sb.push "    type Component with "
     kc = 0
     for Name, properties of config.components
       name = Name[0].toLowerCase()+Name[1...]
-      ex.push "    static member #{Name} with get() = #{++kc}"
-    ex.push "    static member TotalComponents  with get() = #{++kc}"
-    ex.push ""
-    ex.push "type ComponentId = "
-    kc = 0
-    for Name, properties of config.components
-      name = Name[0].toLowerCase()+Name[1...]
-      ex.push "  | #{Name} = #{++kc}"
-    ex.push "  | TotalComponents = #{++kc}"
-    ex.push ""
+      sb.push "        static member #{Name} with get() = #{++kc}"
+    sb.push "        static member TotalComponents  with get() = #{++kc}"
+    sb.push ""

     for Name, properties of config.components
       name = Name[0].toLowerCase()+Name[1...];
       switch properties
         when false
-          ex.push "type Entity with"
-          ex.push ""
-          ex.push "    static member #{name}Component= new #{Name}Component()"
-          ex.push ""
-          ex.push "    member this.is#{Name}"
-          ex.push "        with get() ="
-          ex.push "            this.HasComponent(Component.#{Name})"
-          ex.push "        and  set(value) ="
-          ex.push "            if value <> this.is#{Name} then"
-          ex.push "                this.AddComponent(Component.#{Name}, Entity.#{name}Component) |> ignore"
-          ex.push "            else"
-          ex.push "                this.RemoveComponent(Component.#{Name}) |> ignore"
-          ex.push ""
-          ex.push "    member this.Is#{Name}(value) ="
-          ex.push "        this.is#{Name} <- value"
-          ex.push "        this"
-          ex.push ""
-          ex.push "type Matcher with "
-          ex.push "    static member #{Name} with get() = Matcher.AllOf(Component.#{Name}) "
-          ex.push ""
+          s1.push "    type Entity with"
+          s1.push ""
+          s1.push "        static member #{name}Component= new #{Name}Component()"
+          s1.push ""
+          s1.push "        member this.is#{Name}"
+          s1.push "            with get() ="
+          s1.push "                this.HasComponent(Component.#{Name})"
+          s1.push "            and  set(value) ="
+          s1.push "                if value <> this.is#{Name} then"
+          s1.push "                    this.AddComponent(Component.#{Name}, Entity.#{name}Component) |> ignore"
+          s1.push "                else"
+          s1.push "                    this.RemoveComponent(Component.#{Name}) |> ignore"
+          s1.push ""
+          s1.push "        member this.Is#{Name}(value) ="
+          s1.push "            this.is#{Name} <- value"
+          s1.push "            this"
+          s1.push ""
+          s2.push "    type Matcher with "
+          s2.push "        static member #{Name}"
+          s2.push "            with get() = Matcher.AllOf(Component.#{Name}) "
+          s2.push ""

         else
-          ex.push "type Entity with"
-          ex.push "    member this.#{name}"
-          ex.push "        with get() = this.GetComponent(Component.#{Name}):?>#{Name}Component"
-          ex.push ""
-          ex.push "    member this.has#{Name}"
-          ex.push "        with get() = this.HasComponent(Component.#{Name})"
-          ex.push ""
-          ex.push "    member this._#{name}ComponentPool"
-          ex.push "         with get() = new Stack<#{Name}Component>()"
-          ex.push ""
-          ex.push "    member this.Clear#{Name}ComponentPool() ="
-          ex.push "        this._#{name}ComponentPool.Clear()"
-          ex.push ""
-          ex.push "    member this.Add#{Name}(#{params(properties)}) ="
-          ex.push "        let mutable c = "
-          ex.push "          match this._#{name}ComponentPool.Count with"
-          ex.push "          | 0 -> new #{Name}Component()"
-          ex.push "          | _ -> this._#{name}ComponentPool.Pop()"
+          s1.push "    type Entity with"
+          s1.push "        member this.#{name}"
+          s1.push "            with get() = this.GetComponent(Component.#{Name}):?>#{Name}Component"
+          s1.push ""
+          s1.push "        member this.has#{Name}"
+          s1.push "            with get() = this.HasComponent(Component.#{Name})"
+          s1.push ""
+          s1.push "        member this._#{name}ComponentPool"
+          s1.push "             with get() = new Stack<#{Name}Component>()"
+          s1.push ""
+          s1.push "        member this.Clear#{Name}ComponentPool() ="
+          s1.push "            this._#{name}ComponentPool.Clear()"
+          s1.push ""
+          s1.push "        member this.Add#{Name}(#{params(properties)}) ="
+          s1.push "            let mutable c = "
+          s1.push "              match this._#{name}ComponentPool.Count with"
+          s1.push "              | 0 -> new #{Name}Component()"
+          s1.push "              | _ -> this._#{name}ComponentPool.Pop()"
           for p in properties
-            ex.push "        c.#{p.split(':')[0]} <- #{p.split(':')[0]};"
-          ex.push "        this.AddComponent(Component.#{Name}, c)"
-          ex.push ""
-          ex.push "    member this.Replace#{Name}(#{params(properties)}) ="
-          ex.push "        let previousComponent = if this.has#{Name} then this.#{name} else null"
-          ex.push "        let mutable c = "
-          ex.push "          match this._#{name}ComponentPool.Count with"
-          ex.push "          | 0 -> new #{Name}Component()"
-          ex.push "          | _ -> this._#{name}ComponentPool.Pop()"
+            s1.push "            c.#{p.split(':')[0]} <- #{p.split(':')[0]};"
+          s1.push "            this.AddComponent(Component.#{Name}, c)"
+          s1.push ""
+          s1.push "        member this.Replace#{Name}(#{params(properties)}) ="
+          s1.push "            let previousComponent = if this.has#{Name} then this.#{name} else null"
+          s1.push "            let mutable c = "
+          s1.push "              match this._#{name}ComponentPool.Count with"
+          s1.push "              | 0 -> new #{Name}Component()"
+          s1.push "              | _ -> this._#{name}ComponentPool.Pop()"
           for p in properties
-            ex.push "        c.#{p.split(':')[0]} <- #{p.split(':')[0]};"
-          ex.push "        this.ReplaceComponent(Component.#{Name}, c) |> ignore"
-          ex.push "        if not(isNull(previousComponent)) then"
-          ex.push "            this._#{name}ComponentPool.Push(previousComponent)"
-          ex.push "        this"
-          ex.push ""
-          ex.push "    member this.Remove#{Name}() ="
-          ex.push "        let c = this.#{name}"
-          ex.push "        this.RemoveComponent(Component.#{Name}) |> ignore"
-          ex.push "        this._#{name}ComponentPool.Push(c)"
-          ex.push ""
-          ex.push "type Matcher with "
-          ex.push "    static member #{Name} with get() = Matcher.AllOf(Component.#{Name}) "
-          ex.push ""
+            s1.push "            c.#{p.split(':')[0]} <- #{p.split(':')[0]};"
+          s1.push "            this.ReplaceComponent(Component.#{Name}, c) |> ignore"
+          s1.push "            if not(isNull(previousComponent)) then"
+          s1.push "                this._#{name}ComponentPool.Push(previousComponent)"
+          s1.push "            this"
+          s1.push ""
+          s1.push "        member this.Remove#{Name}() ="
+          s1.push "            let c = this.#{name}"
+          s1.push "            this.RemoveComponent(Component.#{Name}) |> ignore"
+          s1.push "            this._#{name}ComponentPool.Push(c)"
+          s1.push ""
+          s2.push "    type Matcher with "
+          s2.push "        static member #{Name}"
+          s2.push "            with get() = Matcher.AllOf(Component.#{Name}) "
+          s2.push ""

     ###
      * Pooled Entities
     ###
-    ex.push "type World with"
+    s3.push "    type World with"
     for Name, pooled of config.entities
       if pooled
         name = Name[0].toLowerCase()+Name[1...];
         properties = config.components[Name]
         if config.components[Name] is false
-          ex.push ""
-          ex.push "    member this.#{name}Entity"
-          ex.push "        with get() = this.GetGroup(Matcher.#{Name}).GetSingleEntity()"
-          ex.push ""
-          ex.push "    member this.is#{Name}"
-          ex.push "        with get() ="
-          ex.push "            notNull(this.#{name}Entity)"
-          ex.push "        and  set(value) ="
-          ex.push "            let entity = this.#{name}Entity"
-          ex.push "            if value <> notNull(entity) then"
-          ex.push "                if value then"
-          ex.push "                    this.CreateEntity().is#{Name} <- true"
-          ex.push "                else"
-          ex.push "                    this.DestroyEntity(entity)"
-          ex.push ""
+          s3.push ""
+          s3.push "        member this.#{name}Entity"
+          s3.push "            with get() = this.GetGroup(Matcher.#{Name}).GetSingleEntity()"
+          s3.push ""
+          s3.push "        member this.is#{Name}"
+          s3.push "            with get() ="
+          s3.push "                notNull(this.#{name}Entity)"
+          s3.push "            and  set(value) ="
+          s3.push "                let entity = this.#{name}Entity"
+          s3.push "                if value <> notNull(entity) then"
+          s3.push "                    if value then"
+          s3.push "                        this.CreateEntity().is#{Name} <- true"
+          s3.push "                    else"
+          s3.push "                        this.DestroyEntity(entity)"
+          s3.push ""
         else
-          ex.push ""
-          ex.push "    member this.#{name}Entity"
-          ex.push "        with get() = this.GetGroup(Matcher.#{Name}).GetSingleEntity()"
-          ex.push ""
-          ex.push "    member this.#{name}"
-          ex.push "        with get() = this.#{name}Entity.#{name}"
-          ex.push ""
-          ex.push "    member this.has#{Name}"
-          ex.push "        with get() = notNull(this.#{name}Entity)"
-          ex.push ""
-          ex.push "    member this.Set#{Name}(newValue) ="
-          ex.push "        if this.has#{Name} then"
-          ex.push "            failwith \"Single Entity Exception: #{Name}\""
-          ex.push "        let entity = this.CreateEntity()"
-          ex.push "        entity.Add#{Name}(newValue) |> ignore"
-          ex.push "        entity"
-          ex.push ""
-          ex.push "    member this.Replace#{Name}(newValue) ="
-          ex.push "        let entity = this.#{name}Entity"
-          ex.push "        if isNull(entity) then"
-          ex.push "            entity = this.Set#{Name}(newValue) |> ignore"
-          ex.push "        else"
-          ex.push "            entity.Replace#{Name}(newValue) |> ignore"
-          ex.push "        entity"
-          ex.push ""
-          ex.push "    member this.Remove#{Name}() ="
-          ex.push "        this.DestroyEntity(this.#{name}Entity)"
-          ex.push ""
+          s3.push ""
+          s3.push "        member this.#{name}Entity"
+          s3.push "            with get() = this.GetGroup(Matcher.#{Name}).GetSingleEntity()"
+          s3.push ""
+          s3.push "        member this.#{name}"
+          s3.push "            with get() = this.#{name}Entity.#{name}"
+          s3.push ""
+          s3.push "        member this.has#{Name}"
+          s3.push "            with get() = notNull(this.#{name}Entity)"
+          s3.push ""
+          s3.push "        member this.Set#{Name}(newValue) ="
+          s3.push "            if this.has#{Name} then"
+          s3.push "                failwith \"Single Entity Exception: #{Name}\""
+          s3.push "            let entity = this.CreateEntity()"
+          s3.push "            entity.Add#{Name}(newValue) |> ignore"
+          s3.push "            entity"
+          s3.push ""
+          s3.push "        member this.Replace#{Name}(newValue) ="
+          s3.push "            let entity = this.#{name}Entity"
+          s3.push "            if isNull(entity) then"
+          s3.push "                entity = this.Set#{Name}(newValue) |> ignore"
+          s3.push "            else"
+          s3.push "                entity.Replace#{Name}(newValue) |> ignore"
+          s3.push "            entity"
+          s3.push ""
+          s3.push "        member this.Remove#{Name}() ="
+          s3.push "            this.DestroyEntity(this.#{name}Entity)"
+          s3.push ""

+    #
+    # ./<Namespace>.fs - Component declarations
+    # ./Systems/*.fs - System Classes
+    # ./Extensions/EntityExtensions.fs
+    # ./Extensions/MatcherExtensions.fs
+    # ./Extensions/WorldExtensions.fs
+    #
     mkdirp.sync path.dirname(path.join(process.cwd(), config.output.fsharp))
     mkdirp.sync path.join(process.cwd(), config.output.fsharp, "Systems")
-
-    fs.writeFileSync(path.join(process.cwd(), config.output.fsharp, "#{config.namespace}.fs"), sb.join('\n'))
-    fs.writeFileSync(path.join(process.cwd(), config.output.fsharp, "#{config.namespace}Extensions.fs"), ex.join('\n'))
-
+    mkdirp.sync path.join(process.cwd(), config.output.fsharp, "Extensions")
+
+    # Components
+    fs.writeFileSync(path.join(process.cwd(), config.output.fsharp,
+      "Extensions/ComponentExtensions.fs"), sb.join('\n'))
+
+    # Extensions
+    for Name, ex of ext
+      fs.writeFileSync(path.join(process.cwd(), config.output.fsharp,
+        "Extensions/#{Name}Extensions.fs"), ex.join('\n'))
+
+    # Systems
     for Name, sy of sys
-      fs.writeFileSync(path.join(process.cwd(), config.output.fsharp, "Systems/#{Name}.fs"), sy.join('\n'))
+      fs.writeFileSync(path.join(process.cwd(), config.output.fsharp,
+        "Systems/#{Name}.fs"), sy.join('\n'))


优化路径输入

优化路径输入

--- lib/project/new-project-info.coffee
+++ lib/project/new-project-info.coffee
@@ -1,4 +1,5 @@
 desc = require '../utils/text-description'
+pathM = require 'path'
 {Directory} = require 'atom'
 {$, TextEditorView, View} = require 'atom-space-pen-views'

@@ -35,23 +36,22 @@
     if @type isnt 'template'
       @parentView.setNextBtn('finish')
     @parentView.disableNext()
-    # @appId.setText 'newPackage'
-    # @appName.setText '新项目'
-    @appPath.setText desc.newProjectDefaultPath
+    @appPath.basePath = desc.newProjectDefaultPath
+    @appPath.setText @appPath.basePath

   openFolder: ->
     atom.pickFolder (paths) =>
-      if paths[0]?
+      if paths?
         console.log paths[0]
-        path = "#{paths[0]}/#{@appId.getText()}".replace(/\\/g,'/')
+        path = pathM.join paths[0],@appId.getText()
         console.log  path
-        @appPath.setText path
+        @appPath.basePath = path
+        @appPath.setText @appPath.basePath

   getElement: ->
     @element

   getProjectInfo: ->
-    console.log @appId
     projectInfo =
       appId : @appId.getText();
       appName : @appName.getText();
@@ -71,20 +71,19 @@
       @parentView.disableNext()

   setPath: ->
-    currPath = @appPath.getText().trim()
-    currPath = currPath.substr(0,currPath.lastIndexOf('/')+1)
-    console.log currPath
-    @appPath.setText currPath+@appId.getText().trim() if currPath isnt ""
+    currPath = @appPath.basePath
+    # console.log currPath
+    @appPath.setText pathM.join currPath,@appId.getText().trim() if currPath isnt ""
     @checkInput()

   checkPath: ->
     path = @appPath.getText().trim()
+    @appPath.basePath = path if @appPath.hasFocus()
     if path isnt ""
-      console.log path
       dir = new Directory(path);
       dir.exists()
         .then (isExists) =>
-          console.log isExists,@,dir.getRealPathSync()
+          # console.log isExists,@,dir.getRealPathSync()
           unless isExists
             @checkInput()
             @errorMsg.addClass('hide')


winctrl: do not register/unregister Mousetrap bindings

--- lib/core/windowcontroller.coffee
+++ lib/core/windowcontroller.coffee
@@ -1,7 +1,5 @@
 $                  = require 'jquery'
 KD                 = require './kd'
-KDKeyboardListener = require './keyboard/listener'
-KDKeyboardMap      = require './keyboard/map'
 KDController       = require './controller'

 ###
@@ -201,26 +199,12 @@
     return if Object.keys(combos).length > 0 then combos else no

-  registerKeyCombos:(view)->
-    combos = @viewHasKeyCombos view
-    if combos?
-      @comboMap = new KDKeyboardMap { combos }
-      KDKeyboardListener.current().addComboMap @comboMap
-
-
-  unregisterKeyCombos:->
-    KDKeyboardListener.current().removeComboMap @comboMap
-    @keyView.unsetClass "mousetrap" if @keyView
-
-
   setKeyView:(keyView)->
     keyView?.activateKeyView?()
     return if keyView is @keyView

-    @unregisterKeyCombos()
     @oldKeyView = @keyView
     @keyView    = keyView
-    @registerKeyCombos keyView

     keyView?.activateKeyView?()
     @emit 'WindowChangeKeyView', keyView


moving 'throw' to a slightly higher level of precedence

--- grammar.coffee
+++ grammar.coffee
@@ -30,8 +30,8 @@
   ["left",      '.']
   ["right",     'INDENT']
   ["left",      'OUTDENT']
-  ["right",     'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY']
-  ["right",     'THROW', 'FOR', 'NEW', 'SUPER']
+  ["right",     'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW']
+  ["right",     'FOR', 'NEW', 'SUPER']
   ["left",      'EXTENDS']
   ["right",     'ASSIGN', 'RETURN']
   ["right",     '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']


Fix seo bug

Fix seo bug

--- both/_config/seo.coffee
+++ both/_config/seo.coffee
@@ -1,9 +1,7 @@
 Meteor.startup ->
   if Meteor.isClient
     SEO.config
-      title: @Config.name
+      title: Config.name
       meta:
-        description:  @Config.subtitle
-
-      # og:
-      #   image: "http://manuel-schoebel.com/images/authors/manuel-schoebel.jpg"+      	title: Config.name
+        description:  Config.subtitle


editor: test a horrible hack

editor: test a horrible hack

--- salvus/page/editor.coffee
+++ salvus/page/editor.coffee
@@ -1616,6 +1616,7 @@
             elt.data('font-size', size)

     change_font_size: (cm, delta) =>
+        #console.log("change_font_size #{cm.name}, #{delta}")
         scroll_before = cm.getScrollInfo()

         elt = $(cm.getWrapperElement())
@@ -1922,6 +1923,9 @@
             cm_wrapper.css
                 height : height
                 width  : width
+            # additional hack that might help avoid corruption... (I hate doing this)
+            @change_font_size(cm,+1)
+            @change_font_size(cm,-1)

         # This is another hack that specifically hopefully addresses an
         # issue where when I open a tab often the scrollbar is completely


Do not include local libraries as this is automatically handled

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -276,13 +276,11 @@
     styles = filterStyles(@filesSrc).map (file) ->
       file.replace extractRE, '$1.css'

-    # Add vendor files to the *beginning* as external libraries take
-    # precedence. Remote libraries first, then local libraries
-    scripts.unshift local for local in vendorFiles.scripts.local
+    # Add remote vendor files to the *beginning* as external libraries take
+    # precedence
     scripts.unshift remote for remote in vendorFiles.scripts.remote

     # Do the same for styles
-    styles.unshift local for local in vendorFiles.styles.local
     styles.unshift remote for remote in vendorFiles.styles.remote

     # Use non-EJS syntax to insert `yield`


chore: setup workflow for build task

chore: setup workflow for build task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -54,14 +54,26 @@
         ]
         updateConfigs: ['pkg']
         commitFiles: ['-a']
+        pushTo: 'origin'

-  grunt.registerTask 'build', [
+  grunt.registerTask 'dev', [
     'coffeelint'
     'coffee'
     'jasmine'
   ]

+  # Constructs the code, runs tests and if everyting is OK, creates a minified
+  # version ready for production. This task is intended to be run manually.
+  grunt.registerTask 'build', 'Bumps version and builds JS.', (version_type) ->
+    version_type = 'patch' unless version_type in ['patch', 'minor', 'major']
+    grunt.task.run [
+      "bump-only:#{version_type}"
+      'dev'
+      'changelog'
+      'bump-commit'
+    ]
+
   grunt.registerTask 'default', [
     'watch'
   ]


Fixed nugget pack

Fixed nugget pack

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -11,7 +11,7 @@
           configuration: 'Debug'
           company: 'Spicy Taco'
           product: 'Spicy Taco AutoGrid'
-          copyright: 'Copyright 3002 © Spicy Taco'
+          copyright: 'Copyright 2014 © Spicy Taco'
           trademark: 'Spicy Taco'
           version: '0.9.0'
           fileVersion: '0.9.0'
@@ -35,7 +35,7 @@
         src: ['src/**/bin/Debug/*.Tests.dll']
     nugetpack:
       dist:
-        src: 'src/AutoGrid/AutoGrid.nuspec'
+        src: 'src/AutoGrid/AutoGrid.csproj'
         dest: '.'

   grunt.task.registerTask 'banner', () ->


Gruntfile: Run copy:examples task on CI task.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -244,6 +244,7 @@
       'deps'
       'karma:headless'
       'coveralls'
+      'copy:examples'
       'jsdoc'
       'gh-pages'
     ]


Compile index.pug.

Compile index.pug.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -47,17 +47,15 @@
     pug:
       options:
         pretty: true
-      default:
-        expand: true
+      index:
+        src: 'index.pug'
+        dest: 'index.html'
+      partials:
+        expand: true
+        cwd: 'src/'
         ext: '.html'
-        cwd: 'src/'
-        src: ['**.pug', '!include/**']
+        src: ['*.pug', '*/**.pug', '!**include/*.pug']
         dest: 'html'
-        # The default extDot chops off more than the trailing .pug, e.g.:
-        #   src/collections.view.pug -> html/collections.html
-        # We want to preserve the filename up to .pug, e.g.:
-        #   src/collections.view.pug -> html/collections.view.html
-        extDot: 'last'

     markdown:
       default:


also distribute images

also distribute images

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -64,7 +64,8 @@
                 files: [{
                     expand: true
                     src: [
-                        'slides/**'
+                        'slides/**',
+                        'image/**',
                         'bower_components/**'
                         'js/**'
                     ]


Make grunt watch less angry

Make grunt watch less angry

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -63,7 +63,7 @@
           livereload: "<%= connect.options.livereload %>"

         files: [
-          "<%= yeoman.app %>/{,**/}*.html"
+          "<%= yeoman.app %>/{,*/}{,*/}{,*/}*.html"
           ".tmp/styles/{,*/}*.css"
           ".tmp/scripts/{,*/}*.js"
           "<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}"


fix: remove unnecessary task

fix: remove unnecessary task

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -353,7 +353,6 @@
   grunt.registerTask "sync", "Build site + rsync static files to remote server", [
     "build"
     "shell:sync"
-    "copy"
   ]

   grunt.registerTask "s3", "Sync image assets with `s3cmd`", [


Feature: Wrong path for vows tests

Feature: Wrong path for vows tests

Signed-off-by: Christian Roth <396398d2f664a436582eed8a8cfb08dd7671c8d6@port17.de>

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -32,7 +32,7 @@
       server:
         options:
           reporter: 'spec'
-        src:        ['.test/js/*.js']
+        src:        ['.test/*.js']

     watch:
       coffee:


Boyscout.

Boyscout.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -161,7 +161,7 @@
     grunt.log.writeln "Renaming file \"#{source_file_path}\" to \"#{new_source_file_path}\""
     fs.renameSync(source_file_path, new_source_file_path );

-    grunt.log.writeln "Replacing placeholder with hash value in file \"#{destination_file_path}."
+    grunt.log.writeln "Replacing placeholder with hash value in file \"#{destination_file_path}\"."
     content = grunt.file.read destination_file_path
     content_with_hash = content.replace /&\*HASH_PLACE_HOLDER\*&/, source_file_hash
     grunt.file.write destination_file_path, content_with_hash


Removed copy from grunt

Removed copy from grunt

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -13,7 +13,6 @@
   # CoffeeScript and remove files.
   Grunt.loadNpmTasks('grunt-contrib-clean')
   Grunt.loadNpmTasks('grunt-contrib-coffee')
-  Grunt.loadNpmTasks('grunt-contrib-copy')

   # Configuration for CoffeeScript compilation
   coffeeConfiguration =


bundle exec sass for CI

bundle exec sass for CI

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -55,6 +55,8 @@
         dest: 'build/factlink_loader_bookmarklet.js'
     sass:
       build:
+        options:
+          bundleExec: true
         files:
           'build/css/basic_without_embeds.css': 'app/css/basic.scss'
           'build/css/framed_controls_without_embeds.css': 'app/css/framed_controls.scss'


Revert "add curl option for uploading to nexus"

This reverts commit c11f0c6c41b6d7502407a6322cfd252e4838f2f0.

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -268,7 +268,6 @@
       options:
         url: 'http://alm-build.f4tech.com:8080'
         repository: 'thirdparty'
-        curl: true
       deps:
         options:
           fetch: (->


Updated Grunt Tasks

Updated Grunt Tasks

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -29,17 +29,17 @@
 					'src/slider.js': 'slider.coffee'

 		uglify:
-            options:
-                mangle: false
-            my_target:
-                files:
-                    "src/slider.min.js": ['src/slider.js']
+			options:
+				mangle: false
+			my_target:
+				files:
+					"src/slider.min.js": ['src/slider.js']

 		watch:
-            options:
-                livereload: true
-            coffee:
-                files: '*.coffee'
-                tasks: ['coffeelint', 'coffee', 'uglify']
+			options:
+				livereload: true
+			coffee:
+				files: '*.coffee'
+				tasks: ['coffeelint', 'coffee', 'uglify']

-	grunt.registerTask 'default', 'watch'
+	grunt.registerTask 'default', ['coffeelint', 'coffee', 'uglify', 'watch']


Allow for testing specific files

Allow for testing specific files

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -78,9 +78,17 @@
     if 'build' in args then tasks.push 'build:dev'
     tasks.push 'mochaTest'

+    allowedReporters = ['nyan', 'spec', 'dot', 'list', 'json', 'markdown', 'min']
+    files = []
     for arg in args
       if arg is 'build' then continue
-      grunt.config.set('mochaTest.test.options.reporter', arg)
+      if arg in allowedReporters
+        grunt.config.set('mochaTest.test.options.reporter', arg)
+      else if grunt.file.exists("test/#{arg}.coffee")
+        files.push "test/#{arg}.coffee"
+
+    if files.length > 0
+      grunt.config.set('mochaTest.test.src', files)

     grunt.task.run tasks
   )


Configure OAuth endpoints, provider and client_secret

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -87,11 +87,29 @@
           './manifest.webapp': './manifest.dist.webapp'
         options:
           replacements: [
+            pattern: /\$NOFLO_OAUTH_PROVIDER/ig
+            replacement: process.env.NOFLO_OAUTH_PROVIDER or 'https://passport.thegrid.io'
+          ,
+            pattern: /\$NOFLO_OAUTH_GATE/ig
+            replacement: process.env.NOFLO_OAUTH_GATE or 'https://noflo-gate.herokuapp.com/'
+          ,
             pattern: /\$NOFLO_OAUTH_CLIENT_ID/ig
             replacement: process.env.NOFLO_OAUTH_CLIENT_ID or '9d963a3d-8b6f-42fe-bb36-6fccecd039af'
           ,
-            pattern: /\$NOFLO_OAUTH_GATE/ig
-            replacement: process.env.NOFLO_OAUTH_GATE or 'https://noflo-gate.herokuapp.com/'
+            pattern: /\$NOFLO_OAUTH_CLIENT_SECRET/ig
+            replacement: process.env.NOFLO_OAUTH_CLIENT_SECRET or ''
+          ,
+            pattern: /\$NOFLO_OAUTH_ENDPOINT_AUTHORIZE/ig
+            replacement: process.env.NOFLO_OAUTH_ENDPOINT_AUTHORIZE or '/login/authorize'
+          ,
+            pattern: /\$NOFLO_OAUTH_ENDPOINT_TOKEN/ig
+            replacement: process.env.NOFLO_OAUTH_ENDPOINT_TOKEN or '/token'
+          ,
+            pattern: /\$NOFLO_OAUTH_ENDPOINT_CODE/ig
+            replacement: process.env.NOFLO_OAUTH_ENDPOINT_CODE or '/authenticate'
+          ,
+            pattern: /\$NOFLO_OAUTH_ENDPOINT_USER/ig
+            replacement: process.env.NOFLO_OAUTH_ENDPOINT_USER or '/user'
           ,
             pattern: /\$NOFLO_REGISTRY_SERVICE/ig
             replacement: process.env.NOFLO_REGISTRY_SERVICE or 'https://api.flowhub.io'


More aggressive cache config

More aggressive cache config

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -122,14 +122,14 @@
         options:
           basePath: "<%= core.dist %>/"
           # cache: ["js/app.js", "css/app.css"]
-          network: ["//*"]
+          network: ["*"]
           preferOnline: true
           verbose: true
           timestamp: true
           hash: true
           master: ["index.html"]

-        src: ["css/*.js", "css/*.css", "css/*.woff"]
+        src: ["**/*.html", "**/css/*.js", "**/css/*.css", "**/css/*.woff"]
         dest: "<%= core.dist %>/manifest.appcache"

     shell:


:lipstick: Make biscotto quiet

:lipstick: Make biscotto quiet

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -148,7 +148,7 @@
   grunt.registerTask 'biscotto', 'Generates the documentation', ->
     done = @async()
     # run('biscotto src')
-    run('/Users/cedric/Development/coffeescript/biscotto/bin/biscotto --internal --private -v src')
+    run('/Users/cedric/Development/coffeescript/biscotto/bin/biscotto --internal --private -q src')
     .then ->
       done()
     .fail ->


Remove redundant code

Remove redundant code

--- Gruntfile.coffee
+++ Gruntfile.coffee
@@ -65,12 +65,6 @@
         src: ["**", "!**/styl/**", "!**/classes/**"]
         dest: "build/client/"

-      server:
-        expand: true
-        cwd: "/"
-        src: ["app.js"]
-        dest: "build/server/"
-
     uglify:
       options:
         banner: "/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today(\"yyyy-mm-dd\") %>\n" + "* <%= pkg.homepage %>/\n" + "* Copyright (c) <%= grunt.template.today(\"yyyy\") %> <%= pkg.author %>; Licensed <%= pkg.license %> */\n"
@@ -125,7 +119,7 @@
   grunt.loadNpmTasks "grunt-nodemon"
   grunt.loadNpmTasks "grunt-concurrent"

-  grunt.registerTask "server", ["jshint:server", "copy:server"]
+  grunt.registerTask "server", ["jshint:server"]
   grunt.registerTask "client", ["jshint:client", "copy:client", "concat", "stylus"]
   grunt.registerTask "client-prod", ["client", "uglify"]
   grunt.registerTask "default", ["server", "client", "concurrent", "watch"]


Ensure lithium returns success code instead of null on success

--- code/li.coffee
+++ code/li.coffee
@@ -72,8 +72,9 @@
 deploy = (args) ->
   Linode.get args[2], (instance) ->
     callback = (code) ->
-        console.log "Exit code: #{code}"
-        process.exit code
+      if code is null then code = 0
+      console.log "Exit code: #{code}"
+      process.exit code
     instance.run_hooks callback

 # Displays a list of instances


able to close reveal with back key

able to close reveal with back key

--- views/js/myutil.coffee
+++ views/js/myutil.coffee
@@ -2,6 +2,9 @@
   _ = require("underscore")
   $ = require("jquery")
   Backbone = require("backbone")
+
+  String.prototype.endsWith = (x)->
+    @indexOf(x,@length-x.length) != -1

   # 履歴付きBackbone.Router
   class HistoryRouter extends Backbone.Router
@@ -220,18 +223,39 @@
     # TODO: 将来的にZurb Foundationがバージョンアップしたらその方法が用意されるかもしれない
     reveal_view: (target,view,confirm_when_edited) ->
       obj = $(target)
+      window.foundation_is_revealing = true
       obj.one("closed", ->
         $(".reveal-modal-bg").off('click')
         view.remove()
         obj.empty()
         obj.removeClass("form-changed")
+        if window.foundation_is_revealing
+          # do nothing since other window is revealing
+        else if window.location.hash.endsWith("@revealed")
+          # closed with $.foundation("reveal","close")
+          window.onhashchange = ->
+            window.onhashchange = null
+            Backbone.history.start({silent:true})
+          window.history.back()
+        else
+          # closed with browser's back key or window.history.back()
+          window.onhashchange = null
+          Backbone.history.start({silent:true})
       )
-      #
       obj.one("opened", ->
+        window.foundation_is_revealing = false
+        Backbone.history.stop()
+        if not window.location.hash.endsWith("@revealed")
+          window.location.hash = window.location.hash + "@revealed"
+        window.onhashchange = ->
+          if not window.location.hash.endsWith("@revealed")
+            if obj.hasClass("form-changed") and not confirm("本当に変更を破棄して閉じますか？")
+              window.history.forward()
+              return
+            obj.foundation("reveal","close")
+
         $(".reveal-modal-bg").on('click',->
-          if obj.hasClass("form-changed") and not confirm("本当に変更を破棄して閉じますか？")
-            return
-          obj.foundation("reveal","close")
+          window.history.back()
         )
       )
       if confirm_when_edited


Make the REPL *CLI* use the global context so as to be consistent with the `node` REPL CLI.

Make the REPL *CLI* use the global context so as to (a) be consistent
with the `node` REPL CLI and, therefore, (b) make packages that modify
native prototypes (such as 'colors' and 'sugar') work as expected.

Note that, by contrast, programmatic use (`require 'repl'`) will
continue to default to a NON-global context - again, consistent with
node's behavior.

--- command.coffee
+++ command.coffee
@@ -25,7 +25,7 @@

 hidden = (file) -> /^\.|~$/.test file

-# The help banner that is printed when `coffee` is called without arguments.
+# The help banner that is printed in conjunction with `-h`/`--help`.
 BANNER = '''
   Usage: coffee [options] path/to/script.coffee -- [args]

@@ -65,15 +65,19 @@
 # `--` will be passed verbatim to your script as arguments in `process.argv`
 exports.run = ->
   parseOptions()
-  return forkNode()                      if opts.nodejs
-  return usage()                         if opts.help
-  return version()                       if opts.version
-  return require('./repl').start()       if opts.interactive
+  # Make the REPL *CLI* use the global context so as to (a) be consistent with the
+  # `node` REPL CLI and, therefore, (b) make packages that modify native prototypes
+  # (such as 'colors' and 'sugar') work as expected.
+  replCliOpts = useGlobal: yes
+  return forkNode()                             if opts.nodejs
+  return usage()                                if opts.help
+  return version()                              if opts.version
+  return require('./repl').start(replCliOpts)   if opts.interactive
   if opts.watch and not fs.watch
     return printWarn "The --watch feature depends on Node v0.6.0+. You are running #{process.version}."
-  return compileStdio()                  if opts.stdio
-  return compileScript null, sources[0]  if opts.eval
-  return require('./repl').start()       unless sources.length
+  return compileStdio()                         if opts.stdio
+  return compileScript null, sources[0]         if opts.eval
+  return require('./repl').start(replCliOpts)   unless sources.length
   literals = if opts.run then sources.splice 1 else []
   process.argv = process.argv[0..1].concat literals
   process.argv[0] = 'coffee'