bugfix backInfo length

bugfix backInfo length


Hydrator: change specs to use new complex nodes hydration logic.

--- src/OVirtResponseHydrator.coffee
+++ src/OVirtResponseHydrator.coffee
@@ -53,6 +53,15 @@
 # ### Hydrate top level element attributes
 #
 # - Save attributes in corresponding property if existed.
+#
+# ### General tasks
+#
+# - If current node is an owner of collections, resource links or actions
+#   (except the case when the node is a resource)then an API node instance
+#   should be created and set as a current target.
+# - If current node is a root one then current target should be a hydrator
+#   instance target.
+# - We should replace node value with current target (if exists).
 #
 # ### Hydrate collections
 #
@@ -87,14 +96,15 @@
 #     + Loop over related special objects adding them to corresponding
 #       collections.
 #     + Clean the applied `specialObjects` namespace.
-# + Export collections (right after collections setup)
+# - Hydrate collections owner (right after collections setup)
 #     + If `link` is array then remove undefined values from it.
 #     + Delete link if it is an epty array or is undefined.
 #     + Remove special objects element from node children.
 #     + Use collection `rel` attribute as a collection name.
 #     + Detect whether current `xpath` points to root node.
 #     + If current node is a root one export collections to target node.
-#     + Otherwise populate collections to node with collection name as a key.
+#     - Otherwise export collections to the current target (should be an API
+#       node instance).
 #     + Clean current namespace of the `_collections` property.
 #
 # ### Hydrate resource links
@@ -106,19 +116,20 @@
 #     + Save the node instance in `_resources` property with `xpath` base as a
 #       namespace and element name as a key.
 #     + Set resource link node value to undefined.
-# + Resource link export
+# - Resource links owner hydration
 #     + Detect that current node has a resource links.
 #     + Retrive resource links related to `xpath`.
 #     + Remove resource link child elements from target node.
 #     + If current node is a root one then export corresponding
 #       `_resourceLinks` namespace to target.
-#     + Otherwise populate the namespace over the node.
+#     - Otherwise export resource links to the current target (should be an API
+#       node instance).
 #     + Remove related namespace from `_resourceLinks` property.
 #
 # ### Hydrate resources
 #
 # + Detect resources.
-# - Delegate resource hydration to other hydrator instance.
+# - Create a resource object and set as a current target.
 # + Replace node value with hydrated resource.
 #
 # ### Hydrate actions
@@ -128,18 +139,11 @@
 #
 # ### Hydrate properties
 #
-# - Detect properties
-# - Save them in corresponding property.
-#
-#
-# Export tasks
-# -------------
-#
-# - Export attributes.
-# - Export collections.
-# - Export resources.
-# - Export resource links.
-# - Export properties.
+# - If node has an attributes then they should be merged to node hash.
+# - For API nodes (e.g. when current target existed) attributes should be
+#     - exportet to current target
+#     - and removed from node hash.
+# - If current target is specified then properties should be exported to it.
 #
 #
 # Utility tasks


Support for resources.yml files added

Support for resources.yml files added

--- cli/tasks/build/parse/resources/parser.coffee
+++ cli/tasks/build/parse/resources/parser.coffee
@@ -88,7 +88,7 @@

     file = fs.readFileSync path, 'utf-8'
     try
-        if pathUtils.extname(path) is '.yaml'
+        if pathUtils.extname(path) in ['.yaml', '.yml']
             json = yaml.safeLoad file
         else
             json = JSON.parse file
@@ -218,20 +218,20 @@
         return

     stat = fs.statSync path
-    jsonPathResourcesFile = pathUtils.join path, './resources.json'
-    yamlPathResourcesFile = pathUtils.join path, './resources.yaml'
+    possiblePaths = [
+        pathUtils.join(path, './resources.json'),
+        pathUtils.join(path, './resources.yaml'),
+        pathUtils.join(path, './resources.yml'),
+    ]

     if isResourcesPath(path)
-        parseResourcesFile path, config
-    else if stat.isDirectory()
-        if fs.existsSync(jsonPathResourcesFile)
-            parseResourcesFile jsonPathResourcesFile, config
-        else if fs.existsSync(yamlPathResourcesFile)
-            parseResourcesFile yamlPathResourcesFile, config
-        else
-            parseResourcesFolder path, config
-    else
-        parseResourceFile path, config
+        return parseResourcesFile path, config
+    if stat.isDirectory()
+        for possiblePath in possiblePaths
+            if fs.existsSync(possiblePath)
+                return parseResourcesFile possiblePath, config
+        return parseResourcesFolder path, config
+    return parseResourceFile path, config

 exports.parse = (path, callback) ->
     stack = new utils.async.Stack


activity: move cursor to the end when input view is focused

--- client/Social/Activity/views/inputview.coffee
+++ client/Social/Activity/views/inputview.coffee
@@ -24,4 +24,11 @@
     @emit 'Enter', value

-  empty: -> @setValue ''+  empty: -> @setValue ''
+
+  setFocus: ->
+    el = @getElement()
+    # move cursor to the end
+    if el.selectionStart? and el.selectionEnd?
+      el.selectionStart = el.selectionEnd = el.value.length
+


activity: define `ActivityInputView::insertNewline` method

--- client/Social/Activity/views/inputview.coffee
+++ client/Social/Activity/views/inputview.coffee
@@ -76,6 +76,9 @@
     return  if @getTokens().length >= TOKEN_LIMIT
     super

+  insertNewline: ->
+    document.execCommand 'insertText', no, "\n"
+
   getPosition: ->
     {startContainer, startOffset} = KD.utils.getSelectionRange()
     {parentNode} = startContainer


Find nodes by prefix or exact match

Find nodes by prefix or exact match

--- lib/assets/javascripts/turbolinks.js.coffee
+++ lib/assets/javascripts/turbolinks.js.coffee
@@ -160,7 +160,7 @@
 findNodesMatchingKeys = (body, keys) ->
   matchingNodes = []
   for key in keys
-    matchingNodes.push(findNodes(body, '[id^="'+key+'"]')...)
+    matchingNodes.push(findNodes(body, '[id^="'+key+':"], [id="'+key+'"]')...)

   return matchingNodes


Fix typo

Fix typo

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -299,7 +299,7 @@
       title         : "Host's layout is updated since you last watched his changes."
       cssClass      : "modal-with-text layout-changed-modal"
       content       : """
-        if you click yes below we'll change your tabs layout to match host's layout.
+        If you click yes below we'll change your tabs layout to match host's layout.
         You won't lose your changes, if you have any.

         Would you like to proceed?
       """


ide/collaborationcontroller: removed error code check

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -258,10 +258,9 @@
         .then =>
           @listenKlientKite()
         .catch (err) =>
-          if err?.code is 1002
-            if @amIHost
-            then @handleCollaborationEndedForHost()
-            else @handleCollaborationEndedForParticipant()
+          if @amIHost
+          then @handleCollaborationEndedForHost()
+          else @handleCollaborationEndedForParticipant()

   setWatchMap: ->


collaboration: use fetchChannel helper

collaboration: use fetchChannel helper

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -65,12 +65,10 @@
     unless id = @getSocialChannelId()
       return callback()

-
-    kd.singletons.socialapi.cacheable 'channel', id, (err, channel) =>
+    socialHelpers.fetchChannel id, (err, channel) =>
       return callback err  if err

       @setSocialChannel channel
-
       callback null, @socialChannel


collaboration: wait for rtm to be ready to be loading

--- client/ide/lib/collaborationcontroller.coffee
+++ client/ide/lib/collaborationcontroller.coffee
@@ -713,7 +713,7 @@

     @rtm = new RealtimeManager
     @showShareButton()
-    kd.utils.defer => @setCollaborationState 'loading'
+    kd.utils.defer => @rtm.ready => @setCollaborationState 'loading'

   onCollaborationLoading: ->


Inline now works when having no pre-rendered items, resolves #191

--- wzk/ui/inlineform/DynamicForm.coffee
+++ wzk/ui/inlineform/DynamicForm.coffee
@@ -43,8 +43,9 @@
     row = rows[rows.length - 1] # prototype row, intended to be cloned
     builder = new wzk.ui.inlineform.RowBuilder(row, expert, @dom)

-    for rowIndex in [0..rows.length - 2]
-      builder.decorateRow rows[rowIndex]
+    if rows.length > 1
+      for rowIndex in [0..rows.length - 2]
+        builder.decorateRow rows[rowIndex]

     if enabled
       @hangAddRowListener builder, btn


Remove an annoying debugging comment

Remove an annoying debugging comment

--- lib/assets/javascripts/up/history.js.coffee
+++ lib/assets/javascripts/up/history.js.coffee
@@ -63,7 +63,6 @@
     normalizeUrl(url) == currentUrl()

   observeNewUrl = (url) ->
-    console.log("observing new url %o", url)
     if nextPreviousUrl
       previousUrl = nextPreviousUrl
       nextPreviousUrl = undefined


bug fix window jumping when clicking group page tabs

--- vue/src/routes.coffee
+++ vue/src/routes.coffee
@@ -32,15 +32,15 @@
 Vue.use(Router)

 groupPageChildren = [
-  {path: 'polls', component: GroupPollsPanel}
-  {path: 'members', component: MembersPanel}
-  {path: 'membership_requests', component: MembershipRequestsPanel}
-  {path: 'members/requests', redirect: 'membership_requests' }
-  {path: 'subgroups', component: GroupSubgroupsPanel}
-  {path: 'files', component: GroupFilesPanel}
-  {path: 'settings', component: GroupSettingsPanel}
-  {path: ':stub?', component: GroupDiscussionsPanel}
-  {path: 'slack/install', component: InstallSlackPage}
+  {path: 'polls', component: GroupPollsPanel, meta: {noScroll: true}}
+  {path: 'members', component: MembersPanel, meta: {noScroll: true}}
+  {path: 'membership_requests', component: MembershipRequestsPanel, meta: {noScroll: true}}
+  {path: 'members/requests', redirect: 'membership_requests', meta: {noScroll: true}}
+  {path: 'subgroups', component: GroupSubgroupsPanel, meta: {noScroll: true}}
+  {path: 'files', component: GroupFilesPanel, meta: {noScroll: true}}
+  {path: 'settings', component: GroupSettingsPanel, meta: {noScroll: true}}
+  {path: ':stub?', component: GroupDiscussionsPanel, meta: {noScroll: true}}
+  {path: 'slack/install', component: InstallSlackPage, meta: {noScroll: true}}
 ]

 threadPageChildren = [
@@ -52,8 +52,15 @@

 export default new Router
   mode: 'history'
+
   scrollBehavior: (to, from, savedPosition) ->
-    { x: 0, y: 0 }
+    if savedPosition
+      savedPosition
+    else if (to.meta.noScroll and from.meta.noScroll)
+      window.scrollHeight
+    else
+      { x: 0, y: 0 }
+
   routes: [
     {path: '/dashboard', component: DashboardPage},
     {path: '/dashboard/:filter', component: DashboardPage},
@@ -67,7 +74,7 @@
     {path: '/d/new', component: StartDiscussionPage },
     {path: '/d/:key', name: 'discussion', component: ThreadPage, children: threadPageChildren },
     {path: '/g/new', component: StartGroupPage},
-    {path: '/g/:key', component: GroupPage, children: groupPageChildren},
+    {path: '/g/:key', component: GroupPage, children: groupPageChildren, name: 'groupKey'},
     {path: '/:key', component: GroupPage, children: groupPageChildren},
     {path: '/', redirect: '/dashboard' }
   ]


add generateRandomUserArray function

add generateRandomUserArray function

--- workers/social/testhelper/index.coffee
+++ workers/social/testhelper/index.coffee
@@ -1,5 +1,6 @@
 _                       = require 'underscore'
 hat                     = require 'hat'
+JUser                   = require '../lib/social/models/user'
 JAccount                = require '../lib/social/models/account'
 JSession                = require '../lib/social/models/session'
 Bongo                   = require 'bongo'
@@ -117,6 +118,24 @@
   return userInfo

+generateRandomUserArray =  (count, callback) ->
+
+  queue     = []
+  userArray = []
+
+  for i in [0...count]
+    queue.push ->
+      JUser.createUser generateUserInfo(), (err, user_) ->
+        expect(err).to.not.exist
+        userArray.push user_
+        queue.next()
+
+  queue.push -> callback userArray
+
+  daisy queue
+
+
+
 module.exports = {
   daisy
   expect
@@ -128,6 +147,7 @@
   generateRandomString
   checkBongoConnectivity
   generateRandomUsername
+  generateRandomUserArray
   generateDummyUserFormData
 }


style: use explicit dependencies and leaner indentation

--- src/coffee/services.coffee
+++ src/coffee/services.coffee
@@ -50,22 +50,21 @@
             service.districts = data
     service.promise = $q.all [service.placesPromise, service.districtsPromise]
     return service
+]

+eob_services.factory 'eob_weather', ['$http', ($http) ->
+    FORECAST_ENDPOINT = "http://query.yahooapis.com/v1/public/yql?q="
+    FORECAST_YQL_OPEN 	= "select * from weather.forecast where location='"
+    FORECAST_YQL_CLOSE 	= "'and u='c'&format=json"
+    YQL_BERLIN = "GMXX0007"

-eob_services.factory 'eob_weather', ['$http',
-    ($http) ->
-        FORECAST_ENDPOINT = "http://query.yahooapis.com/v1/public/yql?q="
-        FORECAST_YQL_OPEN 	= "select * from weather.forecast where location='"
-        FORECAST_YQL_CLOSE 	= "'and u='c'&format=json"
-        YQL_BERLIN = "GMXX0007"
-
-        {
-            getWeather: (scope) ->
-                url = FORECAST_ENDPOINT + FORECAST_YQL_OPEN + YQL_BERLIN + FORECAST_YQL_CLOSE
-                $http.get(url).success( (data) ->
-                    scope.weather = data
-                    scope.temp = data.query.results.channel.item.condition.temp
-                    scope.wcode = data.query.results.channel.item.condition.code
-                )
-        }
+    {
+        getWeather: (scope) ->
+            url = FORECAST_ENDPOINT + FORECAST_YQL_OPEN + YQL_BERLIN + FORECAST_YQL_CLOSE
+            $http.get(url).success( (data) ->
+                scope.weather = data
+                scope.temp = data.query.results.channel.item.condition.temp
+                scope.wcode = data.query.results.channel.item.condition.code
+            )
+    }
 ]


Prevent multiple form submits.

Prevent multiple form submits.

--- app/assets/javascripts/app/controllers/ticket_zoom.coffee
+++ app/assets/javascripts/app/controllers/ticket_zoom.coffee
@@ -495,8 +495,13 @@
     e.stopPropagation()
     e.preventDefault()

+    # disable form
+    @formDisable(e)
+
     # validate new article
-    return if !@articleNew.validate()
+    if !@articleNew.validate()
+      @formEnable(e)
+      return

     taskAction = @$('.js-secondaryActionButtonLabel').data('type')

@@ -539,13 +544,11 @@
     # check if title exists
     if !ticket['title']
       alert( App.i18n.translateContent('Title needed') )
+      @formEnable(e)
       return

     # submit ticket & article
     @log 'notice', 'update ticket', ticket
-
-    # disable form
-    @formDisable(e)

     # stop autosave
     @autosaveStop()


Still working on it...

Still working on it...

--- app/assets/javascripts/sprangular/services/catalog.coffee
+++ app/assets/javascripts/sprangular/services/catalog.coffee
@@ -34,7 +34,7 @@
     find: (id) ->
       $http.get("/api/products/#{id}", class: Sprangular.Product)
         .then (response) ->
-          Status.cacheProduct response
+          Status.cacheProduct(response)

     getPaged: (page=1, params={}) ->
       $http.get("/api/products", ignoreLoadingIndicator: params.ignoreLoadingIndicator, params: {per_page: @pageSize, page: page, "q[name_or_description_cont]": params.search, "q[taxons_permalink_eq]": params.taxon})


Removed unnecessary cookie setting logic

--- sample.coffee
+++ sample.coffee
@@ -63,11 +63,7 @@
    Deps.autorun () ->
       userId = Meteor.userId()
       Meteor.subscribe 'allData', userId
-      token = Accounts._storedLoginToken()
-      cookie = $.cookie 'X-Auth-Token'
-      if cookie isnt token
-         $.removeCookie 'X-Auth-Token' if cookie
-         $.cookie 'X-Auth-Token', token
+      $.cookie 'X-Auth-Token', Accounts._storedLoginToken()

    #####################
    # UI template helpers


Revert "guests group: map it over to "koding" on the client side"

This reverts commit 205a952a959dad9a48c4ea669ed7fd76f06d0037.

--- client/landing/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Groups.kdapplication/AppController.coffee
@@ -66,15 +66,22 @@

   changeGroup:(groupName='', callback=->)->

-    groupName or=
-      if KD.defaultSlug is 'guests'
-      then 'koding'
-      else KD.defaultSlug
-
+    groupName or= KD.defaultSlug
     return callback()  if @currentGroupName is groupName

-    throw new Error 'Cannot change the group!'  if @currentGroupName?
-    unless @currentGroupName is groupName
+    if @currentGroupName?
+      location.reload()
+      # modal = new KDModalView
+      #   title       : 'Change group'
+      #   content     : 'You have requested to change the group.'
+      #   overlay     : yes
+      #   buttons     :
+      #     "Yes, Change group":
+      #       style    : "modal-clean-red"
+      #       callback : (event)=>
+      #         location.reload()
+
+    else unless @currentGroupName is groupName
       KD.remote.cacheable groupName, (err, models)=>
         if err then callback err
         else if models?


Fix issues with EugeniaNotation tests.

Fix issues with EugeniaNotation tests.

--- app/scripts/controllers/notations/eugenia_notation.coffee
+++ app/scripts/controllers/notations/eugenia_notation.coffee
@@ -203,11 +203,21 @@
     deserialiseProperties: (definition) ->
       result = {}

-      properties_pattern = /@gmf\.\w*\((.*)\)/
+      # As Javascript regex doesn't have a flag that allows the . character
+      # to match newlines, we use the [\s\S] character class instead.
+      # [\s\S] means "whitespace or non-whitespace" and is equivalent to
+      # any character (including a newline)
+      properties_pattern = /@gmf\.\w*\(([\s\S]*)\)/
+
       properties = definition.match(properties_pattern)[1]
       for property in properties.split(', ')
         property_pattern = /([^=]*)="([^"]*)"/
         [key, value] = property.match(property_pattern)[1..2]
-        result[key] = value
-
-      result+        result[@strip(key)] = @strip(value)
+
+      result
+
+    # Remove leading / trailing whitespace
+    strip: (string) ->
+      string.replace /^\s+|\s+$/g, ""
+


Add Polish

Add Polish

--- app/main.coffee
+++ app/main.coffee
@@ -9,6 +9,7 @@
 languageManager = new LanguageManager
   translations:
     en: label: 'English', strings: enUs
+    pl: label: 'Polski'

 languageManager.on 'change-language', (e, code, strings) ->
   translate.load strings


Use ArrayPort with Kick

Use ArrayPort with Kick

--- src/components/Kick.coffee
+++ src/components/Kick.coffee
@@ -16,7 +16,7 @@
       data: new noflo.Port()

     @outPorts =
-      out: new noflo.Port()
+      out: new noflo.ArrayPort()

     @inPorts.in.on 'begingroup', (group) =>
       @groups.push group
@@ -41,7 +41,7 @@
     @outPorts.out.send kick.packet

     for group in kick.group
-      @outPorts.out.endGroup group
+      @outPorts.out.endGroup()

     @outPorts.out.disconnect()


extend from Stark.View

extend from Stark.View

--- manager/app/assets/javascripts/monitoring/monitoring_views.js.coffee
+++ manager/app/assets/javascripts/monitoring/monitoring_views.js.coffee
@@ -1,7 +1,7 @@

 namespace "Bixby.view.monitoring", (exports, top) ->

-  class exports.Layout extends Backbone.View
+  class exports.Layout extends Stark.View
     el: $("#content")
     template: "monitoring/layout"
     events: {


stuff

stuff

--- config/application.coffee
+++ config/application.coffee
@@ -4,7 +4,7 @@
 steroids.config.name = "My New Application"

 # -- Initial Location --
-steroids.config.location = "http://localhost/views/recipe/index.html"
+steroids.config.location = "http://localhost/views/movie/index.html"

 # -- Tab Bar --
 # steroids.config.tabBar.enabled = true


Turn off CDN for assets

Turn off CDN for assets

--- config/application.coffee
+++ config/application.coffee
@@ -1,4 +1,4 @@
-cdn = "http://cdn4.testdouble.com/"
+cdn = ""
 lineman = require(process.env['LINEMAN_MAIN'])

 module.exports = lineman.config.extend "application",


Get the articles property from the output of articleSelectors.containerSelector.

--- server.coffee
+++ server.coffee
@@ -10,7 +10,7 @@
 db = require './db.coffee'
 init = require './src/scripts/init.coffee'
 store = require './src/scripts/store.coffee'
-articleSelectors = require '.src/scripts/article-selectors.coffee'
+articleSelectors = require './src/scripts/selectors/article-selectors.coffee'
 routes = require './src/scripts/views/routes.coffee'
 Template = React.createFactory require './views/index.coffee'

@@ -56,8 +56,9 @@
 	lang = req.acceptsLanguages 'nb', 'en'
 	res.header 'Content-Type', 'application/atom+xml; charset=utf8'
 	init().then ->
-		articles = articleSelectors.containerSelector store.getState()
-		res.render 'feed', id: '', updated: '', articles: articles
+		articles = articleSelectors.containerSelector(store.getState()).articles
+		updated = if articles.length then articles[0].updated else ''
+		res.render 'feed', id: req.url, updated: updated, articles: articles

 server.get '/:view', (req, res) ->
 	query = {}


change default port for mail

change default port for mail

--- server.coffee
+++ server.coffee
@@ -14,7 +14,7 @@
 app = module.exports = require('railway').createServer()

 if not module.parent
-  port = process.env.PORT or 8003
+  port = process.env.PORT or 9203, "127.0.0.1"
   app.listen port
   console.log "CozyMail server listening on port %d within %s environment", port, app.settings.env


seed reset

seed reset

--- server.coffee
+++ server.coffee
@@ -21,6 +21,7 @@
 	seed=log[0]
 	if !openseeds[seed]? or new Date().getTime()-((+openseeds[seed])) > seed_timeout
 		res.send 403,'seed already used or server restart'
+	openseeds[seed]=0

 	# Reevaluate the game
 	score=(new tetris.Game()).run log


add todo

add todo

--- server.coffee
+++ server.coffee
@@ -336,6 +336,7 @@
         if err
           res.send 500, { error: "API call failed" }
           return
+        # TODO (anton) we need updated members property of the repo here.
         res.json resp
     else
       res.send 500, {error: "Internal error"}


debug info

debug info

--- server.coffee
+++ server.coffee
@@ -364,10 +364,12 @@
 getTopicMeta = (community, topic, callback) ->
   ghAdmin = github.client nconf.get "GIHUB_ADMIN_TOKEN"
   ghAdmin.get "/repos/communities/#{community}/git/refs/heads/#{topic}", {}, (err, status, ref) ->
+    console.log "topic meta1", err, status, ref
     if err or not ref? or not ref.object?
       callback err
       return
     getCommits community, ref.object.sha, (err, commits) ->
+      console.log "topic meta: commits", err, commits
       if err
         callback err
         return
@@ -459,7 +461,7 @@
 renderIndexPage = (req, res) ->
   params =
     user: req.user or {}
-    jsFile: if nconf.get("NODE_ENV") == "production" then "/app.min.js" else  "/app.js"
+    jsFile: if nconf.get("NODE_ENV") == "production" then "/app.min.js" else "/app.js"
   getCommunities (err, communities) ->
     if !err
       params.communitiesCount = communities.length


ignore invalid savegames

ignore invalid savegames

--- server/app/controllers/Game.coffee
+++ server/app/controllers/Game.coffee
@@ -21,7 +21,9 @@
 		fs.readdir __dirname + '/../../../answers/', (err,files) =>
 			oldQuestions = []
 			for file in files
-				for action in require('../../../answers/' + file).actions
+				save = require('../../../answers/' + file)
+				continue unless save.actions?
+				for action in save.actions
 					continue if not action.question
 					oldQuestions.push action.question.question
 			log.info oldQuestions


fixed test

fixed test

--- test/watch_project.coffee
+++ test/watch_project.coffee
@@ -44,7 +44,7 @@
     test.expect 1
     zombie.visit('http://localhost:8080', (err, browser, status) ->
       throw err.message if err
-      test.strictEqual browser.html('h1'), '
Welcome to Brunch
'
+      test.strictEqual browser.html('h1'), '
brunch
'
       test.done()
     )
   'update package dependencies when file has been added': (test) ->
@@ -82,7 +82,7 @@
       ->
         zombie.visit('http://localhost:8080', (err, browser, status) ->
           throw err.message if err
-          test.strictEqual browser.html('h1'), '
Welcome to Brunch
'
+          test.strictEqual browser.html('h1'), '
brunch
'
           test.done()
         )
       2000


pull the current country from the configuration, instead of allowing it to be hard-coded to the US.

--- src/coffee/donations-form-model.coffee
+++ src/coffee/donations-form-model.coffee
@@ -31,7 +31,7 @@

     self.org = ko.observable(config['org'])

-    self.countryCode = ko.observable("US")
+    self.countryCode = ko.observable(config['country'] )

     self.imgPath = ko.observable(config['imgpath'])
     self.initializeIcons(self.imgPath())


use shape's draw_circle method

use shape's draw_circle method

--- views/gorillas.coffee
+++ views/gorillas.coffee
@@ -1,8 +1,11 @@
 class Shape
   constructor:(@context) ->

-  draw_circle:(x, y, width, color) ->
-    @context.fillStyle = color
+  set_color:(color) ->
+    @color = color
+
+  draw_circle:(x, y, width) ->
+    @context.fillStyle = @color
     @context.beginPath()
     @context.arc x, y, width, 0, Math.PI*2, true
     @context.closePath()
@@ -121,14 +124,15 @@
     @smile()

   draw_body:() ->
-    shape = new Shape(@context)
-    shape.draw_circle(@position(), @y, @width, @color)
+    shape = new Shape @context
+    shape.set_color @color
+    shape.draw_circle @position(), @y, @width

   eyes:() ->
     shape = new Shape(@context)
-    color = '#000000'
-    shape.draw_circle(@position()-10, @y-10, 5, color)
-    shape.draw_circle(@position()+10, @y-10, 5, color)
+    shape.set_color '#000000'
+    shape.draw_circle @position()-10, @y-10, 5
+    shape.draw_circle @position()+10, @y-10, 5

   smile:() ->
     @context.strokeStyle = '#000000'


display name and no redundant requiring

display name and no redundant requiring

--- src/components/async-button.cjsx
+++ src/components/async-button.cjsx
@@ -2,19 +2,18 @@
 BS = require 'react-bootstrap'

 module.exports = React.createClass
-  displayText: 'AsyncButton'
+  displayName: 'AsyncButton'

   propTypes:
     store: React.PropTypes.object.isRequired
     isWaiting: React.PropTypes.bool.isRequired
     isDone: React.PropTypes.bool
-    isFailed: React.PropTypes.bool.isRequired
-    waitingText: React.PropTypes.any.isRequired # TODO: This should be a Component or array
-    errorText: React.PropTypes.any.isRequired
+    isFailed: React.PropTypes.bool
+    waitingText: React.PropTypes.any # TODO: This should be a Component or array
+    errorText: React.PropTypes.any
     doneText: React.PropTypes.any

   getDefaultProps: ->
-    isWaiting: false
     isDone: false
     isFailed: false
     waitingText: 'Loading…'


ok thats a commit

ok thats a commit

--- lineman/app/js/models/proposal_model.coffee
+++ lineman/app/js/models/proposal_model.coffee
@@ -28,9 +28,8 @@
       RecordStoreService.get('discussions', @discussionId)

     votes: ->
-      [{createdAt: moment().year(2001), proposalId: 1} ]
-      #RecordStoreService.get 'votes', (vote) =>
-        #vote.proposalId == @id
+      RecordStoreService.get 'votes', (vote) =>
+        vote.proposalId == @id

     authorName: ->
       @author().name


Cleanup

Cleanup

--- apps/notifications/client/index.coffee
+++ apps/notifications/client/index.coffee
@@ -46,9 +46,6 @@
     @$feed.waypoint (direction) =>
       @nextPage() if direction is 'down'
     , { offset: 'bottom-in-view' }
-    # @$artistFeed.waypoint (direction) =>
-    #   @nextArtistPage() if direction is 'down'
-    # , { offset: 'bottom-in-view' }

   params: ->
     qs.parse(location.search.substring(1))


x last sticky test

x last sticky test

--- src/desktop/apps/notifications/test/client/index.test.coffee
+++ src/desktop/apps/notifications/test/client/index.test.coffee
@@ -13,7 +13,8 @@
 { stubChildClasses } = require '../../../../test/helpers/stubs'
 SidebarView = null

-describe 'NotificationsView', ->
+# FIXME: cannot set location on undefined (window) in benv setup
+xdescribe 'NotificationsView', ->
   before (done) ->
     benv.setup ->
       benv.expose


Fail fast when passing an invalid location range to #setLocationRange

--- src/trix/models/selection_manager.coffee
+++ src/trix/models/selection_manager.coffee
@@ -20,8 +20,9 @@
     else
       new Trix.LocationRange start, end

-    @setDOMRange(locationRange)
-    @updateCurrentLocationRange(locationRange)
+    if locationRange = @setDOMRange(locationRange)
+      @updateCurrentLocationRange(locationRange)
+      locationRange

   setLocationRangeFromPoint: (point) ->
     locationRange = @getLocationRangeAtPoint(point)
@@ -95,6 +96,8 @@
       else
         @findContainerAndOffsetForLocation(locationRange.end)

+    return unless rangeStart? and rangeEnd?
+
     range = document.createRange()
     range.setStart(rangeStart...)
     range.setEnd(rangeEnd...)
@@ -112,6 +115,8 @@
       # https://code.google.com/p/chromium/issues/detail?id=423170
       # https://code.google.com/p/chromium/issues/detail?id=138439
       defer(applyRange)
+
+    locationRange

   createLocationRangeFromDOMRange: (range) ->
     return unless range? and @rangeWithinElement(range)


artik710.coffee: Upgrade to experimental

Signed-off-by: Andrei Gherzan <8dc7c09356db0b1762fb140617d7375c0a5a4131@resin.io>

--- artik710.coffee
+++ artik710.coffee
@@ -19,7 +19,7 @@
 	aliases: [ 'artik710' ]
 	name: 'Samsung Artik 710'
 	arch: 'aarch64'
-	state: 'HIDDEN'
+	state: 'experimental'

 	stateInstructions:
 		postProvisioning: postProvisioningInstructions


Router: Don't handle the route if it's already the path is same.

--- src/lib/core/Router.coffee
+++ src/lib/core/Router.coffee
@@ -24,9 +24,15 @@
     @historyManager = new spark.core.HistoryManager
     @routes = {}
     @routeRegexes = {}
+    @latestHandledRoute = null

     @historyManager.on 'Navigated', (e) =>
-      @handleRoute_ e.data
+      path = e.data
+
+      return if @latestHandledRoute is path
+
+      @handleRoute_ path
+      @latestHandledRoute = path

   ###*


Updated upgradeChoices; victims of Saboteur were choosing to gain Bag of Gold instead of nothing when a Silver was trashed, so now upgradeChoices makes sure card2 is not a Prize before adding it to the array of choices that will be returned.

--- cards.coffee
+++ cards.coffee
@@ -1725,7 +1725,8 @@
       for cardname2 of state.supply
         card2 = c[cardname2]
         if filter(state, card, card2) and state.supply[card2] > 0
-          choices.push([card, card2])
+          if not card2.isPrize
+            choices.push([card, card2])
   return choices

 # Export functions that are needed elsewhere.


Fix method doc

Fix method doc

--- src/mentions-kinder.coffee
+++ src/mentions-kinder.coffee
@@ -279,7 +279,7 @@

   # Converts the given input/textarea to an editable that hopefully looks the same
   # called from constructor
-  # assigns @$wrap, @$editable and @$input
+  # assigns @$wrap and @$editable
   # requires @$originalInput
   _setupElements: ->
     # create wrap, editable and hidden input


Add wheel_zoom tests about zoom origin

Add wheel_zoom tests about zoom origin

--- bokehjs/test/models/tools/gestures/wheel_zoom_tool.coffee
+++ bokehjs/test/models/tools/gestures/wheel_zoom_tool.coffee
@@ -31,6 +31,8 @@
     beforeEach ->
       utils.stub_canvas()

+      # Note default plot dimensions is 600 x 600 (height x width)
+      # This is why zooming at {sx: 300, sy: 300} causes the x/y ranges to zoom equally
       @plot = new Plot({
          x_range: new Range1d({start: -1, end: 1})
          y_range: new Range1d({start: -1, end: 1})
@@ -91,7 +93,7 @@
       expect(vr.start).to.be.closeTo(-1.166, 0.01)
       expect(vr.end).to.be.closeTo(1.166, 0.01)

-    it "should zoom the x-axis only", ->
+    it "should zoom the x-axis only because dimensions arg is set", ->
       wheel_zoom = new WheelZoomTool({dimensions: ['width']})

       @plot.add_tools(wheel_zoom)
@@ -114,7 +116,30 @@
       vr = @plot_canvas_view.frame.y_ranges['default']
       expect([vr.start, vr.end]).to.be.deep.equal([-1.0, 1.0])

-    it "should zoom the y-axis only", ->
+    it "should zoom the x-axis only because sy is off frame", ->
+      wheel_zoom = new WheelZoomTool({dimensions: ['height', 'width']})
+
+      @plot.add_tools(wheel_zoom)
+
+      wheel_zoom_view = new wheel_zoom.default_view({
+        model: wheel_zoom
+        plot_model: @plot.plot_canvas
+        plot_view: @plot_canvas_view
+      })
+
+      # positive delta will zoom in
+      zoom_event = {"bokeh": {sx: 300, sy: 0, delta: 100}}
+
+      # perform the tool action
+      wheel_zoom_view._scroll(zoom_event)
+
+      hr = @plot_canvas_view.frame.x_ranges['default']
+      expect(hr.start).to.be.closeTo(-0.833, 0.01)
+      expect(hr.end).to.be.closeTo(0.833, 0.01)
+      vr = @plot_canvas_view.frame.y_ranges['default']
+      expect([vr.start, vr.end]).to.be.deep.equal([-1.0, 1.0])
+
+    it "should zoom the y-axis only because dimensions arg is set", ->
       wheel_zoom = new WheelZoomTool({dimensions: ['height']})

       @plot.add_tools(wheel_zoom)
@@ -136,3 +161,50 @@
       vr = @plot_canvas_view.frame.y_ranges['default']
       expect(vr.start).to.be.closeTo(-0.833, 0.01)
       expect(vr.end).to.be.closeTo(0.833, 0.01)
+
+    it "should zoom the y-axis only because sx is off frame", ->
+      wheel_zoom = new WheelZoomTool({dimensions: ['width', 'height']})
+
+      @plot.add_tools(wheel_zoom)
+
+      wheel_zoom_view = new wheel_zoom.default_view({
+        model: wheel_zoom
+        plot_model: @plot.plot_canvas
+        plot_view: @plot_canvas_view
+      })
+
+      # positive delta will zoom in
+      zoom_event = {"bokeh": {sx: 0, sy: 300, delta: 100}}
+
+      # perform the tool action
+      wheel_zoom_view._scroll(zoom_event)
+
+      hr = @plot_canvas_view.frame.x_ranges['default']
+      expect([hr.start, hr.end]).to.be.deep.equal([-1.0, 1.0])
+      vr = @plot_canvas_view.frame.y_ranges['default']
+      expect(vr.start).to.be.closeTo(-0.833, 0.01)
+      expect(vr.end).to.be.closeTo(0.833, 0.01)
+
+    it "should zoom centered around the zoom point", ->
+      wheel_zoom = new WheelZoomTool({dimensions: ['height', 'width']})
+
+      @plot.add_tools(wheel_zoom)
+
+      wheel_zoom_view = new wheel_zoom.default_view({
+        model: wheel_zoom
+        plot_model: @plot.plot_canvas
+        plot_view: @plot_canvas_view
+      })
+
+      # positive delta will zoom in
+      zoom_event = {"bokeh": {sx: 100, sy: 100, delta: 100}}
+
+      # perform the tool action
+      wheel_zoom_view._scroll(zoom_event)
+
+      hr = @plot_canvas_view.frame.x_ranges['default']
+      expect(hr.start).to.be.closeTo(-0.945, 0.01)
+      expect(hr.end).to.be.closeTo(0.722, 0.01)
+      vr = @plot_canvas_view.frame.y_ranges['default']
+      expect(vr.start).to.be.closeTo(-0.722, 0.01)
+      expect(vr.end).to.be.closeTo(0.945, 0.01)


switch from bind to self because tests fail in phantomjs

--- chain.coffee
+++ chain.coffee
@@ -4,9 +4,10 @@
     # build a chain to use
     @_chain = buildChain()
     # we want to reorder the chain's array when fn's are added/removed
-    reorder = @_reorder.bind this
-    @_chain.on 'add', reorder
-    @_chain.on 'remove', reorder
+    # phantomjs disliked my using: reorder = @_reorder.bind(this), so, use self:
+    self = this
+    @_chain.on 'add', -> self._reorder()
+    @_chain.on 'remove', -> self._reorder()
     # same as for chain-builder above.
     @_orderer  = ordering ? Npm.require 'ordering'


revise to use new chain-builder

revise to use new chain-builder

--- chain.coffee
+++ chain.coffee
@@ -1,43 +1,40 @@
+# client has `buildChain` browserified, server uses Npm.require
+buildChain ?= Npm.require 'chain-builder'
+
+# let's add Ordering to the array
 class Chain

-  constructor: (@type = 'chain') ->
-    @_actions = []
-    # client has `builder` browserified, server uses Npm.require
-    @_builder  = builder ? Npm.require 'chain-builder'
-    # same as for builder above.
+  constructor: () ->
+    # build a chain to use
+    @_chain = buildChain()
+    # we want to reorder the chain's array when fn's are added/removed
+    reorder = @_reorder.bind this
+    @_chain.on 'add', -> reorder
+    @_chain.on 'remove', -> reorder
+    # same as for chain-builder above.
     @_orderer  = ordering ? Npm.require 'ordering'
-    @_build()

   # TODO: allow (string, action) to specify the ID as first param
   add: (action) ->
     # TODO: verify action is a function
     # TODO: verify action has a name in options or on itself
     action.options = id:action.name unless action?.options?
-    @_actions.push action
-    @_build()
+    @_chain.add action

   remove: (actionOrId) ->
+    switch typeof actionOrId
+      when 'function' then action = actionOrId
+      when 'string'
+        action = a for a in @_chain.array when actionOrId is a.options.id

-    index = -1
+    @_chain.remove action

-    switch typeof actionOrId
-      when 'function'
-        index = @_actions.indexOf actionOrId
-      when 'string'
-        index = i for action,i in @_actions when actionOrId is action.options.id
+  execute: (context, done) -> @_chain.run context:context, done:done

-    @_actions.splice index, 1 if index > -1 if index isnt -1
-
-    @_build()
-
-  execute: (context) -> @_chain context
-
-  _build: ->
-    result = @_order @_actions
+  _reorder: ->
+    result = @_order @_chain.array
     @_printError result, 'Error ordering actions' if result?.error?
-    result = @_builder[@type] result.array
-    @_printError result, 'Error building actions chain' if result?.error?
-    @_chain = result[@type] if result?[@type]?
+    @_chain.array = result.array
     return

   _order: (array) -> @_orderer.order array:array


fix agda file <=> non-agda file instantiation

--- lib/agda-mode.coffee
+++ lib/agda-mode.coffee
@@ -43,14 +43,18 @@

             # instantiate core if it's .agda
             @instantiateCore editor if isAgdaFile editor
-            # instantiate core if it becomes .agda
+
             editor.onDidChangePath =>
-                if isAgdaFile editor
-                    @instantiateCore editor
-                else if editor.core
-                    editor.core.destroy()
+                # agda => not agda
+                if editor.core and not isAgdaFile(editor)
                     editorElement = atom.views.getView editor
                     editorElement.classList.remove 'agda'
+                    editor.core.destroy()
+                    delete editor.core
+
+                # not agda => agda
+                if not editor.core and isAgdaFile(editor)
+                    @instantiateCore editor

         @registerEditorActivation()
         @registerCommands()


add parseVariable test

add parseVariable test

--- tests/variableSpec.coffee
+++ tests/variableSpec.coffee
@@ -19,4 +19,19 @@
 		result = marktab.parseVariable variableName

 		# assert
-		expect(result).toEqual({1:[1], 2:[2]})+		expect(result).toEqual({1:[1], 2:[2]})
+
+	it "Should convert riff to json", ->
+		# arrange
+		variableName = "myVar"
+		variable = variableName + ": [1:0 2:2]"
+		marktab.setVariable(variable)
+		expected =
+			1:[0]
+			2:[undefined,2]
+
+		# act
+		result = marktab.parseVariable variableName
+
+		# assert
+		expect(result).toEqual(expected)


Use absolute value of dot product to choose reference edge

Otherwise the reference swaps as an edge rotates from <0 to >0

--- app/js/physics.coffee
+++ app/js/physics.coffee
@@ -7,7 +7,7 @@
   controls = new KeyboardControls

   # dot = new Particle [100, ctx.height - 100]
-  window.rect = new Rectangle 120, 100, [100, 80], 0.3, "#F00"
+  window.rect = new Rectangle 200, 200, [100, 80], 0.3, "#F00"
   rect2 = new Rectangle 120, 100, [0, 0], 0, "#00F"

   _.extend ctx,
@@ -70,7 +70,7 @@
     # Now, clip the edges. The reference edge is most perpendicular to contact
     # axis, and will be used to clip the incident edge vertices to generate the
     # contact points.
-    if e1.dot(minAxis) <= e2.dot(minAxis)
+    if Math.abs(e1.dot(minAxis)) <= Math.abs(e2.dot(minAxis))
       reference = e1
       incident  = e2
     else


Dev host

Dev host

--- app/lib/config.coffee
+++ app/lib/config.coffee
@@ -14,7 +14,7 @@
       workflowId: '502a701e516bcb0001000002'

   development:
-    apiHost: 'https://api.zooniverse.org'
+    apiHost: 'http://localhost:3000'
     surveys:
       candels:
         id: '50251c3b516bcb6ecb000001'


video: opentok service remove error signal

--- client/app/lib/videocollaboration/services/opentok.coffee
+++ client/app/lib/videocollaboration/services/opentok.coffee
@@ -214,13 +214,6 @@
     session.signal data, _errorSignal

-  ###*
-   * Default error signal.
-  ###
-  _errorSignal = (error) ->
-
-    log "signal error #{error.reason}"  if error
-

   ###*
    * It creates the `OT.Publisher` instance for sending video/audio.


Fix invalid modification check on model save.

--- app/coffee/services/model.coffee
+++ app/coffee/services/model.coffee
@@ -83,7 +83,7 @@
                 self = @
                 defered = $q.defer()

-                if @isModified()
+                if not @isModified()
                     defered.resolve(true)
                     return defered.promise


Removed overlay when visible tooltip length is 0.

--- client/landing/app/CommonViews/introductiontooltip.coffee
+++ client/landing/app/CommonViews/introductiontooltip.coffee
@@ -69,6 +69,7 @@
       @close parentView.getOptions().introId
       parentView.tooltip.destroy()
       @visibleTooltips.splice @visibleTooltips.indexOf(tooltip), 1
+      @overlay.remove() if @visibleTooltips.length is 0

   isExpired: (expiryDate) ->
     return new Date(expiryDate).getTime() < @currentTimestamp


removing stuff from the prototype chain, oops

--- lib/jsMegaHal.coffee
+++ lib/jsMegaHal.coffee
@@ -20,22 +20,22 @@
 	#the regex to split sentences by -- remove all \r\n
 	sentenceRegex: /[!?\.]/

-	#all of the current words jsMegaHal knows
-	words: Object.create null
-
-	#all of the quads, mapped by quad.hash() -> quad
-	quads: {}
-
-	#all of the quads that can come after a given quad, mapped by quad.hash() -> [quad, quad, ...]
-	next: {}
-
-	#all of the quads that can come before a given quad, mapped by quad.hash() -> [quad, quad, ...]
-	prev: {}
-
 	###
 	@markov - the markov order to use for this jsMegaHal instance, defaults to 4
 	###
 	constructor: (@markov = 4, @defaultReply = '') ->
+
+		#all of the current words jsMegaHal knows
+		@words = Object.create null
+
+		#all of the quads, mapped by quad.hash() -> quad
+		@quads = {}
+
+		#all of the quads that can come after a given quad, mapped by quad.hash() -> [quad, quad, ...]
+		@next = {}
+
+		#all of the quads that can come before a given quad, mapped by quad.hash() -> [quad, quad, ...]
+		@prev = {}

 	###
 	generate a number between min and max, inclusive


fix for uncompilable function

fix for uncompilable function

--- src/partials-for-js.coffee
+++ src/partials-for-js.coffee
@@ -13,7 +13,7 @@
     f.apply dis, values
   n.apply null, args

-createObjectWrapper = (dis, obj, args)
+createObjectWrapper = (dis, obj, args) ->
     for f of obj
         if typeof obj[f] == 'function'
             objf = obj[f]


typo

typo

Leeds one…

--- app/data/locations/leedsone.cson
+++ app/data/locations/leedsone.cson
@@ -29,6 +29,6 @@
 eatinganddrinking: [
   "There's a Costa coffee stand immediately behind reception."
   "Kitchen areas are located on each floor, and have fridges, kettles and microwaves."
-  "Turn left out of the main entrance for the Crown Point shopping centre. There's a Boot's store, a small cafe upstaris in the Asda homeware store and a Subway fast food restaurant."
-  "Turn right out of the building and head towards the large silver sky high rise building (Bridgewater Place) to find a Tesco metro, Philpotts sandwich delicatessen and an oriental lunch time takeaway 'Juici Sushi'."
+  "Turn left out of the main entrance for the Crown Point shopping centre. There's a Boot's store, a small cafe upstairs in the Asda homeware store and a Subway fast food restaurant."
+  "Turn right out of the building and head towards the large silver sky high rise building (Bridgewater Place) to find a Tesco metro, Philpotts sandwich delicatessen and a lunch time takeaway 'Juici Sushi'."
 ]


disable understaffed mails and orga mails

--- both/methods/shift/shiftRequest.coffee
+++ both/methods/shift/shiftRequest.coffee
@@ -163,10 +163,10 @@
 					$pull: 'teams.$.participants': _id: userId
 					$addToSet: 'teams.$.pending': cancelledUser

-				if shift.scheduling == 'manual' and Meteor.isThisWeek(shift.date)
-					Meteor.call 'sendUnderstaffed', shiftId, teamId
-				else if shift.scheduling == 'manual'
-					Meteor.call 'sendToOrga', shift.projectId, 'teamCancel', shiftId, teamId
+				#if shift.scheduling == 'manual' and Meteor.isThisWeek(shift.date)
+				#	Meteor.call 'sendUnderstaffed', shiftId, teamId
+				#else if shift.scheduling == 'manual'
+				#	Meteor.call 'sendToOrga', shift.projectId, 'teamCancel', shiftId, teamId

 				Meteor.call 'cancelTeam', shiftId, teamId, 'missingParticipant'
 			else


Use right syntax

Use right syntax

--- buzzer.coffee
+++ buzzer.coffee
@@ -30,7 +30,7 @@
       return

     if data
-      if @lastOpened !== data.last_open
+      if @lastOpened isnt data.last_open
         @lastOpened = data.last_open
       else
         console.log('Already opened')


Edge adjacency computation.

Edge adjacency computation.

--- packages/landsofillusions-assets/documents/mesh/object/solver/polyhedron/edge.coffee
+++ packages/landsofillusions-assets/documents/mesh/object/solver/polyhedron/edge.coffee
@@ -31,6 +31,34 @@
         @segmentsMap[segment[0].x][segment[0].y][segment[1].x][segment[1].y] = null

     _.remove @segments, (segment) -> not segment.added
+
+    # Calculate adjacency.
+    @lines = []
+
+    segment.line = null for segment in @segments
+
+    pointEquals = (a, b) => a.x is b.x and a.y is b.y
+
+    for segment, startIndex in @segments when not segment.line
+      line = [segment]
+      segment.line = line
+      added = true
+
+      while added
+        added = false
+
+        for testSegmentIndex in [startIndex + 1...@segments.length]
+          testSegment = @segments[testSegmentIndex]
+          continue if testSegment.line
+
+          for lineSegment in line
+            if pointEquals(lineSegment[0], testSegment[0]) or pointEquals(lineSegment[0], testSegment[1]) or pointEquals(lineSegment[1], testSegment[0]) or pointEquals(lineSegment[1], testSegment[1])
+              line.push testSegment
+              testSegment.line = line
+              added = true
+              break
+
+      @lines.push line

   addSegment: (coordinates, startXOffset, startYOffset, endXOffset, endYOffset) ->
     start =


Translate missing translation

Translate missing translation

Closes #23

Signed-off-by: Santos Gallegos <c7d20f0b590f7c49e45e22db249ad9b63899f894@outlook.com>

--- def/es/settings.cson
+++ def/es/settings.cson
@@ -66,10 +66,11 @@
       }
       {
         _id: 'editor-settings-note'
-        html: 'These settings are related to text editing. Some of these
-               can be overriden on a per-language basis. Check language
-               settings by clicking its package card in the
-               Packages list.'
+        html: 'Estos ajustes están relacionados a la edición de texto. Algunas
+               de estas pueden ser sobre escritas para un lenguaje específico.
+               Accede a los ajustes de un lenguaje dando click en el botón
+               `Ajustes` en la lista de
+               Paquetes.'
       }
     ]
     controls: [


remove ipCookie from CurrentUser service

--- app/services/current-user.coffee
+++ app/services/current-user.coffee
@@ -1,6 +1,6 @@
 null

 ### @ngInject ###
-global.cobudgetApp.factory 'CurrentUser', (Records, ipCookie) ->
+global.cobudgetApp.factory 'CurrentUser', (Records) ->
   ->
     Records.users.find(global.cobudgetApp.currentUserId)


Social: add a sugar function for fetching group activity

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -16,6 +16,15 @@
         return callback err if err
         return callback null, @mapActivity result

+  fetchGroupActivity:(options, callback)->
+    @getCurrentGroup (group)=>
+      return callback {message: "Group doesnt have socialApiChannelId"} unless group.socialApiChannelId
+      options.id        = group.socialApiChannelId
+      options.groupName = group.slug
+      {SocialChannel} = KD.remote.api
+      SocialChannel.fetchActivity options, (err, result)=>
+        return callback err if err
+        return callback null, @mapActivity result

   mapActivity:(result)->
     messages = result.messageList


Social: Add account object ref into message data

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -58,8 +58,11 @@
     for message in messages
       m = new SocialMessage message.message
       m._id = message.message.id
+      m.account = {}
+      m.account.constructorName = "JAccount"
+      m.account._id = message.accountOldId
       m.meta = {}
-      m.meta.likes = message.interactions.length or 0
+      m.meta.likes = message.interactions?.like?.length or 0
       m.meta.createdAt = message.message.createdAt
       m.replies = message.replies
       m.repliesCount = message.replies.length or 0


Revert "Move-anims: Just in case the sprite does not load"

This reverts commit 6b27831cf42ef6ae606ead847dd94bbf41b1e5be.

--- client/app/js/views/battle_view.coffee
+++ client/app/js/views/battle_view.coffee
@@ -364,8 +364,7 @@
     $sprite.fadeOut =>
       $sprite.remove()
       @renderPokemon $spriteContainer, ($image) ->
-        $image.hide().fadeIn()
-      done()
+        $image.hide().fadeIn(done)

   changeWeather: (newWeather, done) =>
     $overlays = @$('.battle_overlays')


Fix method bind problems in phantomjs

Fix method bind problems in phantomjs

--- ObjectLogger.coffee
+++ ObjectLogger.coffee
@@ -6,10 +6,10 @@

     @callStack = []

-    @log.enter = @enter.bind(@, 'debug')
-    @log.fineEnter = @enter.bind(@, 'fine')
-    @log.return = @return.bind(@, 'debug')
-    @log.fineReturn = @return.bind(@, 'fine')
+    @log.enter = @bindMethod(@enter, 'debug')
+    @log.fineEnter = @bindMethod(@enter, 'fine')
+    @log.return = @bindMethod(@return, 'debug')
+    @log.fineReturn = @bindMethod(@return, 'fine')

     return @log

@@ -27,3 +27,20 @@
     if @callStack.length > 0
       methodName = @callStack[0]
       @log.setPrefix "#{@className}.#{methodName}:"
+
+
+  bindMethod: (method, level) ->
+    if typeof method.bind == 'function'
+      return method.bind(@, level)
+    else
+      try
+        return Function::bind.call(method, @, level)
+      catch e
+      # Missing bind shim or IE8 + Modernizr, fallback to wrapping
+        console.log 'Missing bind shim or IE8 + Modernizr, fallback to wrapping'
+        return (args...)=>
+          args.unshift(level)
+          Function::apply.apply method, [
+            @
+            args
+          ]


Fix discussion preview

Fix discussion preview

--- app/talk/discussion-preview.cjsx
+++ app/talk/discussion-preview.cjsx
@@ -17,20 +17,17 @@

   render: ->
     {params, discussion} = @props
+    comment = @props.comment or discussion.latest_comment

-
-        <PromiseRenderer catch={null} promise={talkClient.type('comments').get(discussion.links.comments[0])}>{(comment) =>
-          if comment.focus_id and (comment.focus_type is 'Subject')
-

-              <PromiseRenderer catch={null} promise={apiClient.type('subjects').get(comment.focus_id)}>{(subject) =>
-                <Thumbnail src={getSubjectLocation(subject).src} width={100} />
-              }</PromiseRenderer>
-

-          else
-            null
-        }</PromiseRenderer>
+        {if comment.focus_id and (comment.focus_type is 'Subject')
+

+            <PromiseRenderer catch={null} promise={apiClient.type('subjects').get(comment.focus_id)}>{(subject) =>
+              <Thumbnail src={getSubjectLocation(subject).src} width={100} />
+            }</PromiseRenderer>
+

+        }

           { if discussion.sticky}


add firstname sorting to shift participants

--- client/views/common/shift/shift.coffee
+++ client/views/common/shift/shift.coffee
@@ -96,6 +96,8 @@

 				if aSplit[aSplit.length-1] < bSplit[bSplit.length-1] then -1
 				else if aSplit[aSplit.length-1] > bSplit[bSplit.length-1] then 1
+				else if aSplit[0] < bSplit[0] then -1
+				else if aSplit[0] > bSplit[0] then 1
 				else 0

 Template.shift.onCreated ->


Update view helpers to work with my fixed brunch-handlebars plugin

Fixes handlebars when used with source maps.

--- app/lib/view-helper.coffee
+++ app/lib/view-helper.coffee
@@ -1,4 +1,5 @@
 Chaplin = require 'chaplin'
+Handlebars = require 'Handlebars' unless Handlebars?

 # Application-specific view helpers
 # http://handlebarsjs.com/#helpers


Changes to Atom plugins

Changes to Atom plugins

--- atom/atom/config.cson
+++ atom/atom/config.cson
@@ -94,7 +94,6 @@
   "cursor-history":
     excludeClosedBuffer: true
   "dark-mode":
-    ambientLight: true
     ambientLightThreshold: 9000000
     darkProfile: "pristine-ui one-dark-syntax"
   docblockr: {}
@@ -146,13 +145,6 @@
   "linter-csslint":
     csslintExecutablePath: "/usr/local/bin/csslint"
   "linter-eslint": {}
-  "linter-jscs":
-    esnext: true
-    executablePath: "/usr/local/bin/jscs"
-    onlyConfig: true
-  "linter-jshint":
-    disableWhenNoJshintrcFileInPath: true
-    jshintExecutablePath: "/usr/local/bin/jshint"
   "linter-scss-lint":
     executablePath: "/usr/local/bin/scss-lint"
   "linter-tidy":
@@ -189,9 +181,11 @@
   "prettier-atom":
     formatOnSaveOptions:
       enabled: true
+      isDisabledIfNoConfigFile: true
       isDisabledIfNotInPackageJson: true
+    prettierEslintOptions:
+      prettierLast: true
     prettierOptions:
-      semi: false
       singleQuote: true
     useEditorConfig: false
     useEslint: true
@@ -203,15 +197,16 @@
     indent: 2
     path: '''
       /usr/local/bin:/usr/local/sbin:/usr/local/git/bin:/usr/texbin:/Users/Felix/.rvm/gems/ruby-2.1.0/bin:/Users/Felix/.rvm/gems/ruby-2.1.0@global/bin:/Users/Felix/.rvm/rubies/ruby-2.1.0/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/Felix/.rvm/bin:/Users/Felix/.rvm/bin
-
+
     '''
   tabs:
-    alwaysShowTabBar: false
+    addNewTabsAtEnd: true
     enableVcsColoring: true
   "tool-bar":
     position: "Left"
   "tree-view":
     hideIgnoredNames: true
+    hideVcsIgnoredFiles: true
     showOnRightSide: true
   "vim-mode":
     useClipboardAsDefaultRegister: true


Candlestick Maker

Candlestick Maker

--- cards.coffee
+++ cards.coffee
@@ -363,6 +363,10 @@
 makeCard 'Bazaar', action, {
   cost: 5, actions: 2, cards: 1, coins: 1
   ai_playValue: (state, my) -> 835
+}
+makeCard 'Candlestick Maker', action, {
+  cost: 2, actions: 1, coinTokens: 1
+  ai_playValue: (state, my) -> 734
 }

 # Kingdom Victory cards


fix css

fix css

--- scripts/chat-logger.coffee
+++ scripts/chat-logger.coffee
@@ -53,9 +53,10 @@
       }

       p {
-        border-bottom: 1px solid
+        border-bottom: 1px solid;
+        border-bottom-color: #000000;
       }
-      p {
+      p:last-child {
         border: 0;
       }
     </style>


Safeguard in cases that the editor was not instantiated


Refactor writeFile and readFile to use isBinary better

--- scripts/gh-book/app.coffee
+++ scripts/gh-book/app.coffee
@@ -69,11 +69,12 @@

     # Github read/write and repo configuration

-    writeFile = (path, text, commitText) ->
-      session.getBranch().write path, text, commitText
+    writeFile = (path, text, commitText, isBinary) ->
+      if isBinary
+        text = btoa(text)
+      session.getBranch().write path, text, commitText, isBinary

-    readFile =       (path) -> session.getBranch().read       path
-    readBinaryFile = (path) -> session.getBranch().read       path, true # isBinary == true
+    readFile = (path, isBinary) -> session.getBranch().read path, isBinary
     readDir =        (path) -> session.getBranch().contents   path

@@ -84,17 +85,13 @@
       console.log method, path
       ret = null
       switch method
-        when 'read'
-          if model.isBinary
-            ret = readBinaryFile(path)
-          else
-            ret = readFile(path)
-        when 'update' then ret = writeFile(path, model.serialize(), 'Editor Save')
+        when 'read' then ret = readFile(path, model.isBinary)
+        when 'update' then ret = writeFile(path, model.serialize(), 'Editor Save', model.isBinary)
         when 'create'
           # Create an id if this model has not been saved yet
           id = _uuid()
           model.set 'id', id
-          ret = writeFile(path, model.serialize())
+          ret = writeFile(path, model.serialize(), model.isBinary)
         else throw "Model sync method not supported: #{method}"

       ret.done (value) => options?.success?(value)


dilbert: fix regex, add comment for /help

--- src/scripts/dilbert.coffee
+++ src/scripts/dilbert.coffee
@@ -1,7 +1,11 @@
+# Dilbert
+#
+# show me dilbert - gets the daily dilbert
+
 htmlparser = require "htmlparser"

 module.exports = (robot) ->
-  robot.respond /(show( me)?|fetch ( me)? )?dilbert/i, (msg) ->
+  robot.respond /((show|fetch)( me )?)?dilbert/i, (msg) ->
     dilbertRss msg, (url) ->
       msg.send url

@@ -14,6 +18,6 @@
         item = dom.items[0]
         match = item.description.match(dilbertRegexp)
         cb match[1] if match
-
+
       parser = new htmlparser.Parser(handler)
       parser.parseComplete(body)


Test coverage for going from modal to modal

--- source/javascripts/suite.js.coffee
+++ source/javascripts/suite.js.coffee
@@ -178,6 +178,20 @@
     $trigger.find('a.three.trigger').click()
     tester.verifyVisible()

+  test 'opening a second modal maintains shared overlay', ->
+    tester.createElements()
+    $('#modal').append($("trigger 2"))
+    $('a.trigger2').windoze({
+      container: '#modal2'
+      duration:
+        modal: 0
+        overlay: 0
+    })
+    tester.init().click()
+    $('#modal a').click()
+    $('#modal_layer, #modal2').shouldBe(':visible')
+    $('#modal').shouldNotBe(':visible')
+
   module 'Form Elements',
     setup: ->
       tester.createElements()


Fixing echo back bug in socket.io

Fixing echo back bug in socket.io

The logic for skipping sending an op to the client that originally sent
it was broken for socket.io. When agent.id was renamed to
agent.sessionId, this reference was missed.

This fixes the logic so that socket.io clients don't have their ops
echoed back to them anymore.

--- src/server/socketio.coffee
+++ src/server/socketio.coffee
@@ -79,7 +79,7 @@
         p "listener doc:#{docName} opdata:#{i opData} v:#{version}"

         # Skip the op if this socket sent it.
-        return if opData.meta?.source == client.id
+        return if opData.meta?.source == client.sessionId

         opMsg =
           doc: docName


missed a conditional timestamp

missed a conditional timestamp

--- resources/assets/lib/beatmap-discussions/discussion.coffee
+++ resources/assets/lib/beatmap-discussions/discussion.coffee
@@ -290,7 +290,7 @@
                 title: trans 'beatmaps.discussions.resolved'

         div className: "#{tbn}__text",
-          formatTimestamp @props.discussion.timestamp
+          formatTimestamp @props.discussion.timestamp if @props.discussion.timestamp?

   toggleCollapse: =>


re add status updates were causing - Maximum call stack size exceeded error

--- workers/social/lib/social/models/activity/index.coffee
+++ workers/social/lib/social/models/activity/index.coffee
@@ -280,7 +280,7 @@
       if err then return callback err

       {facets, to, limit} = options
-      limit or= 20
+      limit = 5 #bandage for now

       groupId = group._id
       groupName = group.slug
@@ -340,7 +340,7 @@

       {facets, to, limit} = options
-      limit or= 20
+      limit = 5 #bandage for now

       groupId = group._id
       groupName = group.slug


WFGH: fixed the defaults and fetching them

--- workers/social/lib/social/models/campaigns/wfgh.coffee
+++ workers/social/lib/social/models/campaigns/wfgh.coffee
@@ -71,9 +71,9 @@

       username = account?.profile?.nickname

-      {cap, prize, deadline} = campaign
+      {cap, prize, deadline} = campaign.content

-      cap      ?= 50000
+      cap      ?= 1000
       prize    ?= 10000
       deadline ?= new Date 1418626800000 # Mon, 15 Dec 2014 00:00:00 PDT


Changed modal redirect behaviour

Changed modal redirect behaviour

--- app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
+++ app/assets/javascripts/darkswarm/services/authentication_service.js.coffee
@@ -25,9 +25,7 @@
     isActive: Navigation.isActive

     close: ->
-      if location.pathname in ["/", "/checkout"]
-        Navigation.navigate "/"
-      else
+      if location.pathname in ["/register", "/register/auth"]
         Loading.message = t 'going_back_to_home_page'
         location.hash = ""
         location.pathname = "/"


[#65105556] hide dropdown on second click

--- app/assets/javascripts/trade/views/search_form/multi_select_view.js.coffee
+++ app/assets/javascripts/trade/views/search_form/multi_select_view.js.coffee
@@ -9,8 +9,10 @@
   templateName: 'trade/shipments/multi_select'

   click: ->
+    wasVisible = @.$('.popup-holder01').is(':visible')
     $('.popup-holder01').hide()
-    @.$('.popup-holder01').show()
+    unless wasVisible
+      @.$('.popup-holder01').show()

 Trade.MultiSelectButton = Ember.View.extend
   tagName: 'a'


IMPROVED a little more streamlining for childrenSize calc

--- source/Art/Engine/Core/EpochLayout/StateEpochLayout.coffee
+++ source/Art/Engine/Core/EpochLayout/StateEpochLayout.coffee
@@ -123,11 +123,13 @@
   ) ->
     return point0 unless children?.length > 0

-    tMin = lMin = bMax = rMax = 0
-    l = r = t = b = 0
-    first = true
+    bMax = rMax = 0

     if customComputeChildArea = element.getPendingChildArea()
+      tMin = lMin = 0
+      l = r = t = b = 0
+      first = true
+
       for child in children

         area = customComputeChildArea child, reusableRectForChildrenSizeCalc
@@ -148,21 +150,14 @@
           rMax = max r, rMax
           bMax = max b, bMax

+      sizeWithPadding (rMax - lMin), (bMax - tMin), currentPadding
+
     else
       for child in children
-
-        r = child.getPendingMaxXInParentSpace()
-        b = child.getPendingMaxYInParentSpace()
-
-        if first
-          first = false
-          rMax = r
-          bMax = b
-        else
-          rMax = max r, rMax
-          bMax = max b, bMax
-
-    sizeWithPadding (rMax - lMin), (bMax - tMin), currentPadding
+        rMax = max rMax, child.getPendingMaxXInParentSpace()
+        bMax = max bMax, child.getPendingMaxYInParentSpace()
+
+      sizeWithPadding rMax, bMax, currentPadding

   # NOTE: grid layout determines an area dedicated to each element.
   #   This area is passed to the element as-if it was the parent's full children-area
@@ -209,6 +204,7 @@
           child.getPendingCurrentSize().x

       offset += gridSize
+    null

   defaultWidthOfEachLine = (i, widthOfEachLine) -> widthOfEachLine[i]
   alignChildren = (state, parentSize, childrenSize) ->


Add space for highlight to work

Add space for highlight to work

--- src/databound.coffee
+++ src/databound.coffee
@@ -103,6 +103,7 @@
     _this = @

     # backend responds with:
+    #
     # ```javascript
     # {
     #   success: true,


Minor revisions

Minor revisions

--- client/app/Applications/Activity.kdapplication/widgets/widgetbutton.coffee
+++ client/app/Applications/Activity.kdapplication/widgets/widgetbutton.coffee
@@ -42,13 +42,13 @@
   viewAppended:->
     {items, delegate} = @getOptions()

-    for title, content of items
+    for own title, content of items
       @addSubView icon = new KDCustomHTMLView
         cssClass       : "#{@utils.slugify(content.type)}"
-        _type          : content.type
-        _title         : title
+        type          : content.type
+        title         : title
         click          : ->
-          delegate.changeTab @getOption("_type"), @getOption("_title")
+          delegate.changeTab @getOption("type"), @getOption("title")

       icon.setClass "hidden" if content.disabled


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/expirable.coffee
+++ src/expirable.coffee
@@ -9,6 +9,7 @@
   self.bind "update", ->
     if I.fadeOut
       log I.age
+      log I.duration
       log (I.age + 1 / I.duration)
       I.alpha = 1 - (I.age + 1 / I.duration)


coffee-script: fix incompatible code

coffee-script: fix incompatible code

--- workers/social/lib/social/models/payment/subscription.coffee
+++ workers/social/lib/social/models/payment/subscription.coffee
@@ -233,8 +233,7 @@

         { quantities } = pack

-        $set = (Object.keys quantities)
-          .reduce( (memo, key) =>
+        op = $set: (Object.keys quantities).reduce( (memo, key) =>
             memo["usage.#{ key }"] =
               (@usage[key] ? 0) + quantities[key] * multiplyFactor
             memo


[fix] More attempts at plugging memory leak; See filearts/plunker#49

--- assets/js/panes/catalogue.coffee
+++ assets/js/panes/catalogue.coffee
@@ -59,8 +59,10 @@
           $scope.markup = updater.parse($scope.clean = session.getActiveBuffer().content)
           $scope.markup.findAllDependencies()
           $scope.dirty = false
-
-        $timeout(recheck, 2000)
+
+      setInterval ->
+        $scope.$apply(recheck)
+      , 2000

       recheck()


fix ajax headers in authorization

fix ajax headers in authorization

--- app/authorization.coffee
+++ app/authorization.coffee
@@ -99,6 +99,8 @@
     !!@token

   @ajaxSettings: (params, defaults) ->
+    if params.headers
+      params.headers = $.extend({}, Spine.Ajax.defaults.headers, params.headers)
     $.extend({}, defaults, params)

   @ajax: (params) ->


VM stats are not fetched if VM is not running

--- app/modules/vm/index.coffee
+++ app/modules/vm/index.coffee
@@ -82,7 +82,7 @@

         prepareDiskData mountedIso

-        # get the RRDs every sec
+        # get the RRDs every 5 sec
         interval = $interval(
           () => $scope.refreshStats(VM.UUID)
           5000
@@ -135,6 +135,7 @@
       }

     $scope.refreshStats = (id) ->
+      return unless (get id)?.power_state is 'Running'
       return xo.vm.refreshStats id
         .then (result) ->
           result.cpuSeries = []


Add FIXME

Add FIXME


Removes outdated mapquest_api

Removes outdated mapquest_api

--- src/services/mapquest_api.coffee
+++ src/services/mapquest_api.coffee
@@ -1,34 +0,0 @@
-qs      = require 'querystring'
-request = require 'request'
-config  = require '../../lib/config'
-log     = require '../../lib/logging'
-
-class MapquestApi
-
-  constructor: (@apikey) ->
-    @
-
-  reverseGeocode: (lat, lon, limit, cb) ->
-    host   = 'www.mapquestapi.com'
-    path   = 'geocoding/v1/address'
-    params = qs.stringify {
-      lat: lat,
-      lng: lon,
-      maxResults: limit,
-      outFormat: 'json'
-    }
-    url     = "http://#{host}/#{path}?key=#{@apikey}&#{params}"
-    log.debug url
-    request url, (err, resp, body) =>
-      if !err && resp.statusCode == 200
-        try
-          body = JSON.parse body
-          cb body
-        catch error
-          cb undefined
-      else
-        cb undefined
-
-module.exports         = MapquestApi
-module.exports.default = new MapquestApi(config.apikeys.mapquest)
-


Fix untitled issue

Fix untitled issue

--- lib/file-info-view.coffee
+++ lib/file-info-view.coffee
@@ -19,7 +19,7 @@
     @subscribeToActiveItem()

     clickHandler = ->
-      atom.clipboard.write(@getActiveItem()?.getPath?())
+      atom.clipboard.write(@getActiveItem()?.getPath?() or 'untitled')
       setTimeout =>
         @newTooltip()
       , 2000
@@ -29,12 +29,12 @@

   newTooltip: ->
     @myTip?.dispose()
-    @myTip = atom.tooltips.add(this,
-      title: 'Copied: '+@getActiveItem()?.getPath?()
+    @myTip = atom.tooltips.add this,
+      title: 'Copied: '+(@getActiveItem()?.getPath?() or 'untitled')
       trigger: 'click'
       delay:
         show: 0
-    )
+

   subscribeToActiveItem: ->
     @modifiedSubscription?.dispose()


Set proper value to seconds if it passed 60

--- views/coffee/timer.coffee
+++ views/coffee/timer.coffee
@@ -2,6 +2,7 @@

 @start = (limit) ->
   window.startDate = new Date().getTime()
+  window.elapsedSeconds = 0
   window.seconds = 0
   window.minutes = 0
   window.limit = limit
@@ -13,16 +14,18 @@
   return

 timeCounter = ->
-  if seconds >= limit
+  if elapsedSeconds >= limit
     stop()
     return

   time = new Date().getTime() - startDate

-  window.seconds = parseInt(Math.floor(time / 100) / 10)
+  window.elapsedSeconds = parseInt(Math.floor(time / 100) / 10)

-  if seconds % 60 == 0
-    minutes += 1
+  allTheTime = elapsedSeconds
+  minutes = parseInt(allTheTime/60)
+  allTheTime -= minutes * 60
+  seconds = parseInt(allTheTime)

   document.getElementById('seconds').innerHTML = seconds
   document.getElementById('minutes').innerHTML = minutes


Bugfix with sharing from rendered view.

Bugfix with sharing from rendered view.


Benchmark moving to eof

Benchmark moving to eof

--- benchmark/benchmark-suite.coffee
+++ benchmark/benchmark-suite.coffee
@@ -42,17 +42,25 @@
         editor.backspace()

   describe "9000-line-file.", ->
-    fbenchmark "opening", 1, ->
+    benchmark "opening.", 1, ->
       editor.setBuffer new Buffer(require.resolve('fixtures/huge.js'))

-    describe "at-end.", ->
-      endPosition = null
-
+    describe "after-opening.", ->
       beforeEach ->
         editor.setBuffer new Buffer(require.resolve('fixtures/huge.js'))
+
+      benchmark "moving-to-eof.", 1, ->
         editor.moveCursorToBottom()
-        endPosition = editor.getCursorScreenPosition()
+        waitsFor (scrollComplete) ->
+          editor.scroller.on 'scroll', scrollComplete

-      benchmark "move-to-beginning-of-word", ->
-        editor.moveCursorToBeginningOfWord()
-        editor.setCursorScreenPosition(endPosition)
+      describe "at-eof.", ->
+        endPosition = null
+
+        beforeEach ->
+          editor.moveCursorToBottom()
+          endPosition = editor.getCursorScreenPosition()
+
+        benchmark "move-to-beginning-of-word", ->
+          editor.moveCursorToBeginningOfWord()
+          editor.setCursorScreenPosition(endPosition)


Show the message we got from loading a graph

--- src/lib/Graph.coffee
+++ src/lib/Graph.coffee
@@ -337,7 +337,7 @@
       exports.loadJSON definition, success
     catch e
       # TODO: Try AJAX GET
-      throw new Error "Failed to load graph #{file}"
+      throw new Error "Failed to load graph #{file}: #{e.message}"
     return
   require('fs').readFile file, "utf-8", (err, data) ->
     throw err if err


range will not implement getFormats

range will not implement getFormats

--- src/lib/range.coffee
+++ src/lib/range.coffee
@@ -1,15 +1,9 @@
-_ = require('lodash')
-
-
 class Range
   constructor: (@doc, @start, @end) ->

   equals: (range) ->
     return false unless range?
     return @doc == range.doc and @start == range.start and @end == range.end
-
-  getFormats: ->
-    return {}

   shift: (index, length) ->
     @start += length


Trying to address https://github.com/cs150bf/ever-notedown/issues/63

References:
    - http://docs.mathjax.org/en/latest/options/SVG.html
    - http://docs.mathjax.org/en/latest/reference/CSS-styles.html#css-style-objects

--- lib/mathjax-helper.coffee
+++ lib/mathjax-helper.coffee
@@ -189,10 +189,16 @@
     }
     SVG: {
       font: "Tex"
+      scale: 100
       undefinedFamily: "STIXGeneral, 'Arial Unicode MS', serif"
       linebreaks:
         automatic: false
         width: "75%"
+      #styles: {
+      #  ".MathJax_SVG, .MathJax_SVG_Display": {
+      #    "font-size": "100% !important"
+      #  }
+      #}
     }
     messageStyle: "none"
     showMathMenu: false


Very low chunk size for testing - temporary

--- web/service/upload.coffee
+++ web/service/upload.coffee
@@ -9,7 +9,7 @@
       target: router.controllers.uploadChunk.route()
       method: 'octet'
       # chunkSize: 4194304
-      chunkSize: 500000
+      chunkSize: 500
       # forceChunkSize: false
       forceChunkSize: true
       simultaneousUploads: 3


split utils in to separate namespaces to divide functionality more logically

--- src/lib/utils.coffee
+++ src/lib/utils.coffee
@@ -16,7 +16,7 @@
   # `value`.
   'i18n-content': (element, value, subMap) ->
     subs = i18nSubs element, value, subMap
-    element.innerHTML = utils.i18n value, subs
+    element.innerHTML = i18n.get value, subs

   # Replace the value of the properties and/or attributes of `element` with the
   # messages looked up for their corresponding values.
@@ -33,10 +33,10 @@
           obj = element
           obj = obj[path.shift()] while obj and path.length > 1
           if obj
-            obj[path] = utils.i18n value, subs
+            obj[path] = i18n.get value, subs
             i18nProcess element, subMap if path is 'innerHTML'
         else
-          element.setAttribute propName, utils.i18n propExpr, subs
+          element.setAttribute propName, i18n.get propExpr, subs
 # List of internationalization attributes/handlers available.
 i18nAttributes = []
 i18nAttributes.push key for own key of i18nHandlers
@@ -71,16 +71,49 @@

 utils = window.utils =

-  # Public functions
-  # ----------------
+  # Generate a unique key based on the current time and using a randomly
+  # generated hexadecimal number of the specified length.
+  keyGen: (separator = '.', length = 5) ->
+    parts  = []
+    # Populate the segment(s) to attempt uniquity.
+    parts.push new Date().getTime()
+    if length > 0
+      min = @repeat '1', '0', if length is 1 then 1 else length - 1
+      max = @repeat 'f', 'f', if length is 1 then 1 else length - 1
+      min = parseInt min, 16
+      max = parseInt max, 16
+      parts.push @random min max
+    # Convert segments to their hexadecimal (base 16) forms.
+    parts[i] = part.toString 16 for part, i in parts
+    # Join all segments and transform to upper case.
+    parts.join(separator).toUpperCase()

   # Retrieve the first entity/all entities that pass the specified `filter`.
   query: (entities, singular, filter) ->
     return entity for entity in entities when filter entity if singular
     entity for entity in entities when filter entity

-  # Data functions
-  # --------------
+  # Generate a random number between the `min` and `max` values provided.
+  random: (min, max) ->
+    Math.floor(Math.random() * (max - min + 1)) + min
+
+  # Repeat the string provided the specified number of times.
+  repeat: (str = '', repeatStr = str, count = 1) ->
+    if count isnt 0
+      # Repeat to the right if `count` is positive.
+      str += repeatStr for i in [1..count] if count > 0
+      # Repeat to the left if `count` is negative.
+      str = repeatStr + str for i in [1..count*-1] if count < 0
+    str
+
+# Storage setup
+# -------------
+
+store = window.store =
+
+  # Clear all keys from `localStorage`.
+  clear: ->
+    delete localStorage[key] for own key of localStorage

   # Determine whether or not the specified `keys` exist in `localStorage`.
   exists: (keys...) ->
@@ -111,6 +144,14 @@
       when 'object'
         @set key, @get(key) ? defaultValue for own key, defaultValue of keys
       when 'string' then @set keys, @get(keys) ? defaultValue
+
+  # For each of the specified `keys`, retrieve their value in `localStorage`
+  # and pass it, along with the key, to the `callback` function provided.
+  # If `callback` returns a value that is not `undefined`, then that value will
+  # be assigned to the key in `localStorage`. This functionality is very useful
+  # when just manipulating existing values but can be used in any case.
+  modify: (keys..., callback) ->
+    @set key, callback?(@get(key), key) ? @get key for key in keys

   # Remove the specified `keys` from `localStorage`.
   # If only one key is specified then the current value of that key is returned
@@ -153,87 +194,83 @@
         localStorage[keys] = if value? then JSON.stringify value else value
         oldValue

-  # For each of the specified `keys`, retrieve their value in `localStorage`
-  # and pass it, along with the key, to the `callback` function provided.
-  # If `callback` returns a value that is not `undefined`, then that value will
-  # be assigned to the key in `localStorage`. This functionality is very useful
-  # when just manipulating existing values but can be used in any case.
-  sync: (keys..., callback) ->
-    @set key, callback?(@get(key), key) ? @get key for key in keys
-
-  # Internationalization functions
-  # ------------------------------
-
-  # Convenient shorthand for `chrome.i18n.getMessage`.
-  i18n: ->
-    chrome.i18n.getMessage arguments...
+# Internationalization setup
+# --------------------------
+
+i18n = window.i18n =

   # Internationalize the specified attribute of all the selected elements.
-  i18nAttribute: (selector, attribute, value, subs) ->
+  attribute: (selector, attribute, value, subs) ->
     elements = document.querySelectorAll selector
     # Ensure the substitution string(s) are in an array.
     subs = [subs] if typeof subs is 'string'
-    for element in elements
-      element.setAttribute attribute, @i18n value, subs
+    element.setAttribute attribute, @get value, subs for element in elements

   # Internationalize the contents of all the selected elements.
-  i18nContent: (selector, value, subs) ->
+  content: (selector, value, subs) ->
     elements = document.querySelectorAll selector
     # Ensure the substitution string(s) are in an array.
     subs = [subs] if typeof subs is 'string'
-    element.innerHTML = @i18n value, subs for element in elements
-
-  # Perform all internationalization setup required for the current page.
-  i18nSetup: (subMap) ->
+    element.innerHTML = @get value, subs for element in elements
+
+  # Convenient shorthand for `chrome.i18n.getMessage`.
+  get: ->
+    chrome.i18n.getMessage arguments...
+
+  # Perform all internationalization substitutions available for the current
+  # page.
+  init: (subMap) ->
     i18nProcess document, subMap

-  # Log functions
-  # -------------
+# Logging setup
+# -------------
+
+log = window.log =

   # Output all failed `assertions`.
   assert: (assertions...) ->
-    console.assert assertion for assertion in assertions if @logging()
+    console.assert assertion for assertion in assertions if @enabled()

   # Create/increment a counter and output its current count for all `names`.
   count: (names...) ->
-    console.count name for name in names if @logging()
+    console.count name for name in names if @enabled()

   # Output all debug `entries`.
   debug: (entries...) ->
-    console.debug entry for entry in entries if @logging()
+    console.debug entry for entry in entries if @enabled()

   # Display an interactive listing of the properties of all `entries`.
   dir: (entries...) ->
-    console.dir entry for entry in entries if @logging()
+    console.dir entry for entry in entries if @enabled()
+
+  # Indicate whether or not logging is enabled.
+  enabled: ->
+    store.get 'log'

   # Output all error `entries`.
   error: (entries...) ->
-    console.error entry for entry in entries if @logging()
+    console.error entry for entry in entries if @enabled()

   # Output all informative `entries`.
   info: (entries...) ->
-    console.info entry for entry in entries if @logging()
+    console.info entry for entry in entries if @enabled()

   # Output all general `entries`.
-  log: (entries...) ->
-    console.log entry for entry in entries if @logging()
-
-  # Indicates whether or not logging is enabled.
-  logging: ->
-    @get 'log'
+  out: (entries...) ->
+    console.log entry for entry in entries if @enabled()

   # Start a timer for all `names`.
   time: (names...) ->
-    console.time name for name in names if @logging()
+    console.time name for name in names if @enabled()

   # Stop a timer and output its elapsed time in milliseconds for all `names`.
   timeEnd: (names...) ->
-    console.timeEnd name for name in names if @logging()
+    console.timeEnd name for name in names if @enabled()

   # Output a stack trace.
   trace: ->
-    console.trace() if @logging()
+    console.trace() if @enabled()

   # Output all warning `entries`.
   warn: (entries...) ->
-    console.warn entry for entry in entries if @logging()+    console.warn entry for entry in entries if @enabled()


Don't initialize js-lib until document.readyState is interactive.

--- js-library/app/js/loader/loader_common.coffee
+++ js-library/app/js/loader/loader_common.coffee
@@ -30,46 +30,52 @@
     content && el.appendChild(content)
     el

-  # Add styles
-  style_tag = mkEl 'style', null, document.createTextNode(style_code)
-  document.getElementsByTagName('head')[0].appendChild style_tag
+  onReady = ->
+    # Add styles
+    style_tag = mkEl 'style', null, document.createTextNode(style_code)
+    document.getElementsByTagName('head')[0].appendChild style_tag

-  #### Create iframe so jslib's namespace (window) doesn't collide with any content window.
-  jslib_jail_iframe = mkEl 'iframe', 'factlink-iframe'
+    #### Create iframe so jslib's namespace (window) doesn't collide with any content window.
+    jslib_jail_iframe = mkEl 'iframe', 'factlink-iframe'

-  # Wrapper for increased CSS specificity
-  outerWrapperEl = mkEl 'div', 'factlink-containment-wrapper', jslib_jail_iframe
+    # Wrapper for increased CSS specificity
+    outerWrapperEl = mkEl 'div', 'factlink-containment-wrapper', jslib_jail_iframe

-  document.body.appendChild outerWrapperEl
+    document.body.appendChild outerWrapperEl

-  window.FACTLINK_ON_CORE_LOAD = ->
-    for name in methods
-      do (name) ->
-        # don't return the value, as we can't do that when storing calls
-        window.FACTLINK[name] = ->
-          jslib_jail_iframe.contentWindow.FactlinkJailRoot[name](arguments...)
-          return
+    window.FACTLINK_ON_CORE_LOAD = -> #called from jail-iframe when core iframe is ready.
+      for name in methods
+        do (name) ->
+          # don't return the value, as we can't do that when storing calls
+          window.FACTLINK[name] = ->
+            jslib_jail_iframe.contentWindow.FactlinkJailRoot[name](arguments...)
+            return

-    delete window.FACTLINK_ON_CORE_LOAD
+      delete window.FACTLINK_ON_CORE_LOAD

-    for methodCall in storedMethodCalls
-      window.FACTLINK[methodCall.name](methodCall.arguments...)
-    storedMethodCalls = undefined
+      for methodCall in storedMethodCalls
+        window.FACTLINK[methodCall.name](methodCall.arguments...)
+      storedMethodCalls = undefined

-  jail_window = jslib_jail_iframe.contentWindow
-  jail_window.FactlinkConfig = window.FactlinkConfig
-  jail_window.FrameCss = frame_style_code
+    jail_window = jslib_jail_iframe.contentWindow
+    jail_window.FactlinkConfig = window.FactlinkConfig
+    jail_window.FrameCss = frame_style_code

-  #### Load iframe with script tag
-  jslib_jail_doc = jail_window.document
+    #### Load iframe with script tag
+    jslib_jail_doc = jail_window.document

-  jslib_jail_doc.open()
-  jslib_jail_doc.write '<!DOCTYPE html><title></title>'
-  jslib_jail_doc.close()
+    jslib_jail_doc.open()
+    jslib_jail_doc.write '<!DOCTYPE html><title></title>'
+    jslib_jail_doc.close()

-  script_tag = jslib_jail_doc.createElement 'script'
-  script_tag.appendChild(jslib_jail_doc.createTextNode(jslib_jail_code))
-  jslib_jail_doc.documentElement.appendChild(script_tag)
+    script_tag = jslib_jail_doc.createElement 'script'
+    script_tag.appendChild(jslib_jail_doc.createTextNode(jslib_jail_code))
+    jslib_jail_doc.documentElement.appendChild(script_tag)
+
+  if /^(interactive|complete)$/.test(document.readyState)
+    onReady()
+  else
+    document.addEventListener('DOMContentLoaded',onReady);

 jslib_jail_code = __INLINE_JS_PLACEHOLDER__


Change the condition that checks whether a user is allowed to submit or not

--- lib/model/proposal.coffee
+++ lib/model/proposal.coffee
@@ -68,7 +68,7 @@
 @Proposal._collection.allow
   insert: (userId, doc) ->
     # the user must be logged in, and the document must be owned by the user
-    userId and doc.speaker_ids == [userId]
+    userId and _.contains(doc.speaker_ids, userId)

   update: (userId, doc, fields, modifier) ->
     # Tags editable by moderator and admins


preventing empty groups from being broken on reordering

--- jsapp/xlform_model_view/view.surveyApp.coffee
+++ jsapp/xlform_model_view/view.surveyApp.coffee
@@ -284,9 +284,14 @@
           activate: sortable_activate_deactivate
           deactivate: sortable_activate_deactivate
         })
-      @formEditorEl.find('.group__rows').sortable({
+      group_rows = @formEditorEl.find('.group__rows')
+      group_rows.off 'mouseenter', '> .survey__row', @_preventSortableIfGroupTooSmall
+      group_rows.off 'mouseleave', '> .survey__row', @_preventSortableIfGroupTooSmall
+      group_rows.on 'mouseenter', '> .survey__row', @_preventSortableIfGroupTooSmall
+      group_rows.on 'mouseleave', '> .survey__row', @_preventSortableIfGroupTooSmall
+      group_rows.sortable({
           axis: "y"
-          # cancel: "button,div.add-row-btn,.well,ul.list-view,li.editor-message, .editableform, .row-extras"
+          cancel: '.js-cancel-sort, .js-cancel-group-sort'
           cursor: "move"
           distance: 5
           items: "> li"
@@ -299,7 +304,13 @@
           deactivate: sortable_activate_deactivate
         })
       ``
-
+    _preventSortableIfGroupTooSmall: (evt)->
+      $ect = $(evt.currentTarget)
+      if $ect.siblings('.survey__row').length is 0
+        if evt.type is 'mouseenter'
+          $ect.addClass('js-cancel-group-sort')
+        else
+          $ect.removeClass('js-cancel-group-sort')

     validateSurvey: ()->
       true


preventing event callbacks from returning false due to cs' implicit returns

--- jsapp/xlform_model_view/view.surveyApp.coffee
+++ jsapp/xlform_model_view/view.surveyApp.coffee
@@ -177,6 +177,7 @@
         @is_selecting = false
       else
         @deselect_all_rows()
+      return
     selectRow: (evt)->
       @is_selecting = true
       $et = $(evt.target)
@@ -206,6 +207,7 @@

         @questionSelect()
         @$('.js-blur-on-select-row').blur()
+      return

     select_group_if_all_items_selected: ($group) ->
       $rows = $group.find('.survey__row')


fix(onboarding): pass along accountId too

--- internal_packages/onboarding/lib/page-router-store.coffee
+++ internal_packages/onboarding/lib/page-router-store.coffee
@@ -49,7 +49,8 @@
     n1_id = encode(NylasEnv.config.get("updateIdentity"))
     email = encode(account.emailAddress)
     provider = encode(account.provider)
-    params = "?n=#{n1_id}&e=#{email}&p=#{provider}"
+    accountId = encode(account.id)
+    params = "?n=#{n1_id}&e=#{email}&p=#{provider}&a=#{accountId}"
     {shell} = require('electron')
     shell.openExternal("https://nylas.com/welcome#{params}", activate: false)


Cleanup

Cleanup

--- src/win32/constants.coffee
+++ src/win32/constants.coffee
@@ -5,6 +5,7 @@

   # windef.h
   @NULL: ref.NULL
+
   # winnt.h
   @STANDARD_RIGHTS_READ: 0x00020000
   @STANDARD_RIGHTS_WRITE: 0x00020000
@@ -14,7 +15,8 @@
   @KEY_ENUMERATE_SUB_KEYS: 0x0008
   @KEY_NOTIFY: 0x0010
   @KEY_CREATE_LINK: 0x0020
-  @KEY_READ: @STANDARD_RIGHTS_READ | @KEY_QUERY_VALUE | @KEY_ENUMERATE_SUB_KEYS | @KEY_NOTIFY
+  @KEY_READ: @STANDARD_RIGHTS_READ | @KEY_QUERY_VALUE |
+    @KEY_ENUMERATE_SUB_KEYS | @KEY_NOTIFY
   @KEY_WRITE: @STANDARD_RIGHTS_WRITE | @KEY_SET_VALUE | @KEY_CREATE_SUB_KEY
   @KEY_EXECUTE: @KEY_READ
   @KEY_ALL_ACCESS: @KEY_READ | @KEY_WRITE | @KEY_CREATE_LINK


Trim remove_delay down closer to transition duration

--- js-library/app/js/jail_iframe/classes/notification.coffee
+++ js-library/app/js/jail_iframe/classes/notification.coffee
@@ -9,7 +9,7 @@
     type_classes: 'fl-message-icon-time fl-message-success'

 in_screen_time = 3000
-removal_delay = 1000 # Should be larger than notification_transition_time
+removal_delay = 350 # Should be larger than notification_transition_time
 content = """


remove debug

remove debug

--- lib/psd/layer_mask.coffee
+++ lib/psd/layer_mask.coffee
@@ -29,9 +29,6 @@

     if @bitDepth == 16
       console.log('16 bit psd detected')
-      throwaway = @file.read(16)
-    else
-      console.log('8 bit psd detected')

     @parseLayers()
     @parseGlobalMask()


Require helpers before local modules

Require helpers before local modules

--- lib/skeleton/index.coffee
+++ lib/skeleton/index.coffee
@@ -5,12 +5,12 @@
 mkdirp = require 'mkdirp'
 colors = require 'colors'

+# Helpers
+require './helpers'
+
 # Local dependencies
 Template = require './template'
 OptionParser = require './option_parser'
-
-# Helpers
-require './helpers'

 # Main class
 class Skeleton


Hopefully a bit better naming.

Hopefully a bit better naming.

--- lib/typeresolution.coffee
+++ lib/typeresolution.coffee
@@ -24,19 +24,19 @@
 # In case it isn't able to resolve this *typeSpecification* object with
 # primitive types only, ends with an error (Boutique builds no symbol table,
 # so it can't resolve any possible inheritance).
-simplifyTypeSpecification = (typeSpecification, cb) ->
-  type = typeSpecification?.name?.name
+simplifyTypeSpecification = (typeSpec, cb) ->
+  type = typeSpec?.name?.name
   return cb null, null if not type  # no type? return null...

   ensurePrimitiveType type, (err) ->
     return cb err if err  # non-primitive type results in error
-    return cb null, {name: type} if (typeSpecification?.nestedTypes?.length or 0) < 1  # no nested types
+    return cb null, {name: type} if (typeSpec?.nestedTypes?.length or 0) < 1  # no nested types

     # just playing safe, this should be already ensured by MSON parser
     if type not in ['array', 'enum']
       return cb new Error "Nested types are allowed only for array and enum types."

-    nested = (typeName.name for typeName in typeSpecification.nestedTypes)
+    nested = (typeName.name for typeName in typeSpec.nestedTypes)
     async.map nested, ensurePrimitiveType, (err) ->
       return cb err if err  # again, non-primitive types result in error
       cb null, {name: type, nested}
@@ -101,15 +101,15 @@
 # primitive types only, ends with an error (Boutique builds no symbol table,
 # so it can't resolve any possible inheritance).
 resolveType = (node, cb) ->
-  typeSpecification = findTypeSpecification node
-  simplifyTypeSpecification typeSpecification, (err, spec) ->
+  typeSpec = findTypeSpecification node
+  simplifyTypeSpecification typeSpec, (err, simpleTypeSpec) ->
     if err
       cb err
-    else if not spec
+    else if not simpleTypeSpec
       resolveImplicitType node, (err, implicitType) ->
         cb err, name: implicitType
     else
-      cb null, spec
+      cb null, simpleTypeSpec

 module.exports = {


Disabled ajax tracking.

Disabled ajax tracking.

--- app/assets/javascripts/app/lib/app_init/track.js.coffee
+++ app/assets/javascripts/app/lib/app_init/track.js.coffee
@@ -58,6 +58,7 @@
     )

     # log ajax calls
+    ### disabled, only needed for debugging
     $(document).bind( 'ajaxComplete', ( e, request, settings ) =>

       # do not log ui requests
@@ -92,6 +93,7 @@
           }
         )
     )
+    ###

     $(window).bind(
       'beforeunload'


Safely wrap `Audio` and replace with a dummy if not defined.

--- app/assets/javascripts/lib/utils/audio_player.js.coffee
+++ app/assets/javascripts/lib/utils/audio_player.js.coffee
@@ -1,8 +1,10 @@
 class Essence.AudioPlayer
+
+  @Audio = window.Audio || -> { play: -> }

   # Plays an audio file.
   #
   # @param [String] file Absolute URL pointing to the audio file
   #
   @play: (file) ->
-    new Audio(file).play()
+    new @Audio(file).play()


Fix setNestedIndex() id replacer.

Fix setNestedIndex() id replacer.

--- app/assets/javascripts/ultimate/improves/form.js.coffee
+++ app/assets/javascripts/ultimate/improves/form.js.coffee
@@ -120,7 +120,7 @@
         [index, oldIndex] = index
       else
         oldIndex = '\\d*'
-      replacers['id'].push   [ (new RegExp "_#{nestedField}_#{oldIndex}_"),          "_#{nestedField}_#{index}_"  ]
+      replacers['id'].push   [ (new RegExp "_#{nestedField}_#{oldIndex}"),           "_#{nestedField}_#{index}"  ]
       replacers['name'].push [ (new RegExp "\\[#{nestedField}\\]\\[#{oldIndex}\\]"), "[#{nestedField}][#{index}]" ]
     ( if @is(':input') then @filter('[name]') else @find(':input[name]') ).map ->
       jInput = $ @


cliente's tipoId input is now smarter. This fixes #14

--- app/assets/javascripts/mixins/cliente_on_form_mixin.js.coffee
+++ app/assets/javascripts/mixins/cliente_on_form_mixin.js.coffee
@@ -47,17 +47,30 @@
 # chosen
   applyChosen: ->
     @$(".tiposIdsSelect").chosen disable_search: true
+    @observeChosen()

   observeChosen: (->
     $select = @$(".tiposIdsSelect")
-    tipoId = @get("tipoId")
-    tipoId = if @get("identificacion").length is 10 then "Cédula" else "RUC" if Ember.isEmpty(tipoId)
+    identificacion = @get("identificacion") || ""
+    tipoId = switch identificacion.length
+      when 10
+        "Cédula"
+      when 13
+        "RUC"
+      else
+        "Pasaporte - otro"
     $select.val tipoId
     $select.trigger "chosen:updated"
-  ).observes("tipoId")
+  ).observes("identificacion")

   destroyChosen: ->
     @$(".tiposIdsSelect").chosen("destroy")
+
+# actions
+  actions:
+    searchCliente: ->
+      # Bandango.ClienteSearchComponent.create().appendTo "body"
+      Bandango.ClienteSearchView.create(container: @get("container"), controller: @get("controller")).append()

 # inherited events
   didInsertElement: ->


Debug representative limit

Debug representative limit

--- app/assets/pg/representatives/representatives.state.js.coffee
+++ app/assets/pg/representatives/representatives.state.js.coffee
@@ -12,4 +12,4 @@
             'My representatives'
           assignments: (Restangular)->
             'ngInject'
-            Restangular.all('assignments').getList(limit: 100)
+            Restangular.all('assignments').getList(limit: 1000)


fix issue with database reconnect when there are a lot of pending queries

--- src/smc-hub/postgres-base.coffee
+++ src/smc-hub/postgres-base.coffee
@@ -543,12 +543,19 @@
         @concurrent_counter.labels('started').inc(1)
         try
             start = new Date()
-            if @_timeout_ms and @_timeout_delay_ms and @_connect_time and new Date() - @_connect_time > @_timeout_delay_ms
+            if @_timeout_ms and @_timeout_delay_ms
                 # Create a timer, so that if the query doesn't return within
                 # timeout_ms time, then the entire connection is destroyed.
                 # It then gets recreated automatically.  I tested
                 # and all outstanding queries also get an error when this happens.
-                timer = setTimeout((=>@_client?.emit('error', 'timeout')), @_timeout_ms)
+                timeout_error = =>
+                    # Only disconnect with timeout error if it has been sufficiently long
+                    # since connecting.   This way when an error is triggered, all the
+                    # outstanding timers at the moment of the error will just get ignored
+                    # when they fire (since @_connect_time is 0 or too recent).
+                    if @_connect_time and new Date() - @_connect_time > @_timeout_delay_ms
+                        @_client?.emit('error', 'timeout')
+                timer = setTimeout(timeout_error, @_timeout_ms)
             @_client.query opts.query, opts.params, (err, result) =>
                 if @_timeout_ms
                     clearTimeout(timer)


Fix missing recipients for encrypted post.

--- static/modules/chan.coffee
+++ static/modules/chan.coffee
@@ -16,7 +16,10 @@

     json = nacl.signPost text
     if dom('#form-encrypt')?.checked
-        try recipientKeys = getQuotedPublicKeys json.pubkey, text
+        try
+            recipientKeys = getQuotedPublicKeys json.pubkey, text
+        catch
+            return
         json.text = nacl.encryptPost recipientKeys, json.text, json.signature
         json.signature = 'ENCRYPTED'
     data.value = JSON.stringify json
@@ -31,11 +34,12 @@
     recipients = [myPublicKey]
     matches = text.match /(^| )>>(\d+)/gm

-    for match in matches
-        publicKey = dom('#id' + match.replace '>>', '')
-            .getAttribute 'data-pubkey'
-        if publicKey not in recipients
-            recipients.push publicKey
+    if matches
+        for match in matches
+            publicKey = dom('#id' + match.replace '>>', '')
+                .getAttribute 'data-pubkey'
+            if publicKey not in recipients
+                recipients.push publicKey

     if recipients.length < 2 and not confirm "No recipients found, only you will be able to read this.\nContinue?"
         throw new Error()


Fix typo.

Fix typo.

--- lms/static/coffee/src/discussion/utils.coffee
+++ lms/static/coffee/src/discussion/utils.coffee
@@ -270,7 +270,7 @@

   @abbreviateString: (text, minLength) ->
     # Abbreviates a string to at least minLength characters, stopping at word boundaries
-    if text.length<100
+    if text.length<minLength
       return text
     else
       while minLength < text.length && text[minLength] != ' '


Stop hiding native attachment selections

--- src/trix/config/embedded_styles.coffee
+++ src/trix/config/embedded_styles.coffee
@@ -55,12 +55,4 @@
   .trix-editor figure.attachment a.remove:hover {
     color: red;
   }
-
-  .trix-editor figure.attachment::selection, figure.attachment *::selection {
-    background-color: rgba(0, 0, 0, 0);
-  }
-
-  .trix-editor figure.attachment::-moz-selection, figure.attachment *::-moz-selection {
-    background-color: rgba(0, 0, 0, 0);
-  }
 """