[#121523735] Fix bug: Can't download documents with large number of cases.

This bug was present on current Chrome. Turned out that the 'download' dialog was using a data URI of the stringified JSON. Appeared to bang up against URI size limits. Converted to a blob URL.

--- src/code/views/download-dialog-view.coffee
+++ src/code/views/download-dialog-view.coffee
@@ -34,6 +34,10 @@
     s.replace /^\s+|\s+$/, ''

   download: (e) ->
+    makeBlobURL = (msg) ->
+      blob = new Blob([msg], {type: 'text/plain'})
+      window.URL.createObjectURL(blob)
+
     if @state.trimmedFilename.length > 0
       json = @props.content.getContent()
       if json and not @state.includeShareInfo
@@ -42,7 +46,7 @@
         delete json.isUnshared
         # CODAP moves the keys into its own namespace
         delete json.metadata.shared if json.metadata?.shared?
-      e.target.setAttribute 'href', "data:application/json,#{encodeURIComponent(JSON.stringify json)}"
+      e.target.setAttribute 'href', makeBlobURL(JSON.stringify(json))
       @props.close()
     else
       e.preventDefault()


Remove bogus serialization bit

Remove bogus serialization bit

--- lib/ide-haskell-hasktags.coffee
+++ lib/ide-haskell-hasktags.coffee
@@ -95,6 +95,3 @@
   deactivate: ->
     @disposables.dispose()
     @tags.destroy()
-
-  serialize: ->
-    ideHaskellHasktagsViewState: @ideHaskellHasktagsView.serialize()


Ensure view_mode is `grid` while I kill this

--- lib/middleware/view_mode.coffee
+++ lib/middleware/view_mode.coffee
@@ -1,6 +1,3 @@
-# Set view mode from cookie
-#
 module.exports = (req, res, next) ->
-  mode = if (req.user?.isPremium() and req.cookies['view_mode']?) then req.cookies['view_mode'] else 'grid'
-  res.locals.view_mode = res.locals.sd.VIEW_MODE = mode
-  next()+  res.locals.view_mode = res.locals.sd.VIEW_MODE = 'grid'
+  next()


Better code

Better code

--- data.coffee
+++ data.coffee
@@ -17,9 +17,7 @@
         @update()._node
       else
         @_node
-    set: (newVal) ->
-      unless EJSON.equals @_node, newVal
-        @_node = newVal
+    set: (newVal) -> @_node = newVal unless EJSON.equals @_node, newVal

   ###
   @locus Server


Troubleshoot: fixes after callling system health check a few times, bongo functions cannot be called bug

--- workers/social/lib/social/models/systemstatus.coffee
+++ workers/social/lib/social/models/systemstatus.coffee
@@ -123,6 +123,7 @@
   @checkRealtimeUpdates = secure (client, callback) ->
     {connection: {delegate}} = client
     delegate.sendNotification "healthCheck"
+    callback result:1

   @sendFeedback = secure (client, options, callback) ->
     {connection: {delegate}} = client


Don't search when query is empty.

Don't search when query is empty.

--- src/views/search-input.coffee
+++ src/views/search-input.coffee
@@ -46,9 +46,11 @@

         search: (e) ->
             e.stopPropagation()
+            e.preventDefault()
+            if @isEmpty()
+                return
             @$searchEl.typeahead 'close'
             @executeQuery()
-            e.preventDefault()

         isEmpty: () ->
             query = @getInputText()


Remove redundant fragment

Remove redundant fragment

--- resources/assets/coffee/react/beatmap-discussions/main.coffee
+++ resources/assets/coffee/react/beatmap-discussions/main.coffee
@@ -131,40 +131,40 @@
             value: @discussions()
             el BeatmapsContext.Provider,
               value: @beatmaps()
-              el React.Fragment, null,
-                if @state.currentMode == 'reviews'
-                  el NewReview,
-                    beatmapset: @state.beatmapset
-                    beatmaps: @beatmaps()
-                    currentBeatmap: @currentBeatmap()
-                    currentDiscussions: @currentDiscussions()
-                    currentUser: @state.currentUser
-                    pinned: @state.pinnedNewDiscussion
-                    setPinned: @setPinnedNewDiscussion
-                    stickTo: @modeSwitcherRef
-                else
-                  el NewDiscussion,
-                    beatmapset: @state.beatmapset
-                    currentUser: @state.currentUser
-                    currentBeatmap: @currentBeatmap()
-                    currentDiscussions: @currentDiscussions()
-                    innerRef: @newDiscussionRef
-                    mode: @state.currentMode
-                    pinned: @state.pinnedNewDiscussion
-                    setPinned: @setPinnedNewDiscussion
-                    stickTo: @modeSwitcherRef
-                    autoFocus: @focusNewDiscussion
-
-                el Discussions,
+
+              if @state.currentMode == 'reviews'
+                el NewReview,
                   beatmapset: @state.beatmapset
+                  beatmaps: @beatmaps()
                   currentBeatmap: @currentBeatmap()
                   currentDiscussions: @currentDiscussions()
-                  currentFilter: @state.currentFilter
                   currentUser: @state.currentUser
+                  pinned: @state.pinnedNewDiscussion
+                  setPinned: @setPinnedNewDiscussion
+                  stickTo: @modeSwitcherRef
+              else
+                el NewDiscussion,
+                  beatmapset: @state.beatmapset
+                  currentUser: @state.currentUser
+                  currentBeatmap: @currentBeatmap()
+                  currentDiscussions: @currentDiscussions()
+                  innerRef: @newDiscussionRef
                   mode: @state.currentMode
-                  readPostIds: @state.readPostIds
-                  showDeleted: @state.showDeleted
-                  users: @users()
+                  pinned: @state.pinnedNewDiscussion
+                  setPinned: @setPinnedNewDiscussion
+                  stickTo: @modeSwitcherRef
+                  autoFocus: @focusNewDiscussion
+
+              el Discussions,
+                beatmapset: @state.beatmapset
+                currentBeatmap: @currentBeatmap()
+                currentDiscussions: @currentDiscussions()
+                currentFilter: @state.currentFilter
+                currentUser: @state.currentUser
+                mode: @state.currentMode
+                readPostIds: @state.readPostIds
+                showDeleted: @state.showDeleted
+                users: @users()

       el BackToTop


Use new css modifier toggle

Use new css modifier toggle

--- resources/assets/coffee/react/beatmap-discussions/post.coffee
+++ resources/assets/coffee/react/beatmap-discussions/post.coffee
@@ -13,6 +13,7 @@
 import Editor from 'beatmap-discussions/editor'
 import { BeatmapsContext } from 'beatmap-discussions/beatmaps-context'
 import { DiscussionsContext } from 'beatmap-discussions/discussions-context'
+import { classWithModifiers } from 'utils/css'

 el = React.createElement

@@ -55,11 +56,11 @@

   render: =>
-    topClasses = "#{bn} #{bn}--#{@props.type}"
-    if @state.editing
-      topClasses += " #{bn}--editing"
-    topClasses += " #{bn}--deleted" if @props.post.deleted_at?
-    topClasses += " #{bn}--unread" if !@props.read && @props.type != 'discussion'
+    topClasses = classWithModifiers bn,
+      "#{@props.type}": true
+      deleted: @props.post.deleted_at?
+      editing: @state.editing
+      unread: !@props.read && @props.type != 'discussion'

     userGroup = if @isOwner() then mapperGroup else @props.user.groups[0]


Client: Activity: Added handleAddChannelButtonClick to open create new channel modal

--- client/app/lib/components/sidebarsection/index.coffee
+++ client/app/lib/components/sidebarsection/index.coffee
@@ -20,6 +20,10 @@
     @setState isModalOpen: no

+  handleAddChannelButtonClick: (event) ->
+
+    kd.utils.stopDOMEvent event
+    @setState isModalOpen: yes

   renderAddChannelModal: ->


landing: root route goes to login directly

--- client/landing/site.landing/coffee/core/routes.coffee
+++ client/landing/site.landing/coffee/core/routes.coffee
@@ -12,7 +12,8 @@

     # root is home if group is koding
     if groupName is 'koding'
-      return router.openSection 'Home', null, null, (app)->
+      return router.openSection 'Login', null, null, (app)->
+        app.getView().animateToForm 'login'
         app.handleQuery options


Add likeCount and likeLink to commentListViewItem so we can like almost everything right now

--- client/landing/app/CommonViews/comments/commentlistitemview.coffee
+++ client/landing/app/CommonViews/comments/commentlistitemview.coffee
@@ -59,6 +59,69 @@
           KDEventTypes       : "click"
           listenedToInstance : @deleteLink
           callback           : => @confirmDeleteComment data
+
+    @likeCount    = new ActivityLikeCount
+      tooltip     :
+        gravity   : "se"
+        title     : ""
+        engine    : "tipsy" # We should force to use tipsy because
+                            # for now only tipsy supports tooltip updates
+      attributes  :
+        href      : "#"
+        title     : "Click to view..."
+      click       : =>
+        if data.meta.likes > 0 # 3
+          data.fetchLikedByes {},
+            sort  : timestamp : -1
+            , (err, likes) =>
+              new FollowedModalView {title:"Members who liked #{data.body}"}, likes
+      , data
+
+    @likeCount.on "countChanged", (count) =>
+      @updateLikeState yes
+
+    @likeLink     = new ActivityActionLink
+
+  updateLikeState:(checkIfILiked = no)->
+
+    data = @getData()
+
+    if data.meta.likes is 0
+      @likeLink.updatePartial "Like"
+      return
+
+    data.fetchLikedByes {},
+      limit : if checkIfILiked then data.meta.likes else 3
+      sort  : timestamp : -1
+
+      , (err, likes) =>
+
+        peopleWhoLiked   = []
+
+        if likes
+          if checkIfILiked
+            {_id}       = KD.whoami()
+            likedBefore = likes.filter((item)-> item._id is _id).length > 0
+
+          likes.forEach (item)=>
+            if peopleWhoLiked.length < 3
+              {firstName, lastName} = item.profile
+              peopleWhoLiked.push "" + firstName + " " + lastName + ""
+            else return
+
+          if data.meta.likes is 1
+            tooltip = peopleWhoLiked[0]
+          else if data.meta.likes is 2
+            tooltip = peopleWhoLiked[0] + " and " + peopleWhoLiked[1]
+          else if data.meta.likes is 3
+            tooltip = peopleWhoLiked[0] + ", " + peopleWhoLiked[1] + " and " + peopleWhoLiked[2]
+          else
+            tooltip = peopleWhoLiked[0] + ", " + peopleWhoLiked[1] + " and " + (data.meta.likes - 2) + " more."
+
+          @likeCount.updateTooltip {title: tooltip }
+
+          if checkIfILiked
+            @likeLink.updatePartial if likedBefore then "Unlike" else "Like"

   render:->
     if @getData().getAt 'deletedAt'


One forgotten console.log, ruining MSIE 8...

--- static/script/settlers.coffee
+++ static/script/settlers.coffee
@@ -19,7 +19,6 @@
         url:                    '/confirm_trumpet'
         handlers:
           h200:                 (response, ajax) ->
-            console.log 'hiding trumpet'
             _trumpet.hide()
             window.hlib.MESSAGE.hide()


Revert "bug fix for adding a included_manifest."

This reverts commit f540ccba04c59c125c6ca23964050bbd0901bb6f.

--- client/templates/manifestsBrowser/manifestForm/manifestForm.coffee
+++ client/templates/manifestsBrowser/manifestForm/manifestForm.coffee
@@ -106,7 +106,7 @@
 	field = id.replace(/^select_(.*)_field$/, '$1')
 	if field?
 		$('#' + id).typeahead('val', '')
-		prepend_to_active_manifest field, datum.value
+		add_to_active_manifest_sorted field, datum.value


production/static builds break with react-hot

--- lib/utils/webpack.config.coffee
+++ lib/utils/webpack.config.coffee
@@ -109,12 +109,12 @@
           {
             test: /\.jsx?$/,
             exclude: /(node_modules|bower_components)/,
-            loaders: ['react-hot', 'babel']
+            loaders: ['babel']
           }
           {
             test: /\.js?$/,
             exclude: /(node_modules|bower_components)/,
-            loaders: ['react-hot', 'babel']
+            loaders: ['babel']
           }
           { test: /\.less/, loaders: ['css', 'less']},
           { test: /\.coffee$/, loader: 'coffee' }
@@ -138,12 +138,12 @@
           {
             test: /\.jsx?$/,
             exclude: /(node_modules|bower_components)/,
-            loaders: ['react-hot', 'babel']
+            loaders: ['babel']
           }
           {
             test: /\.js?$/,
             exclude: /(node_modules|bower_components)/,
-            loaders: ['react-hot', 'babel']
+            loaders: ['babel']
           }
           { test: /\.less/, loaders: ['style', 'css', 'less']},
           { test: /\.coffee$/, loader: 'coffee' }


Fixed capitalization

Fixed capitalization

--- core/app/backbone/views/activities/activity_item_view.coffee
+++ core/app/backbone/views/activities/activity_item_view.coffee
@@ -31,11 +31,11 @@
   _translatedAction: ->
     switch @model.get('action')
       when "believes"
-        Factlink.global.t.fact_believe_past_singular_action_about
+        Factlink.Global.t.fact_believe_past_singular_action_about
       when "believes"
-        Factlink.global.t.fact_disbelieve_past_singular_action_about
+        Factlink.Global.t.fact_disbelieve_past_singular_action_about
       when "believes"
-        Factlink.global.t.fact_doubt_past_singular_action_about
+        Factlink.Global.t.fact_doubt_past_singular_action_about

 class FollowedUserView extends ActivityItemView
   tagName: 'span'


change tests

change tests

--- test/basic-test.coffee
+++ test/basic-test.coffee
@@ -18,35 +18,19 @@

 	describe 'native modules', ->

-		it 'should build "printer" for as-0.17.2 ia32', (done) ->
-			aspm.installModule 'printer',
-				quiet: yes
+		it 'should build "sqlite3" for as-0.17.2 ia32', (done) ->
+			aspm.installModule 'sqlite3',
+				#quiet: yes
 				target: '0.17.2',
 				arch: 'ia32',
 			, (err) ->
 				done(err)

-		it 'should build "printer" for as-0.17.2 x64', (done) ->
-			aspm.installModule 'printer',
-				quiet: yes
+		it 'should build "sqlite3" for as-0.17.2 x64', (done) ->
+			aspm.installModule 'sqlite3',
+				#quiet: yes
 				target: '0.17.2',
 				arch: 'x64',
-			, (err) ->
-				done(err)
-
-		it 'should build "printer" for as-0.19.5 ia32', (done) ->
-			aspm.installModule 'printer',
-				quiet: yes
-				target: '0.19.5',
-				arch: 'ia32',
-			, (err) ->
-				done(err)
-
-		it 'should build "sqlite3" for as-0.17.2 ia32', (done) ->
-			aspm.installModule 'sqlite3',
-				quiet: yes
-				target: '0.17.2',
-				arch: 'ia32',
 			, (err) ->
 				done(err)


fix some import issues

fix some import issues

--- library/semantic/flavour.coffee
+++ library/semantic/flavour.coffee
@@ -23,7 +23,8 @@
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ###

-{GoogleFonts} = "../exposure/fonts"
+{GoogleFonts} = require "../exposure/fonts"
+{Preflight} = require "../membrane/preflight"

 # This is an abstract compound that is intended for the services to
 # be composed in. It customizes a hosting service to include all the


pass in firebase and mongodb to allow for user authenticated api requests on dobi dev server

--- lib/cli.coffee
+++ lib/cli.coffee
@@ -5,6 +5,7 @@
 coffeelint = require 'coffeelint'
 colors = require 'colors'
 columnify = require 'columnify'
+config = require '/u/config/dobi-server'
 clipboard = require('copy-paste').noConflict()
 crypto = require 'crypto'
 extend =  require 'node.extend'
@@ -148,8 +149,8 @@
         next {}

 saveUserConfig = (data, next) ->
-  config = JSON.stringify data
-  fs.writeFile USER_CONFIG_PATH, config, 'utf8', (err) ->
+  data = JSON.stringify data
+  fs.writeFile USER_CONFIG_PATH, data, 'utf8', (err) ->
     exit 'unable to write user config' if err
     next()

@@ -693,18 +694,17 @@

           # update config
           config_path = path.join dest, 'config.cson'
-          config = CSON.parseFileSync config_path
-          config.id = id
-          config.version = version
-          config.author = {name: user.name, email: user.email}
-          config.developers = {}
-          config.developers[user.admin_uid] = 'admin'
-          config = CSON.stringifySync(config).replace /\n\n/g, '\n'
-          fs.writeFileSync config_path, config
+          user_config = CSON.parseFileSync config_path
+          user_config.id = id
+          user_config.version = version
+          user_config.author = {name: user.name, email: user.email}
+          user_config.developers = {}
+          user_config.developers[user.admin_uid] = 'admin'
+          user_config = CSON.stringifySync(config).replace /\n\n/g, '\n'
+          fs.writeFileSync config_path, user_config

           # done
           exit 'package created successfully'
-

   # deploy an app
   when 'deploy'
@@ -937,6 +937,8 @@
     app.use express.methodOverride()
     app.use express.cookieParser()
     app.use dobi {
+      firebase: config.firebase
+      mongodb: config.mongo
       pkg_dir: path.join workspace, 'pkg'
     }
     app.use app.router


[grunt] do not enforce absolute url in `page.url` with leading `/`

--- tasks/grunt-nunjucks-2-html.coffee
+++ tasks/grunt-nunjucks-2-html.coffee
@@ -475,7 +475,7 @@

           data.page.locale     = currentLocale
           data.page.rtl        = _.find(taskConfig.i18n.locales, { locale: currentLocale }).rtl
-          data.page.url        = if pagedir == '.' then '/' else '/' + pagedir
+          data.page.url        = if pagedir == '.' then '' else pagedir
           data.page.breadcrumb = if pagedir == '.' then ['.'] else pagedir.split('/')
           data.page.basename   = path.basename(pagepath, path.extname(pagepath))
           data.page.dirname    = pagedirname


fixed bracket issue

fixed bracket issue

--- dkobo/koboform/static/js/xlform/view.templates.coffee
+++ dkobo/koboform/static/js/xlform/view.templates.coffee
@@ -81,7 +81,7 @@

             #{survey.settings.get("form_title")}

-
[#{survey.settings.get("form_id")}]

+
#{survey.settings.get("form_id")}

         </hgroup>


add metric for pending updates queue

add metric for pending updates queue

--- services/document-updater/app/coffee/RealTimeRedisManager.coffee
+++ services/document-updater/app/coffee/RealTimeRedisManager.coffee
@@ -5,6 +5,7 @@
 logger = require('logger-sharelatex')
 os = require "os"
 crypto = require "crypto"
+metrics = require('./Metrics')

 HOST = os.hostname()
 RND = crypto.randomBytes(4).toString('hex') # generate a random key for this process
@@ -27,6 +28,8 @@
 				catch e
 					return callback e
 				updates.push update
+				# record metric for updates removed from queue
+				metrics.summary "redis.pendingUpdates", jsonUpdate.length, {status: "pop"}
 			callback error, updates

 	getUpdatesLength: (doc_id, callback)->


! move setOuset to move

! move setOuset to move

--- lib/map.coffee
+++ lib/map.coffee
@@ -11,7 +11,7 @@
     @viewportWidth  = options['width'];
     @viewportHeight = options['height'];
     @setDimensions(@fieldSize);
-    @mapLayer.setOutset(options['width'], options['height'], @fieldSize);
+    @mapLayer.setOutset(@viewportWidth, @viewportHeight, @fieldSize);

   setDimensions: (fieldSize) =>
     @fieldWidth  = Math.floor(@viewportWidth  / fieldSize) + 2;
@@ -24,6 +24,7 @@

   move: (fieldSize, oldWidth, oldHeight) =>
     @centerDataPosition(oldWidth, oldHeight);
+    @mapLayer.setOutset(@viewportWidth, @viewportHeight, fieldSize);
     ax = -(@data.rx + 1) * fieldSize + @mapLayer.outsetX; # +1 begin outside of viewport
     ay = -(@data.ry + 1) * fieldSize + @mapLayer.outsetY; # +1 begin outside of viewport
     @mapLayer.mapMovedTo(ax, ay);
@@ -81,7 +82,6 @@
     oldHeight = @fieldHeight;
     @mapLayer.scale(newScale);
     @setDimensions(@fieldSize * newScale);
-    @mapLayer.setOutset(@viewportWidth, @viewportHeight, @fieldSize * newScale);
     @move(@fieldSize * newScale, oldWidth, oldHeight);
     @create();


disabled shift key for now

disabled shift key for now

--- public/dreamcatcher/controllers/ib_manager_controller.coffee
+++ public/dreamcatcher/controllers/ib_manager_controller.coffee
@@ -7,7 +7,8 @@
     @imageCookie = new Dreamcatcher.Classes.CookieHelper("imagebank")
     @populateLists()
     @createUploader()
-    @enableShiftKey()
+    @shiftDown = true
+    #@enableShiftKey()

     album = $.query.get 'album'
     if album.length > 0
@@ -19,9 +20,11 @@
   enableShiftKey: ->
     @shiftDown = false
     $(document).keydown (event) =>
-      @shiftDown = event.keyCode is 16
+      @shiftDown = true if event.shiftKey
+      @ctrlDown = true if event.ctrlDpwn
     $(document).keyup (event) =>
-      @shiftDown = false if event.keyCode is 16
+      @shiftDown = false if event.shiftKey
+      @ctrlDown = false if event.ctrlDown

   ## [ IMAGE FILE UPLOADER ] ##


:lipstick: Move comment to next line

:lipstick: Move comment to next line

--- lib/image-editor-status-view.coffee
+++ lib/image-editor-status-view.coffee
@@ -28,7 +28,8 @@
       view = atom.workspaceView.getActiveView()
       if view.loaded
         @getImageSize(view)
-      else # wait for image to load before getting originalWidth and originalHeight
+      else
+        # Wait for image to load before getting originalWidth and originalHeight
         view.image.load =>
           # Make sure view is still active since load is async
           @getImageSize(view) if view is atom.workspaceView.getActiveView()


AcceptedInvitationsView: Override from PendingInvitations and set statusType.

--- client/admin/lib/views/invitations/acceptedinvitationsview.coffee
+++ client/admin/lib/views/invitations/acceptedinvitationsview.coffee
@@ -1,11 +1,13 @@
-kd                    = require 'kd'
-KDView                = kd.View
-TeamMembersCommonView = require '../members/teammemberscommonview'
+kd                     = require 'kd'
+KDView                 = kd.View
+PendingInvitationsView = require './pendinginvitationsview'

-module.exports = class AcceptedInvitationsView extends TeamMembersCommonView
+module.exports = class AcceptedInvitationsView extends PendingInvitationsView

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

+    options.statusType = 'accepted'
+
     super options, data


groups invitations: change request invite text

--- client/app/Applications/Groups.kdapplication/AppController.coffee
+++ client/app/Applications/Groups.kdapplication/AppController.coffee
@@ -256,7 +256,7 @@
     if isApproval
       title   = 'Request Access'
       content = 'Membership to this group requires administrative approval.'
-      success = 'Access has been requested!'
+      success = "Thanks! You'll receive an email an email shortly."
     else
       title   = 'Request an Invite'
       content = 'Membership to this group requires an invitation.'
@@ -271,7 +271,7 @@
       buttons        :
         request      :
           title      : title
-          loader     :
+          loader     :
             color    : "#ffffff"
             diameter : 12
           style      : 'modal-clean-green'


viewer opens files with https now

viewer opens files with https now

--- client/app/Applications/Viewer.kdapplication/AppController.coffee
+++ client/app/Applications/Viewer.kdapplication/AppController.coffee
@@ -15,7 +15,7 @@
         return cb true  unless path
         path = FSHelper.plainPath path
         publicPath = path.replace \
-          ////home/(.*)/Web/(.*)///, "http://$1.#{KD.config.userSitesDomain}/$2"
+          ////home/(.*)/Web/(.*)///, "https://$1.#{KD.config.userSitesDomain}/$2"
         cb publicPath isnt path, {path: publicPath}

       failure    : (options, cb)->


Remove verticals_tags.coffee test

Remove verticals_tags.coffee test

--- client/apps/edit/components/admin/test/verticals_tags.test.coffee
+++ client/apps/edit/components/admin/test/verticals_tags.test.coffee
@@ -1,162 +0,0 @@
-_ = require 'underscore'
-benv = require 'benv'
-sinon = require 'sinon'
-{ resolve } = require 'path'
-React = require 'react'
-ReactDOM = require 'react-dom'
-Backbone = require 'backbone'
-ReactDOMServer = require 'react-dom/server'
-ReactTestUtils = require 'react-addons-test-utils'
-r =
-  find: ReactTestUtils.scryRenderedDOMComponentsWithClass
-  simulate: ReactTestUtils.Simulate
-fixtures = require '../../../../../../test/helpers/fixtures.coffee'
-Article = require '../../../../../models/article.coffee'
-Vertical = require '../../../../../models/vertical.coffee'
-Verticals = require '../../../../../collections/verticals.coffee'
-
-describe 'AdminVerticalsTags', ->
-
-  beforeEach (done) ->
-    benv.setup =>
-      benv.expose
-        $: benv.require 'jquery'
-        Bloodhound: (Bloodhound = sinon.stub()).returns(
-          initialize: ->
-          ttAdapter: ->
-        )
-        _: benv.require 'underscore'
-      window.jQuery = $
-      window.matchMedia = sinon.stub().returns({
-        matches: sinon.stub()
-      })
-      $.fn.typeahead = sinon.stub()
-      @AdminVerticalsTags = benv.require resolve __dirname, '../verticals_tags/editorial.coffee'
-      @AdminVerticalsTags.__set__ 'sd', {
-        API_URL: 'http://localhost:3005/api'
-        CURRENT_CHANNEL: id: '123'
-        USER: access_token: ''
-      }
-      AutocompleteList = benv.require resolve __dirname, '../../../../../components/autocomplete_list/index.coffee'
-      AutocompleteList.__set__ 'request', get: sinon.stub().returns
-        set: sinon.stub().returns
-          end: sinon.stub().yields(null, body: {results: [{ id: '123', name: 'Artists'}]})
-      @AdminVerticalsTags.__set__ 'AutocompleteList', React.createFactory AutocompleteList
-      @article = new Article _.extend fixtures().articles,
-        tags: ['Artists']
-        tracking_tags: []
-        vertical: {}
-      @Verticals = new Verticals([
-        { id: '1', name: 'Art'}
-        { id: '2', name: 'Art Market'}
-        { id: '3', name: 'Creativity'}
-        { id: '4', name: 'Culture'}
-      ])
-      _.first = sinon.stub().returns new Vertical({ id: '1', name: 'Art'})
-      props = {
-        article: @article
-        onChange: sinon.stub()
-      }
-      sinon.stub Backbone, 'sync'
-      @component = ReactDOM.render React.createElement(@AdminVerticalsTags, props), (@$el = $ "

")[0], =>
-        setTimeout =>
-          @component.setState verticals: @Verticals
-          done()
-
-  afterEach ->
-    Backbone.sync.restore()
-    benv.teardown()
-
-  describe 'Tags', ->
-
-    it 'Renders text inputs for tags', ->
-      $(ReactDOM.findDOMNode(@component)).find('.autocomplete-container--inline').length.should.eql 2
-      $(ReactDOM.findDOMNode(@component)).find('input').first().prop('placeholder').should.eql ''
-      $(ReactDOM.findDOMNode(@component)).find('input').last().prop('placeholder').should.eql 'Start typing a tracking tag...'
-
-    it 'Pre-populates the input with article tags', ->
-      $(ReactDOM.findDOMNode(@component)).find('.autocomplete-container').first().html().should.containEql 'Artists'
-
-    it 'does not render tags when empty', ->
-      @article.unset 'tags'
-      rendered = ReactDOMServer.renderToString React.createElement(@AdminVerticalsTags, { article: @article })
-      rendered.should.containEql 'placeholder="Start typing a topic tag..."'
-
-  describe 'Verticals', ->
-
-    it 'Renders buttons for Verticals', ->
-      $(ReactDOM.findDOMNode(@component)).find('.fields-left .field-group').first().html().should.containEql 'Editorial Vertical'
-      $(ReactDOM.findDOMNode(@component)).find('.field-group').first().find('button').length.should.eql 4
-      $(ReactDOM.findDOMNode(@component)).find('.field-group').first().find('button.avant-garde-button-black').length.should.eql 0
-
-    it 'Can render a saved vertical', ->
-      @component.setState vertical: { id: '1', name: 'Art'}
-      $(ReactDOM.findDOMNode(@component)).find('.field-group').first().find('button.avant-garde-button-black').length.should.eql 1
-
-    it 'Updates the vertical on click', ->
-      @component.state.vertical.should.eql {}
-      r.simulate.click r.find(@component, 'avant-garde-button')[0]
-      @component.state.vertical.should.eql { name: 'Art', id: '1' }
-      @component.props.onChange.args[0][0].should.eql 'vertical'
-      @component.props.onChange.args[0][1].should.eql { name: 'Art', id: '1' }
-
-    it 'Unsets the vertical if already selected', ->
-      @component.setState vertical: { id: '1', name: 'Art'}
-      r.simulate.click r.find(@component, 'avant-garde-button')[0]
-      @component.props.onChange.args[0].should.eql [ 'vertical', null ]
-
-describe 'AdminTags', ->
-
-  beforeEach (done) ->
-    benv.setup =>
-      benv.expose
-        $: benv.require 'jquery'
-        _: benv.require 'underscore'
-        _s: benv.require 'underscore.string'
-      window.jQuery = $
-      @AdminTags = benv.require resolve __dirname, '../verticals_tags/index.coffee'
-      @AdminTags.__set__ 'sd', {}
-      @article = new Article _.extend fixtures().articles,
-        tags: ['Artists']
-        tracking_tags: ['op-ed', 'profile']
-      props = {
-        article: @article
-        onChange: sinon.stub()
-      }
-      sinon.stub Backbone, 'sync'
-      @component = ReactDOM.render React.createElement(@AdminTags, props), (@$el = $ "

")[0], =>
-        setTimeout =>
-          done()
-
-  afterEach ->
-    Backbone.sync.restore()
-    benv.teardown()
-
-  describe 'Topic Tags', ->
-
-    it 'Renders text input', ->
-      $(ReactDOM.findDOMNode(@component)).find('input[name=tags]').prop('placeholder').should.eql 'Start typing a topic tag...'
-
-    it 'Renders saved tags', ->
-      $(ReactDOM.findDOMNode(@component)).find('input[name=tags]').val().should.eql 'Artists'
-
-    it 'Calls onChange with user input', ->
-      input = r.find(@component, 'bordered-input')[0]
-      input.value = 'new, tags'
-      r.simulate.change input
-      @component.props.onChange.args[0].should.eql [ 'tags', [ 'new', 'tags' ] ]
-
-  describe 'Tracking Tags', ->
-
-    it 'Renders text input', ->
-      $(ReactDOM.findDOMNode(@component)).find('input[name=tracking_tags]').prop('placeholder').should.eql 'Start typing a tracking tag...'
-
-    it 'Renders saved tags', ->
-      $(ReactDOM.findDOMNode(@component)).find('input[name=tracking_tags]').val()
-      $(ReactDOM.findDOMNode(@component)).find('input[name=tracking_tags]').val().should.eql 'op-ed, profile'
-
-    it 'Calls onChange with user input', ->
-      input = r.find(@component, 'bordered-input')[1]
-      input.value = 'new, tags'
-      r.simulate.change input
-      @component.props.onChange.args[0].should.eql [ 'tracking_tags', [ 'new', 'tags' ] ]


enterexit: function to delete a point

enterexit: function to delete a point

 - Deleting a random point, but then the others move; I should get rid
   of the transition duration

--- enterexit/enterexit.coffee
+++ enterexit/enterexit.coffee
@@ -25,6 +25,10 @@

 add_datapoint = ->
   data.push(random_datapoint())
+
+remove_datapoint = ->
+  toremove = Math.floor(Math.random()*data.length)
+  data.splice(data, 1)

 jitterAmount = 50
 jitter_value = (val, max) ->
@@ -124,3 +128,7 @@
 randombutton.on "click", ->
            randomize_data()
            recreate_points()
+
+exitbutton.on "click", ->
+           remove_datapoint()
+           recreate_points()


remove solution

remove solution

--- examples-coffee/todomvc/components/MainSection.coffee
+++ examples-coffee/todomvc/components/MainSection.coffee
@@ -3,12 +3,7 @@
 r = require 'r-dom'
 TodoItem = require './TodoItem'
 Footer = require './Footer'
-{ SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } = require '../constants/TodoFilters'
-
-TODO_FILTERS = {}
-TODO_FILTERS[SHOW_ALL] = -> true
-TODO_FILTERS[SHOW_ACTIVE] = (todo) -> !todo.completed
-TODO_FILTERS[SHOW_COMPLETED] = (todo) -> todo.completed
+{ SHOW_ALL } = require '../constants/TodoFilters'

 class MainSection extends Component
   constructor: (props, context) ->
@@ -24,7 +19,7 @@
       @props.actions.clearCompleted()

   handleShow: (filter) =>
-    @setState {filter}
+    console.log 'not implemented yet'

   renderToggleAll: (completedCount) =>
     { todos, actions } = @props
@@ -50,9 +45,7 @@

   render: =>
     { todos, actions } = @props
-    { filter } = @state

-    filteredTodos = todos.filter TODO_FILTERS[filter]
     completedCount = todos.reduce (count, todo) ->
       if todo.completed then count + 1 else count
     , 0
@@ -61,7 +54,7 @@
       className: "main", [
         @renderToggleAll completedCount
         r.ul
-          className: "todo-list", filteredTodos.map (todo) ->
+          className: "todo-list", todos.map (todo) ->
             props = Object.assign {},
               key: todo.id
               todo: todo


Add support for references to content in other elements

--- tooltips.coffee
+++ tooltips.coffee
@@ -104,9 +104,11 @@
 			Tooltips.hide()
 			node.parentNode.removeChild(node)

+SELECTORS = '[data-tooltip], [data-tooltip-element]'
+
 Meteor.startup ->

-	$(document).on 'mouseover', '[data-tooltip]', (evt) ->
+	$(document).on 'mouseover', SELECTORS, (evt) ->
 		$el = $(this)

 		viewport = $el.data 'tooltip-disable'
@@ -115,7 +117,13 @@
 			mq = window.matchMedia(viewport)
 			return false if mq.matches

-		setTooltip $el.data 'tooltip'
+		content = if selector = $el.data 'tooltip-element'
+			$target = $(selector)
+			$target.length and $target.html()
+		else
+			$el.data('tooltip')
+
+		setTooltip content
 		setPosition(top: 0, left: 0)

 		Tracker.afterFlush ->
@@ -148,4 +156,4 @@

 			setPosition(position, direction)

-	$(document).on 'mouseout', '[data-tooltip]', hideTooltip
+	$(document).on 'mouseout', SELECTORS, hideTooltip


all .html files in dist included

all .html files in dist included

--- tasks/fresh/steroids-setup-features.coffee
+++ tasks/fresh/steroids-setup-features.coffee
@@ -13,7 +13,7 @@
   grunt.extendConfig {
     'steroids-setup-features-splashscreen-autohide':
       dist:
-        src: 'dist/app/**/*.html'
+        src: 'dist/**/*.html'
   }
   grunt.registerMultiTask 'steroids-setup-features-splashscreen-autohide', ->
     count = 0


reactiviy: emoji selector: typo fix

reactiviy: emoji selector: typo fix

--- client/activity/lib/components/emojiselector/index.coffee
+++ client/activity/lib/components/emojiselector/index.coffee
@@ -28,9 +28,9 @@
   componentDidUpdate: (prevProps, prevState) ->

     { visible, query } = @props
-    isBecomeVisible    = visible and not prevProps.visible
+    hasBecomeVisible   = visible and not prevProps.visible

-    @refs.list.ready()  if isBecomeVisible
+    @refs.list.ready()  if hasBecomeVisible

   updatePosition: (inputDimensions) -> @refs.dropbox.setInputDimensions inputDimensions


payment: decorate each plan list item with an "Upgrade" button

--- client/landing/app/MainApp/payment/planupgradeform.coffee
+++ client/landing/app/MainApp/payment/planupgradeform.coffee
@@ -7,10 +7,20 @@
     @listController = new KDListViewController
       itemClass: GroupPlanListItem

+    @listView = @listController.getListView()
+
+    @listView.on 'ItemWasAdded', (item) =>
+      item.setControls new KDButtonView
+        title     : 'Upgrade'
+        callback  : =>
+          @emit 'PlanSelected', item.getData()
+
     super()

   pistachio: ->
     """
-    this is the plan upgrade form:
-    {{> @listController.getView()}}
+    <h2>
+      You must upgrade your plan:
+    </h2>
+    {{> @listView}}
     """


Parser: adding basic method test

Parser: adding basic method test

--- test/lib/parser.coffee
+++ test/lib/parser.coffee
@@ -13,9 +13,15 @@
       output      = parser.parse(test_string)
       expect(output.className).to.equal('Stuff')

-    it 'should get correct number of variables correctly', ->
+    it 'should get correct number of variables', ->
       test_string = "class Stuff thing: String otherthing: Array end"
       output      = parser.parse(test_string)
       expect(output.variables.length).to.equal(2)

+    it 'should get correct number of methods', ->
+      test_string = "class Stuff +func1 +func2 end"
+      output      = parser.parse(test_string)
+      expect(output.methods.length).to.equal(2)

+
+


Oscillator

Oscillator

--- test/oscillator.coffee
+++ test/oscillator.coffee
@@ -18,9 +18,9 @@
     amplitude: 10
     offset: -(Math.TAU / 4)

-  equals o(0).toFixed(), 0
-  equals o(30), 0
-  equals o(15), 0
+  equals o(0).toFixed(6), 0
+  equals o(30).toFixed(6), 0
+  equals o(15).toFixed(6), 0
   equals o(7.5), 10
   equals o(22.5), -10


Test stubs for userId, userName, and userEmail

--- test/formatters/json_formatter_test.coffee
+++ test/formatters/json_formatter_test.coffee
@@ -84,6 +84,18 @@
       result = new Formatter().format(outputData)
       expect(result.context.action).to.equal("[request_action]")

+    # it "has `userId`", ->
+    #   result = new Formatter().format(outputData)
+    #   expect(result.context.userId).to.exist
+
+    # it "has `userName`", ->
+    #   result = new Formatter().format(outputData)
+    #   expect(result.context.userName).to.exist
+
+    # it "has `userEmail`", ->
+    #   result = new Formatter().format(outputData)
+    #   expect(result.context.userEmail).to.exist
+
   it "has `environment`", ->
     result = new Formatter().format(outputData);
     expect(result.environment).to.be.an("object")


Workspace: Added missing header to collaborative tabbed editor.

--- client/landing/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
+++ client/landing/app/CommonViews/workspace/panes/collaborativetabbededitorpane.coffee
@@ -111,6 +111,7 @@

   pistachio: ->
     """
+      {{> @header}}
       {{> @tabHandleContainer}}
       {{> @tabView}}
     """


Fixed get().

Fixed get().

--- app/assets/javascripts/app/lib/app_init/config.js.coffee
+++ app/assets/javascripts/app/lib/app_init/config.js.coffee
@@ -4,7 +4,7 @@
   @init: ->
     _instance ?= new _Singleton

-  @get: ( key ) ->
+  @get: ( key, group ) ->
     if _instance == undefined
       _instance ?= new _Singleton
     _instance.get( key )


Provide initial UI before first submit

Provide initial UI before first submit

--- app/assets/javascripts/interaction_web_tools/chat.coffee
+++ app/assets/javascripts/interaction_web_tools/chat.coffee
@@ -15,7 +15,20 @@
     $(@constructor.CHAT_BODY).hide()
     $(@constructor.CHAT_CLOSE).hide()

+  # TODO: Extract to separate messaage class
+  systemMessage: (content) ->
+    {
+      type: 'text',
+      participant_type : 'System',
+      content: content
+    }
+
   onChatDialogInit: ->
+    # TODO: Figure our how to get content for initial UI
+    messages = [
+      @systemMessage('Welcome to our chat')
+    ]
+    @renderMessages(messages)

   pollMessages: ->
     $.get Chat.EVENTS_PATH, (data) ->


EDSC-590 try to get all the cassettes generated

--- app/assets/javascripts/models/page/search_page.js.coffee
+++ app/assets/javascripts/models/page/search_page.js.coffee
@@ -77,7 +77,6 @@
       error = @datasets.error()
       if error?
         for e in error
-          console.log "error:" + e
           return e if e? && (e.indexOf('polygon') != -1 ||
                               e.indexOf('box') != -1 ||
                               e.indexOf('point') != -1)


Added linkedIn service spec

Added linkedIn service spec

--- test/spec/services/linkedIn.coffee
+++ test/spec/services/linkedIn.coffee
@@ -1,14 +1,41 @@
 'use strict'

-describe 'Service: Linkedin', () ->
+describe 'Service: linkedIn', ->
+  windowMock =
+    IN:
+      API:
+        Profile: (string) ->
+          if string is 'me'
+              fields: (fields) ->
+                result: (callback) ->
+                  callback {response: 'response'}
+  linkedIn = {}
+  callback = jasmine.createSpy 'callback'

-  # load the service's module
-  beforeEach module 'portfolioApp'
+  beforeEach ->
+    module 'portfolioApp'
+    module ($provide) ->
+      $provide.value '$window', windowMock
+      null
+
+    inject (_linkedIn_) ->
+      linkedIn = _linkedIn_

-  # instantiate service
-  Linkedin = {}
-  beforeEach inject (_Linkedin_) ->
-    Linkedin = _Linkedin_
+  afterEach ->
+    callback.reset()

-  it 'should do something', () ->
-    expect(!!Linkedin).toBe true
+  it 'should contain an linkedIn service', ->
+    expect(linkedIn).not.toBe null
+
+  it 'should register a callback function and call it when log method is called', ->
+    linkedIn.regCallback callback
+    linkedIn.log()
+    expect(callback).toHaveBeenCalled()
+
+  it 'should return true once log method has been called', ->
+    linkedIn.log()
+    expect(linkedIn.isLogged()).toBe true
+
+  it 'should call to real linkedin api and pass the result to the given function', ->
+    linkedIn.getProfile callback
+    expect(callback).toHaveBeenCalledWith {response: 'response'}


snap: change cutoff to 35GB instead of 50GB...

--- salvus/snap.coffee
+++ salvus/snap.coffee
@@ -19,7 +19,7 @@
 # which is about as long as we want to wait.  Bigger is more efficient
 # overall, because of much better de-duplication, but smaller means
 # faster access.
-REPO_SIZE_CUTOFF_BYTES=50000000
+REPO_SIZE_CUTOFF_BYTES=35000000

 SALVUS_HOME=process.cwd()


Revert "Revert "CredentialStore: keep credentials only on sneaker if it's supported""

This reverts commit ac3e3a4becb4341b01ee1be14061357d3b26ec28.

--- workers/social/lib/social/models/computeproviders/credentialstore.coffee
+++ workers/social/lib/social/models/computeproviders/credentialstore.coffee
@@ -45,11 +45,7 @@
     data = { meta, originId, identifier }

     if @SNEAKER_SUPPORTED
-      storeOnSneaker client, data, (err) ->
-        # This part can be removed once kloud is ready
-        # to use sneaker by default ~ GG cc/ RJ
-        return callback err  if err
-        storeOnMongo data, callback
+      storeOnSneaker client, data, callback
     else
       storeOnMongo data, callback

@@ -121,14 +117,8 @@
     { identifier, meta } = data

     if @SNEAKER_SUPPORTED
-
-      storeOnSneaker client, data, (err) ->
-        return callback err  if err
-
-        updateOnMongo identifier, meta, callback
-
+      storeOnSneaker client, data, callback
     else
-
       updateOnMongo identifier, meta, callback

   # UPDATE ENDS ---------------------------------------------------------------


use eachR helper

use eachR helper

--- manager/app/assets/javascripts/inventory/inventory_views.js.coffee
+++ manager/app/assets/javascripts/inventory/inventory_views.js.coffee
@@ -13,10 +13,8 @@
       super

       list = $(".host_list")
-      @hosts.each (host) ->
-        v = @create_partial(exports.HostTableRow, { host: host })
-        list.append(v.$el)
-      , @
+      @hosts.eachR @, (host) ->
+        list.append( @partial(exports.HostTableRow, { host: host }).$el )

   class exports.HostTableRow extends Stark.View


usercontext was not respecting bokeh prefix

--- bokehjs/src/coffee/server/usercontext/usercontext.coffee
+++ bokehjs/src/coffee/server/usercontext/usercontext.coffee
@@ -144,7 +144,8 @@
     fetch : (options) ->
       if _.isUndefined(options )
         options = {}
-      resp = response = $.get('/bokeh/userinfo/', {})
+      url = base.Config.prefix + "/bokeh/userinfo/"
+      resp = response = $.get(url, {})
       resp.done((data) =>
         docs = data['docs']
         if options.update


Non cumulative trends and balance inclusion

--- src/components/common/trends-add/trends-add.component.coffee
+++ src/components/common/trends-add/trends-add.component.coffee
@@ -133,8 +133,7 @@
       startDate = timestamps[startIndex]
       for i in [startIndex...lastIndex]
         continue unless shouldApplyTrend(trend, startDate, timestamps[i])
-        increment = lastValue * trend.rate / 100.0
-        lastValue += increment
+        increment = lastValue * (trend.rate + 100.0) / 100.0
         incrementRemainingValues(values, i, increment)

       # Return data with timestamps
@@ -172,7 +171,7 @@

     incrementRemainingValues = (values, start, increment) ->
       for i in [start...values.length]
-        values[i] += increment
+        values[i] -= increment

     ctrl.cancel = ->
       _.remove(ctrl.chart.series, {name: "Current trend"})


chat: adjust box size at bottom (this is really crappy still)

--- salvus/page/editor_chat.cjsx
+++ salvus/page/editor_chat.cjsx
@@ -238,12 +238,14 @@
         return

             <Input
                 autoFocus
+                rows      = 4
                 type      = 'textarea'
                 ref       = 'input'
                 onKeyDown = {@keydown} />
-

+

                 <Tip title='Use Markdown' tip={tip}>
-                    Format using Markdown
+                    Shift+Enter for newline.
+                    Format using Markdown.
                 </Tip>

@@ -251,7 +253,7 @@
     chat_log_style:
         overflowY    : "auto"
         overflowX    : "hidden"
-        height       : "70vh"
+        height       : "60vh"
         margin       : "0"
         padding      : "0"
         paddingRight : "10px"


fixed end callbacks for foldUp and unfold

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -597,7 +597,7 @@
       @panels[anchor][i].removeEventListener css.transitionEnd, onTransitionEnd, false
       @panels[anchor][i].style.display = 'none'
       if --i is 0
-        @_callback callback
+        callback() if typeof callback is 'function'
       else
         setTimeout nextPanel, 0

@@ -625,7 +625,7 @@
     onTransitionEnd = (e) =>
       @panels[@lastAnchor][i].removeEventListener css.transitionEnd, onTransitionEnd, false
       if ++i is @panels[@lastAnchor].length
-        callback()
+        callback() if typeof callback is 'function'
       else
         setTimeout nextPanel, 0


Added text

Added text

--- client.coffee
+++ client.coffee
@@ -21,7 +21,8 @@
 	localScores = Obs.create {}
 	copied = {}
 	started = Obs.create false
-	finalReached = Obs.create (Db.shared.peek 'counters', App.userId() >= FINALNUMBER)
+	finalReached = Obs.create (Db.shared.peek('counters', App.userId()) >= FINALNUMBER)
+
 	Obs.observe !->
 		Db.shared.iterate 'counters', (v) !->
 			# just copy once!
@@ -56,9 +57,10 @@
 			renderScores localScores

 renderButton = (finalReached, count, buffer) !->
-	animationDone = Obs.create finalReached.peek()
-	buttonText = Obs.create (if finalReached.peek() then "WINNER" else "Click")
-	doneSpin = animationDone.peek()
+	startedFinished = finalReached.peek()
+	animationDone = Obs.create startedFinished
+	buttonText = Obs.create (if startedFinished then "WINNER" else "Click")
+	doneSpin = startedFinished

 	buffering = Obs.create false
 	Dom.div !->
@@ -85,16 +87,18 @@

 				Obs.observe !-> Dom.text buttonText.get()

+			lastClick = 0
 			Obs.observe !->
 				if not finalReached.get()
 					Dom.onTap !->
-						if true or count?.get() is (FINALNUMBER - 1)
+						if (count?.get() + buffer.peek()) is (FINALNUMBER - 1)
 							finalReached.set true
+							lastClick = App.time()
 							Server.sync 'incr', 1
 						else
 							buffering.set true
 							buffer.incr()
-				else
+				else if (App.time() - lastClick) > 1
 					Dom.onTap !->
 						animationDone.set false
 						Obs.emit()
@@ -132,14 +136,46 @@
 		wrapperEl = Dom.get()
 		Obs.observe !->
 			if finalReached.get() and animationDone.get()
+				if startedFinished
+					startedFinished = false
+					return
 				Dom.div !->
-					Dom.style transform: 'translateY(100px)', padding: '0 20%', fontSize: '1.3em', textAlign: 'justify'
-					Dom.text "klhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhs a dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkgklhsa dbfsa bfha sdk bh adsfbh bfa dhs f dsbfsdfh sd fhksd hgdshfgs d ahfghds afg ksg fkhjsdg adsv fhjkg"
+					smallGap = !-> Dom.div !-> Dom.style height: '70px'
+					bigGap = !-> Dom.div !-> Dom.style height: '200px'
+					Dom.style transform: 'translateY(100px)', padding: '0 20%', fontSize: '1.3em', textAlign: 'justify', lineHeight: '1.3em', boxSizing: 'border-box'
+					Dom.p "A long time ago"
+					Dom.p "in a galaxy far, far away...."
+					smallGap()
+					Dom.p "Ismay began clicking a button, for no real reason."
+					bigGap()
+					Dom.p "It is a period of civil war."
+					Dom.p "Whilst PAIQ is fending off the never-ending attacks by the Sith site Lexa, a new threat looms under the name of TINDER."
+					smallGap()
+					Dom.p "As the Tinder Armies have attempted to besiege Paiq and its valuable users, Ismay, the voice of the Paiq Community, is about to embark on her own journey."
+					Dom.p " Although Met Singles has just been launched, Ismay has driven home her Master's title and is set to pursue the next step of her career."
+					smallGap()
+					Dom.p "Little did Ismay know that THE BUTTON has secretly begun construction on a new animated surprise even more elaborate than the 100.000-mark..."
+					smallGap()
+					Dom.p "The lady Ismay, obsessed with reaching One Million clicks, has spent thousands of minutes clicking the big Button."
+					smallGap()
+					Dom.div !->
+						Dom.style height: '2px', width: '50%', margin: '0 auto', backgroundColor: '#ffd700'
+					smallGap()
+					Dom.p "Despite all that time clicking, you have been a fantastic co-worker. Turmoil has sometimes engulfed Paiq support, but you've led a brave RESISTANCE. You were thorough enough to find solutions and showed the patience to help in restoring peace and justice to the dating world."
+					smallGap()
+					Dom.p "You helped people search their feelings, and endured the loud-mouthed scoundrels you worked with. Despite Ruurt-Jan's never-ending siege, you were never tempted to join the Dark Side."
+					smallGap()
+					Dom.p "Difficult to see, always in motion is the future. But we are certain that your future is very bright! In our experience there is no such thing as luck, but we've been very lucky to have worked with you. We have a good feeling about this."
+					smallGap()
+					Dom.p "May the force be with you."
+					bigGap()
+					Dom.p "...and don't get cocky."

 				Obs.onTime 1000, !->
-					wrapperEl.style transition: 'transform 15s linear'
-					wrapperEl.style transform: 'translateY(-120%)'
-					Obs.onTime 15000, !->
+					seconds = 100
+					wrapperEl.style transition: "transform #{seconds}s linear"
+					wrapperEl.style transform: 'translateY(-110%)'
+					Obs.onTime (seconds * 1000), !->
 						wrapperEl.style opacity: 0
 						wrapperEl.style transition: 'opacity 1s ease'
 						Obs.onTime 300, !->


Fixed tap highlight

Fixed tap highlight

--- client.coffee
+++ client.coffee
@@ -156,7 +156,8 @@
 	dummy = round.get('selfies') # the empty above doesn't appear to trigger a redraw on change (should it?) --Jelmer

 	Dom.div !->
-		Dom.style textAlign: 'center', backgroundColor: '#fff', margin: '-8px -8px 8px -8px', padding: '4px 0', borderBottom: '2px solid #ccc'
+		Dom.style textAlign: 'center', margin: '-8px -8px 8px -8px', padding: '4px 0', borderBottom: '2px solid #ccc'
+		Dom.cls 'currentRnd'

 		Dom.div !->
 			Dom.style fontSize: '180%'
@@ -485,3 +486,10 @@
 				value: Db.shared?.get('deadline')||120
 			Dom.div !->
 				Dom.text tr("minutes")
+
+
+Dom.css
+	'.currentRnd':
+		backgroundColor: '#fff'
+	'.currentRnd.tap':
+		backgroundColor: '#eee'


improve ticking on user bound axes when panning/zooming, etc

--- subtree/bokehjs/static/coffee/renderers/guide/linear_axis.coffee
+++ subtree/bokehjs/static/coffee/renderers/guide/linear_axis.coffee
@@ -372,8 +372,12 @@
     range_bounds = [ranges[i].get('min'), ranges[i].get('max')]

     if _.isArray(user_bounds)
-      start = Math.min(user_bounds[0], user_bounds[1])
-      end = Math.max(user_bounds[0], user_bounds[1])
+      if Math.abs(user_bounds[0]-user_bounds[1]) > Math.abs(range_bounds[0]-range_bounds[1])
+        start = Math.max(Math.min(user_bounds[0], user_bounds[1]), range_bounds[0])
+        end = Math.min(Math.max(user_bounds[0], user_bounds[1]), range_bounds[1])
+      else
+        start = Math.min(user_bounds[0], user_bounds[1])
+        end = Math.max(user_bounds[0], user_bounds[1])
     else
       [start, end] = range_bounds


Keep your promise about saving the data

Keep your promise about saving the data

--- scripts/ayp.coffee
+++ scripts/ayp.coffee
@@ -474,7 +474,7 @@
         return cb(new Error("Failed to read file I just wrote to #{outPath}: #{err}")) if err
         # We can unlink unconditionally now that we have it or failed
         fs.unlink(outPath, ->)
-        cb(false, data)
+        cb(false, (@info.image_jpeg = data))

 # PantsBuffer is the abstraction of "The Logs".


Correctly hide explicit cover for search header based on user setting

--- resources/assets/coffee/react/beatmaps/search-content.coffee
+++ resources/assets/coffee/react/beatmaps/search-content.coffee
@@ -12,6 +12,7 @@
 import * as React from 'react'
 import { a, div, p } from 'react-dom-factories'
 import VirtualList from 'react-virtual-list'
+import { showVisual } from 'utils/beatmapset-helper'

 el = React.createElement
 beatmapsetStore = core.dataStore.beatmapsetStore
@@ -61,7 +62,7 @@
       beatmapsetIds = controller.currentBeatmapsetIds

       firstBeatmapset = beatmapsetStore.get(beatmapsetIds[0])
-      searchBackground = if beatmapsetIds.length > 0 then firstBeatmapset?.covers?.cover else null
+      searchBackground = if firstBeatmapset? && showVisual(firstBeatmapset) then firstBeatmapset.covers?.cover else null
       supporterRequiredFilterText = controller.supporterRequiredFilterText
       listCssClasses = 'beatmapsets'
       listCssClasses += ' beatmapsets--dimmed' if controller.isBusy


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -23,7 +23,7 @@
   pieTween: (d, i) ->
     `var i`
     that = this
-    theOldDataInPie = theAmazingPie.oldPieData
+    theOldDataInPie = @oldPieData
     # Interpolate the arcs in data space
     s0 = undefined
     e0 = undefined
@@ -47,7 +47,7 @@
       endAngle: d.endAngle)
     (t) ->
       b = i(t)
-      theAmazingPie.arc b
+      @arc b

   removePieTween: (d, i) ->
     `var i`
@@ -62,7 +62,7 @@
       endAngle: e0)
     (t) ->
       b = i(t)
-      theAmazingPie.arc b
+      @arc b

   update: (dataSet) ->
     console.log 'update pie', dataSet


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -99,7 +99,7 @@
         c = arc.centroid(d)
         x = c[0]
         y = c[1]
-        mx = 1.6
+        mx = 1.7
         my = 1
         h = Math.sqrt(x*x + y*y)
         r = labelRadius


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -240,17 +240,17 @@
             .attr("fill", (d, i) ->
                 return color(i)
             )
-        console.log("pre-transition")
-        path.transition()
-            .duration(1500)
-            #.attrTween("d", pieTween);
-            .attrTween("d", (d,i) ->
-                i = d3.interpolate({startAngle: 0,endAngle: 0}, {startAngle: d.startAngle,endAngle: d.endAngle})
-                return (t) ->
-                    b = i(t);
-                    return arc(b)
-            )
-        console.log("post-transition")
+
+            .attr("d", arc)
+        #path.transition()
+        #    .duration(1500)
+        #    #.attrTween("d", pieTween);
+        #    .attrTween("d", (d,i) ->
+        #        i = d3.interpolate({startAngle: 0,endAngle: 0}, {startAngle: d.startAngle,endAngle: d.endAngle})
+        #        return (t) ->
+        #            b = i(t);
+        #            return arc(b)
+        #    )

         #this.path.exit()
         #    .transition()
@@ -258,7 +258,6 @@
         #    .attrTween("d", that.removePieTween)
         #    .remove();
         path.exit()
-        console.log("post-exit")

         labels = labelGroup.selectAll("text")
             .data(data.sort((p1,p2) -> return p1.startAngle - p2.startAngle))
@@ -267,7 +266,6 @@
             .attr("text-anchor", "middle")
         labels.exit()
             .remove()
-        console.log("post-labels")

         labelLayout = d3.geom.quadtree()
             .extent([[-width,-height], [width,height] ])


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -117,8 +117,8 @@
         .duration(1000)
         #.attrTween("d", pieTween)
         .attrTween("d", (d,i) ->
-            console.log("d",d)
-            console.log("i",i)
+            #console.log("d",d)
+            #console.log("i",i)
             i = d3.interpolate({startAngle: 0, endAngle: 0}, {startAngle: d.startAngle, endAngle: d.endAngle})
             return (t) ->
                 b = i(t)


add tell us more

add tell us more

--- scripts/im-out.coffee
+++ scripts/im-out.coffee
@@ -1,3 +1,5 @@
 module.exports = (robot) ->
   robot.hear /i'm out/i, (msg) ->
     msg.send "http://gifs.gifbin.com/062009/1245227615_colin_farrel.gif"
+  robot.hear /tell (me|us) more/i, (msg) ->
+    msg.send "http://mlkshk.com/r/BN75.gif"


Quick bugfix: Pong timeout of 15s.

Quick bugfix: Pong timeout of 15s.

--- client/landing/app/MainApp/account-mixins.coffee
+++ client/landing/app/MainApp/account-mixins.coffee
@@ -101,7 +101,7 @@
             callback channel
             i = setInterval ->
               now = Date.now()
-              isUnresponsive = channel.lastPong? and (now - channel.lastPong > 6000)
+              isUnresponsive = channel.lastPong? and (now - channel.lastPong > 15000)
               cycleChannel.call channel  if isUnresponsive
               channel.publish JSON.stringify
                 method      : 'ping'


landing: styles: gulp minor

landing: styles: gulp minor

--- client/landing/gulptasks/helper.constants.coffee
+++ client/landing/gulptasks/helper.constants.coffee
@@ -1,6 +1,6 @@
 argv = require('minimist') process.argv
 site = SITE_NAME or argv.site or 'landing'
-base = "#{__dirname}/.."
+base = __dirname.replace '/gulptasks', ''

 module.exports =
   STYLES_PATH     : [


Remove meme from API key redaction

Remove meme from API key redaction

--- picksel.coffee
+++ picksel.coffee
@@ -55,7 +55,7 @@
 #
 # @param [String] url the URL to redact the API key from
 #
-redactApiKey = (url) -> url.replace user.apiKey, '[NOPE]'
+redactApiKey = (url) -> url.replace user.apiKey, '********'

 # Builds a URL for downloading image information.


JMachine add index to ipAddress

JMachine add index to ipAddress

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -25,6 +25,7 @@
       users             : 'sparse'
       groups            : 'sparse'
       domain            : 'sparse'
+      ipAddress         : 'sparse'

     sharedEvents        :
       static            : [ ]


JMachine::setLabel to provider label update functionality [#78425634]

This also updates the slug based on the provided label, which then we will use
this slug in client-side whenever we need a meaningful slug for machine

--- workers/social/lib/social/models/computeproviders/machine.coffee
+++ workers/social/lib/social/models/computeproviders/machine.coffee
@@ -43,12 +43,15 @@
           (signature String, Function)
         setDomain       :
           (signature String, Function)
+        setLabel        :
+          (signature String, Function)

     permissions         :
       'list machines'   : ['member']
       'populate users'  : ['member']
       'set provisioner' : ['member']
       'set domain'      : ['member']
+      'set label'       : ['member']

     schema              :

@@ -300,3 +303,27 @@
             "The domain #{domain} already exists", "DUPLICATEDOMAIN"

         @update $set: { domain }, (err)-> callback err
+
+
+  setLabel: permit 'set label',
+
+    success: revive
+
+      shouldReviveClient   : yes
+      shouldReviveProvider : no
+
+    , (client, label, callback)->
+
+      { r: { user, group } } = client
+
+      unless isOwner user, this
+        return callback new KodingError 'Access denied'
+
+      slug = slugify label
+
+      if slug isnt @slug
+        generateSlugFromLabel { user, group, label }, (err, slug)=>
+          return callback err  if err?
+          @update $set: { slug, label }, (err)-> callback err
+      else
+        @update $set: { label }, (err)-> callback err


update example

update example

--- example/config_example.coffee
+++ example/config_example.coffee
@@ -1,11 +1,11 @@
 ConfigBundles = require("../src/module/config/config_bundles").ConfigBundles
 ConfigFile = "/Users/vernonzheng/Project/github/hades-node-client/src/setting/hades_config.json"
-TEST_REMOTE_NODE = "TestRemoteConfig"
+TEST_REMOTE_NODE = "route"
 TEST_LOCAL_NODE = "test"

 ConfigBundles.on(ConfigBundles.EVENT_CONFIG_READY, ->
 	console.log("ConfigBundles receive EVENT_CONFIG_READY!!")
-	console.log("TestRemoteConfig from zookeeper result:"+ConfigBundles.get(TEST_REMOTE_NODE))
+	console.log("TestRemoteConfig from zookeeper result:"+ConfigBundles.getDynamic(TEST_REMOTE_NODE))
 	console.log("TestLocalConfig from local file result:"+JSON.stringify(ConfigBundles.get(TEST_LOCAL_NODE)))
 )


Added commons (font-face, and normalize)

--- example/webpack.config.coffee
+++ example/webpack.config.coffee
@@ -11,7 +11,7 @@
   context       : __dirname

   entry:
-    # commons     : ['./components/style/__commons.styl']
+    commons     : ['./node_modules/react-toolbox/components/style/__commons.styl']
     test        : ['webpack/hot/dev-server', './src/app.cjsx']

   output:
@@ -20,18 +20,11 @@
     publicPath  : '/build/'

   devServer:
-    # contentBase : './build'
     host        : 'localhost'
     port        : 8080
-    # colors      : true
-    # progress    : true
-    # noInfo      : false
-    # hot         : true
     inline      : true

   module:
-    noParse     : [node_modules + '/react/dist/*.js']
-
     loaders: [
       test      : /\.cjsx$/,    loader: 'coffee-jsx-loader'
     ,


Update radio clicking instructions in getValue test

--- test/get_value_gm_test.coffee
+++ test/get_value_gm_test.coffee
@@ -100,7 +100,9 @@
     $('.fr_response_field_text input').val('foo').trigger('input')
     $('.fr_response_field_paragraph textarea').val('bar').trigger('input')
     $('.fr_response_field_checkboxes input').first().click().trigger('change')
-    $('.fr_response_field_radio input').last().click().trigger('change')
+    $($('.fr_response_field_radio')[0]).find('input[type=radio]').last().click().trigger('change')
+    $($('.fr_response_field_radio')[1]).find('input[type=radio]').last().click().trigger('change')
+    $('.fr_other_option input[type=text]').val("some alternative answer")
     $('.fr_response_field_dropdown select').val('Choice #2').trigger('change')
     $('.fr_response_field_price input').first().val('12').trigger('input')
     $('.fr_response_field_price input').last().val('99').trigger('input')


cancel existing load/render tasks correctly

--- services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee
+++ services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee
@@ -35,11 +35,19 @@
 					@errorCallback(exception)

 			resetState: () ->
-				@complete = []
-				@timeout = []
-				@pageLoad = []
-				@renderTask = []
+				#console.log 'called reset state'
 				@renderQueue = []
+				clearTimeout @queueTimer if @queueTimer?
+				# clear any existing timers, render tasks
+				for timer in @spinTimer or []
+					clearTimeout timer
+				for page in @pageState or []
+					page?.loadTask?.cancel()
+					page?.renderTask?.cancel()
+				# initialise/reset the state
+				@pageState = []
+				@spinTimer = []     # timers for starting the spinners (to avoid jitter)
+				@spinTimerDone = [] # array of pages where the spinner has activated
 				@jobs = 0

 			getNumPages: () ->
@@ -90,9 +98,7 @@
 					@processRenderQueue()
 				, interval

-			removeCompletedJob: (taskRef, pagenum) ->
-				# may need to clean up deferred object here
-				delete taskRef[pagenum]
+			removeCompletedJob: (pagenum) ->
 				@jobs = @jobs - 1
 				@triggerRenderQueue(0)

@@ -191,12 +197,11 @@
 				# update the spinner to make it spinning (signifies loading has begun)
 				@updateIndicator page

-				completeRef = @complete
-				renderTaskRef = @renderTask
 				# console.log 'started page load', pagenum

 				timedOut = false
 				timer = $timeout () =>
+					return if loadTask.cancelled # return from cancelled page load
 					Raven?.captureMessage?('pdfng page load timed out after ' + @PAGE_LOAD_TIMEOUT + 'ms (1% sample)') if Math.random() < 0.01
 					# console.log 'page load timed out', pagenum
 					timedOut = true
@@ -206,22 +211,31 @@
 					@errorCallback?('timeout')
 				, @PAGE_LOAD_TIMEOUT

-				@pageLoad[pagenum] = @getPage(pagenum)
-
-				@pageLoad[pagenum].then (pageObject) =>
-					# console.log 'in page load success', pagenum
+				loadTask = @getPage(pagenum)
+
+				loadTask.cancel = () ->
+					@cancelled = true
+
+				@pageState[pagenum] = pageState = { loadTask: loadTask }
+
+				loadTask.then (pageObject) =>
+					#console.log 'in page load success', pagenum
 					$timeout.cancel(timer)
-					clearTimeout(spinTimer)
-					@renderTask[pagenum] = @doRender element, pagenum, pageObject
-					@renderTask[pagenum].then () =>
-						# complete
-						# console.log 'render task success', pagenum
-						completeRef[pagenum] = true
-						@removeCompletedJob renderTaskRef, pagenum
+					return if loadTask.cancelled # return from cancelled page load
+					pageState.renderTask = @doRender element, pagenum, pageObject
+					pageState.renderTask.then () =>
+						#console.log 'render task success', pagenum
+						@clearIndicator page
+						pageState.complete = true
+						delete pageState.renderTask
+						@removeCompletedJob pagenum
 					, () =>
+						# display an error icon
 						# console.log 'render task failed', pagenum
+						pageState.complete = false
+						delete pageState.renderTask
 						# rejected
-						@removeCompletedJob renderTaskRef, pagenum
+						@removeCompletedJob pagenum
 				.catch (error) ->
 					# console.log 'in page load error', pagenum, 'timedOut=', timedOut
 					$timeout.cancel(timer)
@@ -230,7 +244,6 @@

 			doRender: (element, pagenum, page) ->
 				self = this
-						# display an error icon
 				scale = @scale

 				if (not scale?)
@@ -325,13 +338,12 @@

 				return result

+			stop: () ->
+
 			destroy: () ->
 				# console.log 'in pdf renderer destroy', @renderQueue
 				@shuttingDown = true
-				clearTimeout @queueTimer if @queueTimer?
-				@renderQueue = []
-				for task in @renderTask
-					task.cancel() if task?
+				@resetState()
 				@pdfjs.then (document) ->
 					document.cleanup()
 					document.destroy()


Fixes

Fixes

--- frontend/views/root.coffee
+++ frontend/views/root.coffee
@@ -2,9 +2,9 @@
   Here = nokia.maps
   App = {
     actions: {
-      zoom_to_bounding_box: (box) ->
+      zoom_to_bounding_box: (box, keep_center = true) ->
         zoom = ->
-          App.map.zoomTo box, true, 'default'
+          App.map.zoomTo box, keep_center, 'default'
         setTimeout zoom, 1000

       set_user_location: (lat, lon) ->
@@ -20,9 +20,9 @@

       find_nearest_geojson_point: (json) ->
         parsed_geojson = L.geoJson json
-        user_leaf_geoloc = L.latLng.apply App.user_location
-        nearest_point = (leafletKnn(parsed_geojson)
-            .nearest(user_leaf_geoloc, 1)[0])
+        user_leaf_geoloc = L.latLng.apply this, App.user_location
+        nearest_point = leafletKnn(parsed_geojson)
+            .nearest(user_leaf_geoloc, 1)[0]

       show_path_from_user_to: (dest_lat, dest_lon) ->
         user_nok_geoloc = new
@@ -44,8 +44,8 @@
                 Here.routing.component.RouteResultSet(routes[0]).container
             App.map.objects.add App.mapRoute

-            # Zoom to the bounding box of the route
-            @zoom_to_bounding_box App.mapRoute.getBoundingBox
+            # Zoom to the bounding box of the route, discarding current map center
+            @zoom_to_bounding_box App.mapRoute.getBoundingBox(), false

         router.calculateRoute points, [
           type: "shortest"
@@ -61,7 +61,7 @@
           dataPoints: []

         for point in data.features
-          coods = point.geometry.coordinates.reverse()
+          coords = point.geometry.coordinates.reverse()
           cluster.add latitude: coords[0], longitude: coords[1]

         cluster.cluster()


More accurate trigger

More accurate trigger

--- BackofficeBundle/Resources/public/coffee/orchestraListeners.coffee
+++ BackofficeBundle/Resources/public/coffee/orchestraListeners.coffee
@@ -14,6 +14,6 @@
   return

 # CLOSE MODALS
-$('.close').click ->
+$(".close", ".modal-header").click ->
   $("#select2-drop-mask").click();
   return


Birds - Actually properly use delegated events.

--- app/lib/tools/BaseTool.coffee
+++ app/lib/tools/BaseTool.coffee
@@ -13,12 +13,10 @@

     for action in @actions when @actions.length
       list += @itemTemplate({key: action.key, displayName: action.displayName})
+      $('#actions').on 'click', "[data-action=#{action.key}]", @[action.callback]

     @interface.actions.html list
-
-    for action in @actions when @actions.length
-      $('#actions').on 'click', "[data-action=#{action.key}]", @[action.callback]
-
+
   clickBox: (e) ->
     # Ensure this exists. Implemented by tools.


update text headers

update text headers

--- app/pages/settings/email.cjsx
+++ app/pages/settings/email.cjsx
@@ -12,7 +12,7 @@

   render: ->

-
Project email preferences

+
Zooniverse email preferences

         <AutoSave resource={@props.user}>

@@ -35,6 +35,7 @@

         </AutoSave>

+
Project email preferences


feat(popover): add default caption

feat(popover): add default caption

--- src/client/scripts/controllers/rb-components/rb-popover.coffee
+++ src/client/scripts/controllers/rb-components/rb-popover.coffee
@@ -25,6 +25,7 @@
 		$scope.reset = ->
 			$scope.a =
 				content: 'Hello popover!'
+				caption: 'Caption'

 		# Watches
 		# =======


viewer cache buster

viewer cache buster

--- client/landing/app/Applications/Viewer.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Viewer.kdapplication/AppController.coffee
@@ -95,12 +95,12 @@
   openPath:(path)->
     @path = path
     @clean = no
-    @iframe.$().attr 'src', path
-    @viewerHeader.setPath(path)
+    @iframe.$().attr 'src', "#{path}?#{Date.now()}"
+    @viewerHeader.setPath path

   refreshIFrame:->
-    @iframe.$().contents().location.reload(yes)
-    # @iframe.$().attr 'src', @path
+    # @iframe.$().contents().location.reload(yes)
+    @iframe.$().attr 'src', "#{@path}?#{Date.now()}"

   isDocumentClean:->
     @clean


Add debugging code.

Add debugging code.

--- lib/assets/javascripts/nyulibraries/popover.js.coffee
+++ lib/assets/javascripts/nyulibraries/popover.js.coffee
@@ -74,6 +74,7 @@

   # Contructor (obviously)
   constructor: (@selector) ->
+    content.log this
     this.content(Popover._CONTENT_CALLBACK(@, @_JSON_URL))

   # Crappy hack to append an extra class


fixing select tests on ie9

fixing select tests on ie9

--- test/manipulation.spec.coffee
+++ test/manipulation.spec.coffee
@@ -113,20 +113,19 @@
         el = $(input).val('bar')
         assert.equal input.value, 'bar'

-        select = makeElement 'select', '<option value="foo">f</option><option value="bar">b</option>'
-        el = $(select).val('bar')
+        div = makeElement 'div', '<select><option value="foo">f</option><option value="bar">b</option></select>'
+        el = $(div).children().val('bar')
         assert.isTrue el.find('option').get(1).selected

     test 'get val', ->
         input = makeElement 'input', '', value: 'foo'
         assert.equal $(input).val(), 'foo'

-        select = makeElement 'select', '<option value="foo">f</option><option value="bar" selected>b</option>'
-        assert.equal $(select).val(), 'bar'
+        div = makeElement 'div', '<select><option value="foo">f</option><option value="bar" selected>b</option></select>'
+        assert.equal $(div).find('select').val(), 'bar'

-        select = makeElement 'select', '', multiple: 'multiple'
-        select.innerHTML = '<option value="foo" selected>f</option><option value="bar" selected>b</option><option value="fizz" disabled selected>f</option>'
-        assert.deepEqual $(select).val(), ['foo', 'bar']
+        div = makeElement 'div', '<select multiple><option value="foo" selected>f</option><option value="bar" selected>b</option><option value="fizz" disabled selected>f</option></select>'
+        assert.deepEqual $(div).find('select').val(), ['foo', 'bar']

     test 'get attr', ->
         input = document.createElement('input')


String#extension

String#extension

--- test/string_extensions.coffee
+++ test/string_extensions.coffee
@@ -17,8 +17,9 @@

 test "#extension", ->
   equals "README".extension(), ""
+  equals "README.md".extension(), "md"

-
+  equals "README.md".extension(), "md"

 test "#humanize", ->
   equals "employee_salary".humanize(), "Employee salary"


Fixed screenshots test

Fixed screenshots test

--- core/app/backbone/views/facts/fact_vote_area_view.coffee
+++ core/app/backbone/views/facts/fact_vote_area_view.coffee
@@ -35,6 +35,8 @@
     @listenTo @collection, 'reset add remove change', @render, @

   appendHtml: (collectionView, itemView, index) ->
+    return unless itemView.model.get('type') in ['believes', 'disbelieves']
+
     @typeRegionForVote(itemView.model).append itemView.el

   typeRegionForVote:(model) ->


Remove debugging output.

Remove debugging output.

--- server/loot.coffee
+++ server/loot.coffee
@@ -59,26 +59,18 @@
     Inventory.insert item

   sort: (type_order, bag) ->
-    console.log type_order, bag
     check type_order, String
     check bag, String
-    console.log type_order
     all_items = Inventory.find bag: bag
-    console.log "got items"
     orders = all_items.map (item) -> item.order or 0
-    console.log orders
     counter = Math.max orders.length, orders...
-    console.log counter
     type_order = type_order.split(" ").reverse()
-    console.log type_order
     for type in type_order
-      console.log type
       items = Inventory.find
         bag: bag
         type:
           $regex: type
       items.forEach (item) ->
-        console.log "setting #{item.name}: #{item.order} -> #{counter}"
         Inventory.update item._id, $set: order: counter
         counter -= 1


Send guid with each ajax request

Send guid with each ajax request

--- lib/ymdp/javascripts/jquery/ajax.js.coffee
+++ lib/ymdp/javascripts/jquery/ajax.js.coffee
@@ -47,11 +47,12 @@
   ajax: (url, method, params, success_function, error_function) ->
     params = params || {}
     params["application"] = View.application
+    params["guid"] = YMDP.guid if YMDP.guid

     debug = !params["_hide_debug"]

     if debug
-      Debug.log "OIB.ajax: About to call openmail.Application.callWebService: ",
+      Debug.log "OIB.ajax: About to call openmail.Application.callWebService: ",
         "method": method,
         "url": url + "?" + $.param(params)

@@ -131,4 +132,4 @@
     , (response) ->
       Debug.error("Scanning.next error", response)
       if (error_function)
-        error_function(response)+        error_function(response)


Tests: Register: Fixed registerUserWithGravatarEmail test.

--- tests/src/register/register.coffee
+++ tests/src/register/register.coffee
@@ -23,8 +23,8 @@
     helpers.attemptEnterEmailAndPasswordOnRegister(browser, user)

     browser
-      .pause   2000
-      .element 'css selector', '.login-input-view.validation-error', (result) =>
+      .pause   5000
+      .element 'css selector', '[testpath=main-sidebar]', (result) =>

         if result.status is 0
           browser.end()


Implemented the update repo endpoint

Implemented the update repo endpoint

--- app.coffee
+++ app.coffee
@@ -70,8 +70,12 @@
 )

 app.post('/update', (req, res) ->
-
-
+	hakiApp.update((error) ->
+		if error
+			res.send(500)
+		else
+			res.send(204)
+	)
 )

 app.listen(80)


Updates

Updates

--- app.coffee
+++ app.coffee
@@ -8,7 +8,13 @@

 startStaticServer = (dirname) ->
   staticServerPort += 1
-  fileServer = new nodeStatic.Server(dirname)
+  fileServer = new nodeStatic.Server(dirname,
+    headers: {
+        "Cache-Control": "no-cache, no-store, must-revalidate",
+        "Pragma": "no-cache",
+       "Expires": 0
+     }
+  )
   staticServer = {
     port: staticServerPort
     dirname: dirname


Force lowercase version number

Force lowercase version number

Closes #6

--- app.coffee
+++ app.coffee
@@ -314,7 +314,7 @@
 											return
 										versionNumber = versionPackageXml.package.packageinformation[0].version[0]
 										# the tar file is incorrectly named -> abort
-										if (versionNumber.replace (new RegExp ' ', 'g'), '_') isnt path.basename versionFile, '.tar'
+										if (versionNumber.toLowerCase().replace (new RegExp ' ', 'g'), '_') isnt path.basename versionFile, '.tar'
 											fileCallback "version number does not match file (#{versionNumber.replace new RegExp(' ', 'g'), '_'} != #{path.basename versionFile, '.tar'})"
 											return

@@ -433,7 +433,7 @@
 				writer.writeElement 'timestamp', String(Math.floor (do version.timestamp.getTime) / 1000)

 				# e.g. {{packageServerHost}}/com.example.wcf.test/1.0.0_Alpha_15
-				writer.writeElement 'file', "{{packageServerHost}}/#{_package.name}/#{versionNumber.replace (new RegExp ' ', 'g'), '_'}"
+				writer.writeElement 'file', "{{packageServerHost}}/#{_package.name}/#{versionNumber.toLowerCase().replace (new RegExp ' ', 'g'), '_'}"

 				# try to extract license
 				if version.license
@@ -475,14 +475,14 @@
 # package download requested
 app.all /^\/([a-z0-9_-]+\.[a-z0-9_-]+(?:\.[a-z0-9_-]+)+)\/([0-9]+\.[0-9]+\.[0-9]+(?:_(?:a|alpha|b|beta|d|dev|rc|pl)_[0-9]+)?)\/?(?:\?.*)?$/i, (req, res) ->
 	callback = (username) ->
-		fs.exists "#{config.packageFolder}/#{req.params[0]}/#{req.params[1]}.tar", (packageExists) ->
+		fs.exists "#{config.packageFolder}/#{req.params[0]}/#{req.params[1].toLowerCase()}.tar", (packageExists) ->
 			if packageExists
 				if isAccessible username, req.params[0], req.params[1]
-					logger.log "notice", "#{username} downloaded #{req.params[0]}/#{req.params[1]}"
+					logger.log "notice", "#{username} downloaded #{req.params[0]}/#{req.params[1].toLowerCase()}"
 					res.attachment "#{req.params[0]}_#{req.params[1]}.tar"
-					res.sendfile "#{config.packageFolder}/#{req.params[0]}/#{req.params[1]}.tar", (err) -> res.send 404, '404 Not Found' if err?
+					res.sendfile "#{config.packageFolder}/#{req.params[0]}/#{req.params[1].toLowerCase()}.tar", (err) -> res.send 404, '404 Not Found' if err?
 				else
-					logger.log "notice", "#{username} tried to download #{req.params[0]}/#{req.params[1]}"
+					logger.log "notice", "#{username} tried to download #{req.params[0]}/#{req.params[1].toLowerCase()}"
 					res.setHeader 'WWW-Authenticate', 'Basic realm="Please provide proper username and password to access this package"'
 					res.send 401, 'Please provide proper username and password to access this package'
 			else
@@ -514,7 +514,7 @@
 	unless versionNumber?
 		res.send 404, '404 Not Found'
 		return
-	res.redirect 301, "#{host}/#{req.params[0]}/#{versionNumber.replace (new RegExp ' ', 'g'), '_'}"
+	res.redirect 301, "#{host}/#{req.params[0]}/#{versionNumber.toLowerCase().replace (new RegExp ' ', 'g'), '_'}"

 # manual update via {{packageServerHost}}/update
 if config.enableManualUpdate


Fixed bad rename in app.coffee

Fixed bad rename in app.coffee

--- app.coffee
+++ app.coffee
@@ -11,8 +11,8 @@
 #bliss        = require "./lib/view.bliss.plugin.coffee"
 jshtml       =  require path.join(modules, "view.jshtml.plugin.coffee")
 parse        =  require path.join(modules, "parse.plugin.coffee")
-sessions     =  require path.join(modules, "sessions.coffee")
-auths		 =  require path.join(modules, "auths.coffee")
+sessions     =  require path.join(modules, "session_helper.coffee")
+auths		 =  require path.join(modules, "auth_helper.coffee")

 app = flatiron.app
 app.use flatiron.plugins.http


remove fs.mkdirParent

remove fs.mkdirParent

--- app.coffee
+++ app.coffee
@@ -45,13 +45,6 @@
       else
         send404 response

-fs.mkdirParent = (dirPath, next) ->
-  fs.mkdir dirPath, '0755', (err)->
-    if err and err.errno is 34
-      fs.mkdirParent(path.dirname(dirPath), next)
-      fs.mkdirParent(dirPath, next)
-    next(err) if next
-
 pathVideo = (data, fileName)->
   ext = fileName.split('.')
   if env is 'development'
@@ -98,19 +91,17 @@
       getFilmPath fields.idFile, (err, data) ->
         send500(res, err) if err

-        fs.mkdirParent data.path, (err)->
+        finalPath = pathVideo data, files.videoFile.name
+        console.log 'pathVideo', finalPath
+        fs.rename files.videoFile.path, finalPath, (err)->
           send500(res, err) if err
-          finalPath = pathVideo data, files.videoFile.name
-          console.log 'pathVideo', finalPath
-          fs.rename files.videoFile.path, finalPath, (err)->
+
+          setSuccess {id: fields.idFile, path: finalPath, size: files.videoFile.size}, (err, data) ->
             send500(res, err) if err

-            setSuccess {id: fields.idFile, path: finalPath, size: files.videoFile.size}, (err, data) ->
-              send500(res, err) if err
-
-              res.writeHead 200, {'content-type': 'text/plain'}
-              res.write 'received upload:\n\n'
-              res.end()
+            res.writeHead 200, {'content-type': 'text/plain'}
+            res.write 'received upload:\n\n'
+            res.end()

     form.on 'progress', (bytesReceived, bytesExpected)->
       process.stdout.write(bytesReceived + ' ' + bytesExpected + "\r");


added example server load tcp server

added example server load tcp server

--- app.coffee
+++ app.coffee
@@ -122,3 +122,26 @@
 setInterval () ->
 	ProjectPersistenceManager.clearExpiredProjects()
 , tenMinutes = 10 * 60 * 1000
+
+
+
+net = require('net')
+os = require('os')
+
+fiveMinLoad = os.loadavg()[1]
+availableWorkingCpus = os.cpus().length - 1
+freeLoad = availableWorkingCpus - fiveMinLoad
+freeLoadPercentage = Math.round((freeLoad / availableWorkingCpus) * 100)
+
+server = net.createServer (socket) ->
+  socket.write "#{freeLoadPercentage}%\n", "ASCII"
+  socket.pipe socket
+  return
+
+port = 4080
+
+server.listen port,  ->
+  console.log "listening on port #{port}"
+  # netcat 127.0.0.1 4080
+
+


Grammar and style edits on the animal descriptions

--- app/translations/en_us.coffee
+++ app/translations/en_us.coffee
@@ -208,7 +208,7 @@
     beaver:
       label: 'Beaver'
       description: '''
-        Usually brown with large sharp front teeth, front feet has claws, back feet are webbed, round body, and a large flat tail. As the second largest rodent in the world, beavers are semi-aquatic and primarily nocturnal.
+        This animal is usually brown with large sharp front teeth, clawed front feet, webbed back feet, a round body, and a large flat tail. As the second largest rodent in the world, beavers are semi-aquatic and primarily nocturnal.
       '''

     bike:
@@ -226,55 +226,55 @@
     chipmunk:
       label: 'Chipmunk'
       description: '''
-        A small member of the squirrel family that use their cheek pouches to carry various foods of nuts, berries, seeds, etc into their burrow or nest to store their food. These have smaller less bushy tails than a typical squirrel and sport signature white and brown stripes around their eye and going down their back. Typically brown or tan in color.
+        A small member of the squirrel family that use their cheek pouches to carry various nuts, berries and seeds into their burrow or nest to store their food. They have smaller, less bushy tails than a typical squirrel and sport signature white and brown stripes around their eye and going down their back. Typically brown or tan in color.
       '''

     coyote:
       label: 'Coyote'
       description: '''
-        Commonly brown and tan in color, this member of the dog family is smaller than wolves and have occasionally been called prairie wolves or brush wolves due to their wolf like appearance. Although, they differ from wolves with their pointed snouts, slender body, and tall, pointy ears. In the fall and winter they form packs for more effective hunting.
+        Commonly brown and tan in color, this member of the dog family is smaller than a wolf. They have occasionally been called prairie wolves or brush wolves due to their wolf like appearance, but they differ from wolves with their pointed snouts, slender body, and tall, pointy ears. In the fall and winter, they form packs for more effective hunting.
       '''

     deer:
       label: 'Deer'
       description: '''
-        A fairly big, tan animal that is in the same family as moose and reindeer. They have large ears and short fluffy tails. The males are called bucks while females are called does and the young are called fawns. Some males may have antlers depending on the time of the year.
+        A fairly big, tan animal that is in the same family as moose and reindeer. They have large ears and short fluffy tails. The males are called bucks while females are called does, and the young are called fawns. Some males may have antlers depending on the time of the year.
       '''

     domCat:
       label: 'Cat, Domestic'
       description: '''
-        A common household pet with a small build, long tails, and small pointed ears. This animals come in a variety of color, patterns (spotted or stripes), and breeds.
+        A common household pet with a small build, a long tail, and small pointed ears. This animal comes in a variety of color, patterns (spotted or stripes), and breeds.
       '''

     domDog:
       label: 'Dog, Domestic'
       description: '''
-        A common household pet related to wolves, foxes, and jackals, but come in a variety of colors, sizes, patterns, and breeds.
+        A common household pet related to wolves, foxes, and jackals. This animal comes in a variety of colors, sizes, patterns, and breeds.
       '''

     flyingSquirrel:
       label: 'Squirrel, Flying'
       description: '''
-        A member of the squirrel family, this animal has large, dark eyes, loose skin between the front and back legs, clawed feet, and a long, bushy tail with dark fur on top and light below. It travels from tree to tree by launching itself and spreading its limbs so it can glide, while using its legs to steer and its tail to brake when it reaches its destination.
+        A member of the squirrel family, this animal has large, dark eyes, loose skin between the front and back legs, clawed feet, and a long, bushy tail with dark fur on top and light below. It travels from tree to tree by launching itself and spreading its limbs so it can glide while using its legs to steer and its tail to brake when it reaches its destination.
       '''

     foxSquirrel:
       label: 'Squirrel, Fox'
       description: '''
-        The largest species of tree squirrel in North America, they look like a larger typical squirrel with an orange tone to their fur. They can be around 2 feet in length and weight 1 - 2 lbs. It spends most time in forging food and roaming around fields.
+        The largest species of tree squirrel in North America, they look like a larger typical squirrel with an orange tone to their fur. They can be around 2 feet in length and weight 1 - 2 lbs. It spends most of its time forging food and roaming around fields.
       '''

     grayFox:
       label: 'Fox, Gray'
       description: '''
-        A small to medium sized animal with gray coat on its back and head with light fur on its chest and belly. They have a signature black tipped, bushy tail and band of black fur from the inner corner of their eyes around the bottom of their snout. They are tree climbers, typically sleep during the day at very rocky locations, and are active during the night.
+        A small to medium sized animal with a gray coat on its back and head with light fur on its chest and belly. They have a signature black tipped, bushy tail and a band of black fur from the inner corner of their eyes around the bottom of their snout. They are tree climbers, typically sleep during the day at very rocky locations, and are active during the night.
       '''

     graySquirrel:
       label: 'Squirrel, Gray'
       description: '''
-        Small squirrels that are gray-brown all over their bodies except the white patch along their belly. This animals diet consists of acorns, hickory nuts, maple, walnuts, etc.
+        Small squirrels that are gray-brown all over their bodies except the white patch along their belly. This animal's diet consists of acorns, hickory nuts, maple and walnuts.
       '''

     horse:
@@ -316,13 +316,13 @@
     muskrat:
       label: 'Muskrat'
       description: '''
-        This animal normally has brown fur and a black tail with small dark eyes. The furless, scaly tail is half of its total length. When it walks, the tail creates a trail. Their front paws are clawed while in the rear they are semi-webbed clawed feet.
+        This animal normally has brown fur and a black tail with small dark eyes. The fur-less, scaly tail is half of its total length. When it walks, the tail creates a trail. Their front paws are clawed while  the rear feet are semi-webbed and clawed.
       '''

     opossum:
       label: 'Opossum'
       description: '''
-        Adept tree climbers with their clawed feet and opposable big toe on rear paw. This animal known for playing dead has a white face with a pink nose,  black eyes, black ears, long tail and long, gray fur on their body.
+        Adept tree climbers with their clawed feet and opposable big toe on rear paw. This animal is known for playing dead and has a white face with a pink nose, black eyes, black ears, long tail and long, gray fur on their body.
       '''

     otherVehicle:
@@ -340,37 +340,37 @@
     raccoon:
       label: 'Raccoon'
       description: '''
-        This brown-gray furry animal looks like it’s wearing a bandit mask with the black patches around its eyes on its white face. Another notable features are its finger like clawed toes and its black-ringed tail with long fur. Raccoons are nocturnal and often seen foraging for food in trash bins.
+        This brown-gray furry animal looks like it is wearing a bandit mask with the black patches around its eyes on its white face. Another notable features are its finger like clawed toes and its black-ringed tail with long fur. Raccoons are nocturnal and often seen foraging for food in trash bins.
       '''

     rat:
       label: 'Rat'
       description: '''
-        A large mouse like critter with a pointy nose, round ears, and a long, hairless, pinkish tail. Many people think they only roam the subway and sewers, but its not uncommon to see then running across the street above ground.
+        A large mouse-like critter with a pointy nose, round ears, and a long, hairless, pinkish tail. Many people think they only roam the subway and sewers, but it is not uncommon to see then running across the street above ground.
       '''

     redFox:
       label: 'Fox, Red'
       description: '''
-        An animal with orange brownish fur along its head and back with and white fur on its belly and typically at the tip of its bushy tail. It’s tail helps it balance just like a cat’s. Some have black fur on the back of its ears and legs.
+        An animal with orange brownish fur along its head and back with and white fur on its belly and typically at the tip of its bushy tail. Its tail helps it balance just like a cat’s. Some have black fur on the back of its ears and legs.
       '''

     skunk:
       label: 'Skunk'
       description: '''
-        An animal, well known for its stinky spray towards predators, has black with white stripe patterns. It has a single thin, white stripe down the middle of its face and two, thicker white stripes originated at the top of its head running down either side of the back into its thick, bushy tail.
+        An animal well known for its stinky spray towards predators and black coat with white stripe patterns. It has a single thin, white stripe down the middle of its face and two, thicker white stripes originated at the top of its head running down either side of the back into its thick, bushy tail.
       '''

     woodChuck:
       label: 'Woodchuck'
       description: '''
-        This animal is also known as a groundhog. It has a brown furry coat, clawed feets, small eyes and ears, and a short, flat tail.
+        This animal is also known as a groundhog. It has a brown furry coat, clawed feet, small eyes and ears, and a short, flat tail.
       '''

     melanisticGraySquirrel:
       label: 'Squirrel, Melanistic Gray'
       description: '''
-        Is an animal that has a color morph to change its fur from gray to black. You may occasionally see them during the color changing process, they will appear to be brown and black patchy.
+        This animal has a color morph to change its fur from gray to black. You may occasionally see them during the color changing process when they will appear to be brown and black patchy.
       '''

   differences:


Starts to add codo to the tbg-close plugin

--- vendor/assets/javascripts/styleguide/plugins/tbg-close.js.coffee
+++ vendor/assets/javascripts/styleguide/plugins/tbg-close.js.coffee
@@ -22,12 +22,28 @@
   "use strict"

   # CLOSE CLASS DEFINITION
-  # =========================
-  class Close
+  #
+  # @example How to use the class
+  #     closeInstance = new Close $('.my-element')
+  #     # Close element
+  #     closeInstance.close()
+  #
+  # @example How to use the class with jQuery
+  #     $('.my-element').close('close')
+  #
+  # @example How to enusre plugin self initalises on element
+  #     <div data-close> Close me </div>
+  #
+  class Close
+
+    # Construct a new Close instance
+    # @param [Object] element HTMLElement on which we will try to close
+    #
     constructor: ( element ) ->
       $el = $(element)
-      @$target = @_getTarget $el
+      @$target = @_getarget $el

+    # Expose the Class
     _constructor:  Close

     close : ->


Remove duplicate line

Remove duplicate line

--- app/assets/javascripts/admin/orders/controllers/orders_controller.js.coffee
+++ app/assets/javascripts/admin/orders/controllers/orders_controller.js.coffee
@@ -35,7 +35,6 @@
       # Set default checkbox values to null. See: https://github.com/openfoodfoundation/openfoodnetwork/pull/3076#issuecomment-440010498
       'q[completed_at_not_null]': $scope['q']['completed_at_not_null'] || null,
       'q[distributor_id_in]': $scope['q']['distributor_id_in'],
-      'q[order_cycle_id_in]': $scope['q']['order_cycle_id_in'],
       'q[order_cycle_id_in]': $scope['q']['order_cycle_id_in'],
       'q[s]': $scope.sorting || 'completed_at desc',
       per_page: $scope.per_page,