add 2 tests for #2054 stacktrace in API response message

--- src/smc-hub/test/api/text_files.coffee
+++ src/smc-hub/test/api/text_files.coffee
@@ -117,6 +117,7 @@
                 expect(resp?.result?.files?.length).toBe(1)
                 expect(resp?.result?.files?[0]).toIncludeKeys(['mtime','name','size'])
                 done(err)
+
     it "uses API query to make a folder public", (done) ->
         api.call
             event : 'query'
@@ -135,3 +136,14 @@
             cb    : (err, resp) ->
                 expect(resp?.data[0..1]).toEqual("PK")
                 done(err)
+
+    it "tries to list public files on nonexistent path in a public project and gets empty list", (done) ->
+        api.call
+            event : 'public_get_directory_listing'
+            body  :
+                project_id: project_id
+                path      : 'nonexistent'
+            cb    : (err, resp) ->
+                expect(resp?.event).toBe('public_directory_listing')
+                expect(resp?.result).toEqual([])
+                done(err)


set up events for tooltips and dashboard communication

--- src/controllers/Scatterplot.coffee
+++ src/controllers/Scatterplot.coffee
@@ -55,7 +55,6 @@
     while tick < max
       ticks.push tick
       tick = tick + tickWidth
-
     return ticks

   start: =>


client: welcome: sendInvitation action added

--- client/app/lib/flux/teams/actions.coffee
+++ client/app/lib/flux/teams/actions.coffee
@@ -15,6 +15,7 @@
 kookies = require 'kookies'
 Tracker = require 'app/util/tracker'
 VerifyPasswordModal = require 'app/commonviews/verifypasswordmodal'
+{ actions : HomeActions } = require 'home/flux'

 loadTeam = ->

@@ -114,6 +115,8 @@

       if invitations.length > 1 or pendingInvites?.size
         title = 'All invitations are sent.'
+        HomeActions.markAsDone 'sendInvitations'
+

       Tracker.track Tracker.TEAMS_SENT_INVITATION  for invite in invitations


clean up lightcurve-viewer code

clean up lightcurve-viewer code

--- app/controllers/lightcurve-viewer.coffee
+++ app/controllers/lightcurve-viewer.coffee
@@ -1,19 +1,8 @@
 BaseController             = require 'zooniverse/controllers/base-controller'
-# User                       = require 'zooniverse/models/user'
-# Subject                    = require 'zooniverse/models/subject'
 NoUiSlider                 = require '../lib/jquery.nouislider.min'
-# translate                  = require 't7e'
 {CanvasGraph, Marks, Mark} = require "../lib/canvas-graph"
+
 $ = window.jQuery
-
-getParameterByName = (name) ->
-  name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]")
-  regex = new RegExp("[\\?&]" + name + "=([^&#]*)")
-  results = regex.exec(location.search)
-  (if not results? then "" else decodeURIComponent(results[1].replace(/\+/g, " ")))
-
-# JSON_FILE = getParameterByName "JsonFile"
-# console.log 'JSON_FILE: ', JSON_FILE # DEBUG code

 class LightcurveViewer extends BaseController
   className: 'lightcurve-viewer'
@@ -26,38 +15,17 @@
   constructor: (jsonFile) ->
     super
     window.viewer = @
-
     @jsonFile = jsonFile
-    # if jsonFile?
-    #   JSON_FILE = jsonFile
-      # console.log 'jsonFile: ', JSON_FILE

     isZoomed: false
     ifFaved: false
-
-    # User.on 'change', @onUserChange
-    # Subject.on 'fetch', @onSubjectFetch
-    # Subject.on 'select', @onSubjectSelect
-    # @Subject = Subject

     @marksContainer = @el.find('#marks-container')[0]
     @loadSubjectData()

-  # onUserChange: (e, user) =>
-  #   # if User.current? # user logged in
-  #   #   # do something
-
-  # onSubjectFetch: (e, user) =>
-
-  # onSubjectSelect: (e, subject) =>
-  #   @subject = subject
-  #   # @classification = new Classification {subject}
-  #   @loadSubjectData()
-
   loadSubjectData: () ->
     console.log  'JSON_FILE: ', @jsonFile
     $('#graph-container').addClass 'loading-lightcurve'
-    # jsonFile = JSON_FILE #@subject.selected_light_curve.location
     # console.log 'jsonFile: ', jsonFile # DEBUG CODE

     # handle ui elements


refactor(macAutocomplete): Removed jQuery dependency and make sure it works with jqLite

--- src/directives/autocomplete.coffee
+++ src/directives/autocomplete.coffee
@@ -150,7 +150,7 @@

         reset()

-      element.on "keydown", (event) ->
+      element.bind "keydown", (event) ->
         switch event.which
           when keys.DOWN
             $scope.$apply ->
@@ -167,7 +167,7 @@

         return true

-      $(document).on "click", (event) ->
+      angular.element(document).bind "click", (event) ->
         if $menuScope.items.length > 0
           $scope.$apply -> reset()

@@ -180,7 +180,7 @@
       if inside
         element.after $compile(menuEl) $menuScope
       else
-        $(document.body).append $compile(menuEl) $menuScope
+        angular.element(document.body).append $compile(menuEl) $menuScope

       #
       # @event


open link in another window.

open link in another window.

--- chat/grails-app/assets/javascripts/chat.coffee
+++ chat/grails-app/assets/javascripts/chat.coffee
@@ -376,7 +376,7 @@
     displayTempMessages()

     if msg.text.match /^https{0,1}:\/\/.+/
-        msg.text = "#{msg.text}"
+        msg.text = "#{msg.text}"

     classQuote = ''
     if msg.text.match /^\>[ \s]+/ or msg.text.match /^>[ \s]+/


Pricing: Plan: if user has some monthly plan set monthly plan as default

--- client/pricing/lib/pricingappview.coffee
+++ client/pricing/lib/pricingappview.coffee
@@ -182,6 +182,8 @@

       @plans.setState @state

+      @selectIntervalToggle planInterval
+
       callback()


Apps: Ask approval/disapproval questions before doing

--- client/Social/Apps/Views/appdetailsview.coffee
+++ client/Social/Apps/Views/appdetailsview.coffee
@@ -74,14 +74,13 @@
       defaultState    : if app.status is 'verified' then "Disapprove" else "Approve"
       states          : [
         title         : "Approve"
-        callback      : (callback)->
-          app.approve yes, (err)->
-            if err then warn err
-            callback? err
+        callback      : (callback)=>
+          @approveApp app, yes, callback
       ,
         title         : "Disapprove"
-        callback      : (callback)->
-          app.approve no, (err)-> callback? err
+        callback      : (callback)=>
+          @approveApp app, no, callback
+
       ]
     , app

@@ -108,6 +107,27 @@
         return tmpl

     # @reviewView = new ReviewView {}, app
+
+  approveApp:(app, state, callback)->
+
+    if state
+      text  = 'approve'
+      style = 'modal-clean-green'
+    else
+      text  = 'disapprove'
+      style = 'modal-clean-red'
+
+    modal = KDModalView.confirm
+      title       : 'Are you sure?'
+      description : "Are you sure you want to #{text} this application?"
+      ok          :
+        style     : style
+        title     : text.capitalize()
+        callback  : ->
+          app.approve state, (err)->
+            if err then warn err
+            modal.destroy()
+            callback? err

   viewAppended: JView::viewAppended


Teamwork: Removed dashboard icon.

Teamwork: Removed dashboard icon.

--- client/Teamwork/Views/teamworkworkspace.coffee
+++ client/Teamwork/Views/teamworkworkspace.coffee
@@ -11,9 +11,6 @@
       @createButtons panel
       @createRunButton panel  if playground
       @getActivePanel().header.setClass "teamwork"
-      @buttonsContainer.addSubView new KDCustomHTMLView
-        cssClass : "tw-db-icon"
-        click    : => @getDelegate().dashboard.show()

     @on "WorkspaceSyncedWithRemote", =>
       if playground and @amIHost()


Use the current user nick if authorNick is not exists

--- client/app/MainApp/kodingappscontroller.coffee
+++ client/app/MainApp/kodingappscontroller.coffee
@@ -259,7 +259,7 @@
           else
             sheet = sheet.replace /(^\.\/)|(^\/+)/, ""
             $("head #app-#{__utils.slugify name}").remove()
-            $('head').append("<link id='app-#{__utils.slugify name}' rel='stylesheet' href='#{KD.appsUri}/#{manifest.authorNick}/#{__utils.stripTags name}/latest/#{__utils.stripTags sheet}'>")
+            $('head').append("<link id='app-#{__utils.slugify name}' rel='stylesheet' href='#{KD.appsUri}/#{manifest.authorNick or KD.whoami().profile.nickname}/#{__utils.stripTags name}/latest/#{__utils.stripTags sheet}'>")

     showError = (error)->
       new KDModalView


Client: Sidebar: Added getInvitationWidgetCoordinates method to calculate invitationWidget coordinates

--- client/app/lib/components/sidebar/index.coffee
+++ client/app/lib/components/sidebar/index.coffee
@@ -65,6 +65,21 @@
       machineId =  machine.get '_id'

     return machineId
+
+
+  getInvitationWidgetCoordinates : (listItem) ->
+
+    coordinates   = { top: 0, left: 0 }
+
+    if listItem
+      domNode       = ReactDOM.findDOMNode listItem
+      clientRect    = domNode.getBoundingClientRect()
+      { top, left, width } = clientRect
+      left = left + width
+      coordinates   = { top, left }
+
+    return coordinates
+

   renderInvitationWidget: ->


* minor changed.

* minor changed.

--- client/app/scripts/directives/iSlidable.coffee
+++ client/app/scripts/directives/iSlidable.coffee
@@ -73,16 +73,16 @@
             @_reset()

 Window.DragManager = DragManager
+Window.dragManager = new DragManager()

 angular.module('iReactive.slidable', ['iReactive'])
     .directive('iSlidable', ['$iReactable', ($iReactable) ->
         aProcessEvent = (model, options, scope, element, attrs, nextValueFn) ->
-            this = options
             _reset: ->
                 now = new Date()
-                if now - @lastClick < 500
-                    model.assign(scope, @defaultValue)
-                @lastClick = now
+                if now - options.lastClick < 500
+                    model.assign(scope, options.defaultValue)
+                options.lastClick = now
                 return

             element.bind('click', (el)->


TerminalPane: Create terminal with joinUser and session if exists.

--- client/ide/workspace/panes/terminalpane.coffee
+++ client/ide/workspace/panes/terminalpane.coffee
@@ -13,13 +13,24 @@
     @createTerminal()

   createTerminal: ->
-    @webtermView       = new WebTermView
+    options =
       delegate         : this
       readOnly         : @getOption 'readOnly'
       machine          : @machine
-      mode             : @getMode()
+      mode             : 'create'
       cssClass         : 'webterm'
       advancedSettings : no
+
+
+    {joinUser, session} = @getOptions()
+
+    if joinUser and session
+      # TODO: Also pass sizeX and sizeY
+      options.joinUser = joinUser
+      options.session  = session
+      options.mode     = 'shared'
+
+    @webtermView = new WebTermView options

     @addSubView @webtermView


client: minor fix

client: minor fix

--- client/landing/Login/Views/registerform.coffee
+++ client/landing/Login/Views/registerform.coffee
@@ -180,7 +180,7 @@

Your username must be at least 4 characters and it’s also going to be your {{> @domain}} domain.

{{> @button}}

-
By signing up to Koding, you indicate that you have read and agree to the Terms of Service.

+
By signing up to Koding, you indicate that you have read and agree to the Terms of Service.

     {{> @invitationCode}}
     """


client: minor fix

client: minor fix

--- client/landing/Login/Views/registerform.coffee
+++ client/landing/Login/Views/registerform.coffee
@@ -180,7 +180,9 @@

Your username must be at least 4 characters and it’s also going to be your {{> @domain}} domain.

{{> @button}}

-
By signing up to Koding, you indicate that you have read and agree to the Terms of Service.

+

+      By creating an account, I accept Koding's  Terms of Service and Privacy Policy.
+

     {{> @invitationCode}}
     """


Disable send private message with image test

--- client/test/lib/messages/privatemessage.coffee
+++ client/test/lib/messages/privatemessage.coffee
@@ -113,12 +113,12 @@
     browser.end()

-  sendPrivateMessageWithImage: (browser) ->
+  # sendPrivateMessageWithImage: (browser) ->

-    image     = "https://koding-cdn.s3.amazonaws.com/images/default.avatar.333.png Hello World"
-    testUsers = [ @users[6] ]
+  #   image     = "https://koding-cdn.s3.amazonaws.com/images/default.avatar.333.png Hello World"
+  #   testUsers = [ @users[6] ]

-    helpers.beginTest(browser)
+  #   helpers.beginTest(browser)

-    messagesHelpers.startConversation(browser, testUsers, image)
-    browser.end()+  #   messagesHelpers.startConversation(browser, testUsers, image)
+  #   browser.end()


center map an new position

center map an new position

--- components/cms/modules/map/view/MapView.coffee
+++ components/cms/modules/map/view/MapView.coffee
@@ -10,6 +10,7 @@
       @createMap()
       @startPositionTracking()
       # @initChildren()
+      App.vent.on "newPosition", @centermap
       App.vent.on "ready", =>
         @findView = new MapListView collection: App.Finds
         @trackView = new MapTrackListView collection: App.Tracks


KDContentEditableView: do not focus if `keydown` event's target is contenteditable element

--- components/inputs/KDContentEditableView.coffee
+++ components/inputs/KDContentEditableView.coffee
@@ -106,7 +106,7 @@
       event.preventDefault()
     else if value.length is 0
       @unsetPlaceholder()
-      @focus()
+      @focus()  if event.target isnt @getEditableElement()

   paste: (event) ->
     event.preventDefault()


Remove unneeded cleanup code

Remove unneeded cleanup code

--- atom/browser/api/lib/web-contents.coffee
+++ atom/browser/api/lib/web-contents.coffee
@@ -43,9 +43,4 @@
   webContents

 module.exports.create = (options={}) ->
-  webContents = @wrap binding.create(options)
-
-  # Ensure the webContents is destroyed on exit.
-  process.on 'exit', -> webContents.destroy()
-
-  webContents
+  @wrap binding.create(options)


look up page by uuid to link to it

look up page by uuid to link to it

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -107,9 +107,15 @@
       @cc.handleClose()
       @cc.setOptions(options)

+    lookUpPageByUuid: (uuid) ->
+      {allPages} = @parent.parent.regions.sidebar.views[0]
+      _.find(allPages, (page) ->
+        page.getUuid() is uuid
+      )
+
     updatePageFromCCNav: ({collectionUUID, moduleUUID, link}) =>
       if @model.getUuid() is collectionUUID
-        page = @model.getPage(moduleUUID)
+        page = @lookUpPageByUuid(moduleUUID)

         if page?


Fixing a spelling mistake in Alder Spiked Shield

--- lib/completion.coffee
+++ lib/completion.coffee
@@ -1891,7 +1891,7 @@
     { snippet: '"Crested Tower Shield"' },
     { snippet: '"Lacewood Spirit Shield"' },
     { snippet: '"Ironwood Buckler"' },
-    { snippet: '"Alder Spike Shield"' },
+    { snippet: '"Alder Spiked Shield"' },
     { snippet: '"Shagreen Tower Shield"' },
     { snippet: '"Teak Round Shield"' },
     { snippet: '"Branded Kite Shield"' },


Clear cycles on reset

Clear cycles on reset

--- lib/dispatcher.coffee
+++ lib/dispatcher.coffee
@@ -75,6 +75,7 @@
   _reset: ->
     @_dependency_count = {}
     @_state = {}
+    @_cycles = {}
     @deps = {}
     @doc = null
     @_control_channel.reset()


Provide more context on GotoView

Provide more context on GotoView

--- lib/go-to-view.coffee
+++ lib/go-to-view.coffee
@@ -2,6 +2,7 @@
 Q = require 'q'
 SymbolsView = require './symbols-view'
 TagReader = require './tag-reader'
+{$$, Point, SelectListView} = require 'atom'

 module.exports =
 class GoToView extends SymbolsView
@@ -13,7 +14,7 @@
       @li class: 'two-lines', =>
         @div name, class: 'primary-line'
         if position
-          text = "Line #{position.row + 1}"
+          text = "#{file}:#{position.row + 1}"
         else
           text = path.basename(file)
         @div text, class: 'secondary-line'


Change overdraw default

Change overdraw default

--- lib/table-edit.coffee
+++ lib/table-edit.coffee
@@ -20,7 +20,7 @@
       default: 16
     rowOverdraw:
       type: 'integer'
-      default: 10
+      default: 3

   activate: (state) ->
     Table ?= require './table'


switched to class pattern

switched to class pattern

--- both/publisher.coffee
+++ both/publisher.coffee
@@ -1,5 +1,5 @@
-Publisher =
-  setupTemplate: (templateName, definition) ->
+@Publisher = class Publisher
+  @setupTemplate: (templateName, definition) ->
     check templateName, String
     check definition, Publisher.Definition

@@ -37,5 +37,5 @@
         @autorun =>
           @subscribe definition.name, @data, @subscribeParams.get()

-  Definition: Definition
-  Utilities: Utilities
+  @Definition: Definition
+  @Utilities: Utilities


Limit notification sound to play ended or 4096ms.

--- views/env.coffee
+++ views/env.coffee
@@ -57,29 +57,21 @@
 NOTIFY_NOTIFICATION_API = true
 if process.platform == 'win32' and semver.lt(os.release(), '6.2.0')
   NOTIFY_NOTIFICATION_API = false
-playing = false
+notify_isPlayingAudio = {}
 window.notify = (msg, options) ->
   # Notification config
   enabled = config.get('poi.notify.enabled', true)
-  audio = config.get('poi.notify.audio', "file://#{ROOT}/assets/audio/poi.mp3")
   volume = config.get('poi.notify.volume', 0.8)
   title = 'poi'
   icon = NOTIFY_DEFAULT_ICON
-  switch options?.type
-    when 'construction'
-      enabled = config.get('poi.notify.construction.enabled', enabled) if enabled
-      audio = config.get('poi.notify.construction.audio', audio)
-    when 'expedition'
-      enabled = config.get('poi.notify.expedition.enabled', enabled) if enabled
-      audio = config.get('poi.notify.expedition.audio', audio)
-    when 'repair'
-      enabled = config.get('poi.notify.repair.enabled', enabled) if enabled
-      audio = config.get('poi.notify.repair.audio', audio)
-    when 'morale'
-      enabled = config.get('poi.notify.morale.enabled', enabled) if enabled
-      audio = config.get('poi.notify.morale.audio', audio)
-    else
-      enabled = config.get('poi.notify.others.enabled', enabled) if enabled
+  audio = config.get('poi.notify.audio', "file://#{ROOT}/assets/audio/poi.mp3")
+  type = options?.type || "others"
+
+  if type in ['construction', 'expedition', 'repair', 'morale']
+    enabled = config.get("poi.notify.#{type}.enabled", enabled) if enabled
+    audio = config.get("poi.notify.#{type}.audio", audio)
+  else
+    enabled = config.get("poi.notify.others.enabled", enabled) if enabled
   # Overwrite by options
   if options?
     title = options.title if options.title
@@ -104,14 +96,18 @@
           content: msg
         appIcon.on 'balloon-click', remote.getGlobal('mainWindow').focus

-  if volume > 0.0001 && !playing
+  if volume > 0.0001 && !notify_isPlayingAudio[type]
+    notify_isPlayingAudio[type] = true
     sound = new Audio(audio)
     sound.volume = volume
+    timer = setTimeout ->
+      sound.onended = null
+      notify_isPlayingAudio[type] = false
+    , 4096
+    sound.onended = ->
+      clearTimeout timer
+      notify_isPlayingAudio[type] = false
     sound.play()
-    sound.onplay = (e) ->
-      playing = true
-    sound.onended = (e) ->
-      playing = false

 modals = []
 window.modalLocked = false


Sorting out messiness with string quotes

--- app/lib/en.coffee
+++ app/lib/en.coffee
@@ -1129,15 +1129,15 @@

   story:
     title: 'The Story So Far'
-    p1: "Galaxy Zoo is now arguably the world’s best-known online citizen science project, and is certainly the one with the largest number of publications based on citizen scientists input. Our success inspired the creation of The Zooniverse, hosting project using the same technique across many research areas."
-    p2: "It all started back in July 2007, with a data set made up of a million galaxies imaged by the Sloan Digital Sky Survey, who still provide some of the images in the site today. With so many galaxies, we'd assumed it would take years for visitors to the site to work through them all, but within 24 hours of launch we were stunned to be receiving almost 70,000 classifications an hour. In the end, more than 50 million classifications were received by the project during its first year, contributed by more than 150,000 people."
+    p1: 'Galaxy Zoo is now arguably the world’s best-known online citizen science project, and is certainly the one with the largest number of publications based on citizen scientists input. Our success inspired the creation of The Zooniverse, hosting project using the same technique across many research areas.'
+    p2: 'It all started back in July 2007, with a data set made up of a million galaxies imaged by the Sloan Digital Sky Survey, who still provide some of the images in the site today. With so many galaxies, we assumed it would take years for visitors to the site to work through them all, but within 24 hours of launch we were stunned to be receiving almost 70,000 classifications an hour. In the end, more than 50 million classifications were received by the project during its first year, contributed by more than 150,000 people.'
     p3: "That meant that many different participants saw each galaxy. This is deliberate; having multiple independent classifications of the same object is important, as it allows us to assess how reliable our results are. For example, for projects where we may only need a few thousand galaxies but want to be sure they're all spirals before using up valuable telescope time on them, there's no problem — we can just use those that 100% of classifiers agree are spiral. For other projects, we may need to look at the properties of hundreds of thousands of galaxies, and can use those that a majority say are spiral."
-    p4: "The task in that first Galaxy Zoo was slightly simpler than yours; all we asked volunteers to do was to split the galaxies into ellipticals, mergers and spirals and — if the galaxy was spiral — to record the direction of the arms. But it was enough to show that the classifications Galaxy Zoo provides were as good as those from professional astronomers, and were of use to a large number of researchers. You can find out what people have been up to with Galaxy Zoo data in our list of papers published and on the Galaxy Zoo blog, as well as below. Apart from the publications, another tangible sign of success is the fact that we’ve been granted time on some of the largest telescopes in the world to follow up on many Galaxy Zoo discoveries: the list currently includes the Isaac Newton and William Herschel Telescopes on the island of La Palma in the Canaries, Gemini South in Chile, the WIYN telescope on Kitt Peak, Arizona, the IRAM radio telescope in Spain's Sierra Nevada, The Very Large Array in New Mexico, Swift, GALEX, Chandra, XMM-Newton and Suzaku up in space, and perhaps most excitingly the Hubble Space Telescope."
+    p4: 'The task in that first Galaxy Zoo was slightly simpler than yours; all we asked volunteers to do was to split the galaxies into ellipticals, mergers and spirals and — if the galaxy was spiral — to record the direction of the arms. But it was enough to show that the classifications Galaxy Zoo provides were as good as those from professional astronomers, and were of use to a large number of researchers. You can find out what people have been up to with Galaxy Zoo data in our list of papers published and on the Galaxy Zoo blog, as well as below. Apart from the publications, another tangible sign of success is the fact that we’ve been granted time on some of the largest telescopes in the world to follow up on many Galaxy Zoo discoveries: the list currently includes the Isaac Newton and William Herschel Telescopes on the island of La Palma in the Canaries, Gemini South in Chile, the WIYN telescope on Kitt Peak, Arizona, the IRAM radio telescope in the Sierra Nevada of Spain, The Very Large Array in New Mexico, Swift, GALEX, Chandra, XMM-Newton and Suzaku up in space, and perhaps most excitingly the Hubble Space Telescope.'
     p5: "The second phase of Galaxy Zoo was inspired by our newfound confidence in the ability of you, our volunteer classifiers, and so we asked for a closer look at just over 200,000 of the brightest of the Sloan galaxies. We asked about the number of spiral arms, the size of the galaxies' bulges and much else besides. Once again, we were thrilled with the response (and a little more prepared for it than we were for Zoo 1!) and in the 14 months the site was up we received a little more than 60 million classifications."
-    p6: "Along the way, we added more detailed images from an area of the survey known as 'Stripe 82', but it was soon time to look at the more distant Universe. The site’s third incarnation, Galaxy Zoo: Hubble drew from surveys conducted by the Hubble Space Telescope to view earlier epochs of galaxy formation. In these surveys, which involve many, many days of dedicated observing time, we can see light from galaxies, which has taken billions of years to reach us. The idea behind Galaxy Zoo: Hubble was to be able to compare galaxies then to galaxies now, giving us a clear understanding of what factors influence their growth, whether through mergers, active black holes or simply star formation. Our publications already include several results from this phase of the project. "
+    p6: '''Along the way, we added more detailed images from an area of the survey known as 'Stripe 82', but it was soon time to look at the more distant Universe. The site’s third incarnation, Galaxy Zoo: Hubble drew from surveys conducted by the Hubble Space Telescope to view earlier epochs of galaxy formation. In these surveys, which involve many, many days of dedicated observing time, we can see light from galaxies, which has taken billions of years to reach us. The idea behind Galaxy Zoo: Hubble was to be able to compare galaxies then to galaxies now, giving us a clear understanding of what factors influence their growth, whether through mergers, active black holes or simply star formation. Our publications already include several results from this phase of the project.'''
     p7: "The Galaxy Zoo site relaunched with an updated design in September 2014. In this version we combined new imaging from Sloan, giving us our best ever view of the local Universe, with the most distant images yet from Hubble's CANDELS survey. The CANDELS survey makes use of the new Wide Field Camera 3 — installed during the final shuttle mission to Hubble — to take ultra-deep images of the Universe. Our first surprise in this data was that contrary to predictions, galactic bars are still found in the most distant galaxies. Stay tuned to see what else we’ll discover!"
-    p8: "The relaunched site also allowed us more flexibility to include smaller sets of galaxies. We have included images taken with the United Kingdom Infrared Telescope (UKIRT), in Hawai'i, for the recently completed UKIDSS project. UKIDSS is the largest, deepest survey of the sky at infrared wavelengths. The UKIDSS infrared-light pictures and the SDSS visible-light pictures are different for two reasons. Firstly, older stars are brighter in infrared wavelengths (while in visible-light we see younger stars), and secondly, infrared light, like a fog light, can penetrate the dust and smoke in the centres of galaxies. Examining the UKIDSS images in Galaxy Zoo will enable us to see how old and young stars are arranged differently in the galaxies, and will reveal more of the structure in the inner parts of galaxies."
-    p9: "The data being put into Galaxy Zoo can now change quickly, thanks to the dedicated work of volunteers and the "retirement" of images that have already been completed. One of the new sets of images to be classified comes from the Dark Energy Camera Legacy Survey (DECaLS), a survey which uses DECam, one of the most sensitive and widest-area cameras ever built and a key tool in our search to measure and understand dark energy. The camera, which is mounted on the 4-m Blanco telescope at CTIO in Chile, images the sky at similar wavelengths to SDSS, but with better resolution and with the ability to detect much fainter galaxies. These images are extending the reach of the science we began with Galaxy Zoo 2 and SDSS. Finally, the site also has Galaxy Zoo's first-ever images of fully simulated galaxies; these are images that have been created entirely on a computer, using sophisticated simulations of the Universe starting just after the Big Bang and then watching as dark matter, gas, and stars evolve to form the galaxies we see today. Your classifications of these images, which come from the Illustris project, are a vital test of the physics that go into these simulations. We are asking if our most sophisticated computer models can predict the distribution of galaxy morphologies seen in the real Universe. "
+    p8: '''The relaunched site also allowed us more flexibility to include smaller sets of galaxies. We have included images taken with the United Kingdom Infrared Telescope (UKIRT), in Hawai'i, for the recently completed UKIDSS project. UKIDSS is the largest, deepest survey of the sky at infrared wavelengths. The UKIDSS infrared-light pictures and the SDSS visible-light pictures are different for two reasons. Firstly, older stars are brighter in infrared wavelengths (while in visible-light we see younger stars), and secondly, infrared light, like a fog light, can penetrate the dust and smoke in the centres of galaxies. Examining the UKIDSS images in Galaxy Zoo will enable us to see how old and young stars are arranged differently in the galaxies, and will reveal more of the structure in the inner parts of galaxies.'''
+    p9: '''The data being put into Galaxy Zoo can now change quickly, thanks to the dedicated work of volunteers and the "retirement" of images that have already been completed. One of the new sets of images to be classified comes from the Dark Energy Camera Legacy Survey (DECaLS), a survey which uses DECam, one of the most sensitive and widest-area cameras ever built and a key tool in our search to measure and understand dark energy. The camera, which is mounted on the 4-m Blanco telescope at CTIO in Chile, images the sky at similar wavelengths to SDSS, but with better resolution and with the ability to detect much fainter galaxies. These images are extending the reach of the science we began with Galaxy Zoo 2 and SDSS. Finally, the site also has Galaxy Zoo's first-ever images of fully simulated galaxies; these are images that have been created entirely on a computer, using sophisticated simulations of the Universe starting just after the Big Bang and then watching as dark matter, gas, and stars evolve to form the galaxies we see today. Your classifications of these images, which come from the Illustris project, are a vital test of the physics that go into these simulations. We are asking if our most sophisticated computer models can predict the distribution of galaxy morphologies seen in the real Universe.'''

   team:
     title: 'The Galaxy Zoo Team'
@@ -1149,8 +1149,8 @@
       schawinski: 'Kevin Schawinski - Co-Founder: Astronomer, ETH Zurich
Works on the formation and evolution of galaxies and their supermassive black holes. Usually trying to get more sleep. And coffee.'
       edmondson: 'Edd Edmondson - Astronomer, University of Portsmouth
Zookeeper, aiding in accessing Sloan data, and general helper-outer.'
       keel: '''Bill Keel - Astronomer, University of Alabama
Author of 'The Road to Galaxy Formation' and 'The Sky at Einstein's Feet'. With research interests in galaxy formation and evolution, dust content of galaxies, and active galactic nuclei, he couldn't stay away when Galaxy Zoo got started.'''
-      cardamone: '''Carie Cardamone - Astronomer, Wheelock College
An educator and astronomer, studying the Zoo's green peas, interested in understanding why galaxies grow they way they do. She's very enthusiastic about engaging the broader public in scientific research and the nature of science.'''
-      willett: 'Kyle Willett - Lead Data Scientist: Astronomer, University of Minnesota
  Studies the roles of both morphology and environment on galaxies and their active black holes. He lead the data reduction and catalog creation from Galaxy Zoo 2 classifications, has worked on building new tools to enable independent research by citizen science volunteers and now leads efforts to include new data sets in Galaxy Zoo. In his spare time, he runs probably more than is healthy.'
+      cardamone: '''Carie Cardamone - Astronomer, Wheelock College
An educator and astronomer, studying the Zoo's green peas, interested in understanding why galaxies grow they way they do. She's very enthusiastic about engaging the broader public in scientific research and the nature of science.'''
+      willett: 'Kyle Willett - Lead Data Scientist: Astronomer, University of Minnesota
  Studies the roles of both morphology and environment on galaxies and their active black holes. He lead the data reduction and catalog creation from Galaxy Zoo 2 classifications, has worked on building new tools to enable independent research by citizen science volunteers and now leads efforts to include new data sets in Galaxy Zoo. In his spare time, he runs probably more than is healthy.'
       casteels: 'Kevin Casteels - Astronomer, University of Victoria
  Interested in galaxy evolution and morphologies, specifically how they are affected by mergers and interactions.  Kevin is currently working with the makers of the Starry Night astronomy software, helping to develop new astronomy apps and keep the systems running!  In his spare time he is also a SCUBA instructor and loves the great outdoors.'
       urry: 'Meg Urry - Physicist, Yale University
Works on supermassive black holes (growth history, unification, relativistic jets, blazars) and their interplay with galaxies. In her spare time, she writes for CNN.com and works to increase the participation of women and minorities in science.'
       nichol: '''Bob Nichol - Cosmologist, University of Portsmouth
An astronomer, astrophysicist and cosmologist with interests in computer science and statistics. A senior member (or 'Builder') of the Sloan Digital Sky Survey, the most ambitious digital survey of the sky ever undertaken. A long suffering supporter of Manchester City, suffering no more.'''


make cache constructor more elegant

make cache constructor more elegant

--- src/lib/cache.coffee
+++ src/lib/cache.coffee
@@ -32,11 +32,9 @@
                         redis.createClient portNum, host
                     else
                         redis.createClient host
-                if gConf.get('redis:blockchain:enabled')
-                    @blockchainEnabled = true
-                if gConf.get('redis:oldDNS:enabled')
-                    @oldDNSEnabled = true
-                    @oldDNSTTL = gConf.get('redis:oldDNS:ttl')
+                @blockchainEnabled = gConf.get 'redis:blockchain:enabled'
+                @oldDNSEnabled = gConf.get 'redis:oldDNS:enabled'
+                @oldDNSTTL = gConf.get 'redis:oldDNS:ttl'
                 @cache.on 'error', (err) =>
                     @log.error "cache errored"
                     @shutdown()


Added external FACTLINK_JQUERY for debugging purposes

--- js-library/app/js/jail_iframe/core.coffee
+++ js-library/app/js/jail_iframe/core.coffee
@@ -5,6 +5,8 @@
 window.$ = (selector, context) ->
   new jQuery.fn.init(selector, context || window.parent.document)

+window.parent.FACTLINK_JQUERY = window.$
+
 $.fn = $.prototype = jQuery.fn
 jQuery.extend $, jQuery


benchmark: comment for cbhost option

benchmark: comment for cbhost option

--- benchmarks/clients/client_process.coffee
+++ benchmarks/clients/client_process.coffee
@@ -462,6 +462,7 @@

 if opts.appAddress?
     parsedUrl = parseUrl(opts.appAddress)
+    # as request cookie domain
     opts.cbhost = "http://#{parsedUrl.hostname}"
     # host contains port
     opts.socketioUrl = "http://#{parsedUrl.host}"


fix: benchmark process won't exit

fix: benchmark process won't exit

if client bootstrap failed, benchmark process should exit

--- benchmarks/clients/client_process.coffee
+++ benchmarks/clients/client_process.coffee
@@ -530,7 +530,7 @@
         opts.eventDescriptors = eventDescriptors
         clientProcess = new ClientProcess(opts)
         clientProcess.start()
-        clientProcess.once("started", next)
+        next()
     (next)->
         resultLogger("start benchmark...")
         clientProcess.startBenchmark()


update Google Analytics Core Reporting API to v3

--- src/validator.coffee
+++ src/validator.coffee
@@ -33,7 +33,7 @@
 		name : name
 		regex : new RegExp "^#{regex}$"
 	}
-
+
 #
 # Gets the dimension which matches param
 # 	@param {string} dimension value to match
@@ -150,323 +150,408 @@

 	dimensions_regex = new RegExp dreg

-#Visitor
-addMetric 'ga:visitors', 'Visitors'
-addMetric 'ga:newVisits', 'New Visits'
-addMetric 'ga:percentNewVisits', 'Percent New Visits'
-
-addDimension 'ga:visitorType', 'Visitor Type'
-addDimension 'ga:visitCount', 'Visit Count'
-addDimension 'ga:daysSinceLastVisit', 'Days Since Last Visit'
+#User
+addDimension 'ga:userType', 'User Type'
+addDimension 'ga:sessionCount', 'Count of Sessions'
+addDimension 'ga:daysSinceLastSession', 'Days Since Last Session'
 addDimension 'ga:userDefinedValue', 'User Defined Value'

+addMetric 'ga:users', 'Users'
+addMetric 'ga:newUsers', 'New Users'
+addMetric 'ga:percentNewSessions', 'Percent New Sessions'
+
 #Session
-addMetric 'ga:visits', 'Visits'
+addDimension 'ga:sessionDurationBucket', 'Session Duration'
+
+addMetric 'ga:sessions', 'Sessions'
 addMetric 'ga:bounces', 'Bounces'
-addMetric 'ga:entranceBounceRate', 'Entrance Bounce Rate'
-addMetric 'ga:visitBounceRate', 'Visit Bounce Rate'
-addMetric 'ga:timeOnSite', 'Time On Site'
-addMetric 'ga:avgTimeOnSite', 'Average Time On Site'
-
-addDimension 'ga:visitLength', 'Visit Length'
+addMetric 'ga:sessionDuration', 'Session Duration'
+addMetric 'ga:bounceRate', 'Bounce Rate'
+addMetric 'ga:avgSessionDuration', 'Avg. Session Duration'

 #Traffic Sources
-addMetric 'ga:organicSearches', 'Organic Searches'
-
 addDimension 'ga:referralPath', 'Referral Path'
+addDimension 'ga:fullReferrer', 'Full Referrer'
 addDimension 'ga:campaign', 'Campaign'
 addDimension 'ga:source', 'Source'
 addDimension 'ga:medium', 'Medium'
+addDimension 'ga:sourceMedium', 'Source / Medium'
 addDimension 'ga:keyword', 'Keyword'
 addDimension 'ga:adContent', 'Ad Content'
 addDimension 'ga:socialNetwork', 'Social Network'
 addDimension 'ga:hasSocialSourceReferral', 'Has Social Source Referral'

-addDimension 'ga:fullReferrer', 'Full Referrer'
-addDimension 'ga:sourceMedium', 'Source Medium'
+addMetric 'ga:organicSearches', 'Organic Searches'

 #AdWords
+addDimension 'ga:adGroup', 'Ad Group'
+addDimension 'ga:adSlot', 'Ad Slot'
+addDimension 'ga:adSlotPosition', 'Ad Slot Position'
+addDimension 'ga:adDistributionNetwork', 'Ad Distribution Network'
+addDimension 'ga:adMatchType', 'Query Match Type'
+addDimension 'ga:adKeywordMatchType', 'Keyword Match Type'
+addDimension 'ga:adMatchedQuery', 'Matched Search Query'
+addDimension 'ga:adPlacementDomain', 'Placement Domain'
+addDimension 'ga:adPlacementUrl', 'Placement URL'
+addDimension 'ga:adFormat', 'Ad Format'
+addDimension 'ga:adTargetingType', 'Targeting Type'
+addDimension 'ga:adTargetingOption', 'Placement Type'
+addDimension 'ga:adDisplayUrl', 'Display URL'
+addDimension 'ga:adDestinationUrl', 'Destination URL'
+addDimension 'ga:adwordsCustomerID', 'AdWords Customer ID'
+addDimension 'ga:adwordsCampaignID', 'AdWords Campaign ID'
+addDimension 'ga:adwordsAdGroupID', 'AdWords Ad Group ID'
+addDimension 'ga:adwordsCreativeID', 'AdWords Creative ID'
+addDimension 'ga:adwordsCriteriaID', 'AdWords Criteria ID'
+addDimension 'ga:isTrueViewVideoAd', 'TrueView Video Ad'
+
 addMetric 'ga:impressions', 'Impressions'
 addMetric 'ga:adClicks', 'Ad Clicks'
 addMetric 'ga:adCost', 'Ad Cost'
 addMetric 'ga:CPM', 'Cost Per Thousand Impressions'
 addMetric 'ga:CPC', 'Cost to Advertiser Per Click'
 addMetric 'ga:CTR', 'Click Through Rate'
-addMetric 'ga:costPerTransaction', 'Cost Per Transaction'
-addMetric 'ga:costPerGoalConversion', 'Cost Per Goal Conversion'
+addMetric 'ga:costPerTransaction', 'Cost per Transaction'
+addMetric 'ga:costPerGoalConversion', 'Cost per Goal Conversion'
+addMetric 'ga:costPerConversion', 'Cost per Conversion'
 addMetric 'ga:RPC', 'Revenue Per Click'
 addMetric 'ga:ROI', 'Returns On Investment'
 addMetric 'ga:margin', 'Margin'

-addDimension 'ga:adGroup', 'Ad Group'
-addDimension 'ga:adSlot', 'Ad Slot'
-addDimension 'ga:adSlotPosition', 'Ad Slot Position'
-addDimension 'ga:adDistributionNetwork', 'Ad Distribution Network'
-addDimension 'ga:adMatchType', 'Ad Match Type'
-addDimension 'ga:adMatchedQuery', 'Ad Matched Query'
-addDimension 'ga:adPlacementDomain', 'Ad Placement Domain'
-addDimension 'ga:adPlacementUrl', 'Ad Placement Url'
-addDimension 'ga:adFormat', 'Ad Format'
-addDimension 'ga:adTargetingType', 'Ad Targeting Type'
-addDimension 'ga:adTargetingOption', 'Ad Targeting Option'
-addDimension 'ga:adDisplayUrl', 'Ad Display Url'
-addDimension 'ga:adDestinationUrl', 'Ad Destination Url'
-addDimension 'ga:adwordsCustomerID', 'Adwords Customer ID'
-addDimension 'ga:adwordsCampaignID', 'Adwords Campaign ID'
-addDimension 'ga:adwordsAdGroupID', 'Adwords Ad Group ID'
-addDimension 'ga:adwordsCreativeID', 'Adwords Creative ID'
-addDimension 'ga:adwordsCriteriaID', 'Adwords Criteria ID'
-
-#AdSense
-addMetric 'ga:adsenseRevenue', 'AdSense Revenue'
-addMetric 'ga:adsenseAdUnitsViewed', 'AdSense Ad Units Viewed'
-addMetric 'ga:adsenseAdsViewed', 'AdSense Ads Viewed'
-addMetric 'ga:adsenseAdsClicks', 'AdSense Ads Clicks'
-addMetric 'ga:adsensePageImpressions', 'AdSense Page Impressions'
-addMetric 'ga:adsenseCTR', 'AdSenseCTR'
-addMetric 'ga:adsenseECPM', 'AdSenseECPM'
-addMetric 'ga:adsenseExits', 'AdSenseExits'
-
 #Goal Conversions
-addMetric 'ga:goal(n)Start', 'Goal Start', 'ga:goal([0-9]+)Start'
-addMetric 'ga:goalStartsAll', 'All Goal Starts'
-addMetric 'ga:goal(n)Completions', 'Goal Completions', 'ga:goal([0-9]+)Completions'
-addMetric 'ga:goalCompletionsAll', 'All Goal Completions'
-addMetric 'ga:goal(n)Value', 'Goal Value', 'ga:goal([0-9]+)Value'
-addMetric 'ga:goalValueAll', 'All Goal Values'
-addMetric 'ga:goalValuePerVisit', 'Goal Value Per Visit'
-addMetric 'ga:goal(n)ConversionRate', 'Goal Conversion Rate', 'ga:goal([0-9]+)ConversionRate'
-addMetric 'ga:goalConversionRateAll', 'All Goal Conversion Rates'
-addMetric 'ga:goal(n)Abandons', 'Goal Abandons', 'ga:goal([0-9]+)Abandons'
-addMetric 'ga:goalAbandonsAll', 'All Goal Abandons'
-addMetric 'ga:goal(n)AbandonRate', 'Goal Abandon Rate', 'ga:goal([0-9]+)AbandonRate'
-addMetric 'ga:goalAbandonRateAll', 'All Goals Abandon Rate'
-
-#Platfrom / Device
+addDimension 'ga:goalCompletionLocation', 'Goal Completion Location'
+addDimension 'ga:goalPreviousStep1', 'Goal Previous Step - 1'
+addDimension 'ga:goalPreviousStep2', 'Goal Previous Step - 2'
+addDimension 'ga:goalPreviousStep3', 'Goal Previous Step - 3'
+
+addMetric 'ga:goalXXStarts', 'Goal XX Starts'
+addMetric 'ga:goalStartsAll', 'Goal Starts'
+addMetric 'ga:goalXXCompletions', 'Goal XX Completions'
+addMetric 'ga:goalCompletionsAll', 'Goal Completions'
+addMetric 'ga:goalXXValue', 'Goal XX Value'
+addMetric 'ga:goalValueAll', 'Goal Value'
+addMetric 'ga:goalValuePerSession', 'Per Session Goal Value'
+addMetric 'ga:goalXXConversionRate', 'Goal XX Conversion Rate'
+addMetric 'ga:goalConversionRateAll', 'Goal Conversion Rate'
+addMetric 'ga:goalXXAbandons', 'Goal XX Abandoned Funnels'
+addMetric 'ga:goalAbandonsAll', 'Abandoned Funnels'
+addMetric 'ga:goalXXAbandonRate', 'Goal XX Abandonment Rate'
+addMetric 'ga:goalAbandonRateAll', 'Total Abandonment Rate'
+
+#Platform or Device
 addDimension 'ga:browser', 'Browser'
 addDimension 'ga:browserVersion', 'Browser Version'
 addDimension 'ga:operatingSystem', 'Operating System'
 addDimension 'ga:operatingSystemVersion', 'Operating System Version'
-addDimension 'ga:deviceCategory', 'Device Category'
-addDimension 'ga:isMobile', 'Is Mobile'
-addDimension 'ga:isTablet', 'Is Tablet'
-addDimension 'ga:mobileDeviceMarketingName', 'Mobile Device Marketing Name'
 addDimension 'ga:mobileDeviceBranding', 'Mobile Device Branding'
 addDimension 'ga:mobileDeviceModel', 'Mobile Device Model'
 addDimension 'ga:mobileInputSelector', 'Mobile Input Selector'
 addDimension 'ga:mobileDeviceInfo', 'Mobile Device Info'
-
-#Geo / Network
+addDimension 'ga:mobileDeviceMarketingName', 'Mobile Device Marketing Name'
+addDimension 'ga:deviceCategory', 'Device Category'
+
+#Geo Network
 addDimension 'ga:continent', 'Continent'
-addDimension 'ga:subContinent', 'Sub Continent'
-addDimension 'ga:country', 'Country'
+addDimension 'ga:subContinent', 'Sub Continent Region'
+addDimension 'ga:country', 'Country / Territory'
 addDimension 'ga:region', 'Region'
 addDimension 'ga:metro', 'Metro'
 addDimension 'ga:city', 'City'
 addDimension 'ga:latitude', 'Latitude'
 addDimension 'ga:longitude', 'Longitude'
 addDimension 'ga:networkDomain', 'Network Domain'
-addDimension 'ga:networkLocation', 'Network Location'
+addDimension 'ga:networkLocation', 'Service Provider'

 #System
 addDimension 'ga:flashVersion', 'Flash Version'
-addDimension 'ga:javaEnabled', 'Java Enabled'
+addDimension 'ga:javaEnabled', 'Java Support'
 addDimension 'ga:language', 'Language'
 addDimension 'ga:screenColors', 'Screen Colors'
+addDimension 'ga:sourcePropertyDisplayName', 'Source Property Display Name'
+addDimension 'ga:sourcePropertyTrackingId', 'Source Property Tracking ID'
 addDimension 'ga:screenResolution', 'Screen Resolution'

 #Social Activities
-addMetric 'ga:socialActivities', 'Social Activities'
-
-addDimension 'ga:socialActivityEndorsingUrl', 'Social Activity Endorsing Url'
-addDimension 'ga:socialActivityDisplayName', 'Social Activity Display Name'
+addDimension 'ga:socialActivityEndorsingUrl', 'Endorsing URL'
+addDimension 'ga:socialActivityDisplayName', 'Display Name'
 addDimension 'ga:socialActivityPost', 'Social Activity Post'
 addDimension 'ga:socialActivityTimestamp', 'Social Activity Timestamp'
-addDimension 'ga:socialActivityUserHandle', 'Social Activity User Handle'
-addDimension 'ga:socialActivityUserPhotoUrl', 'Social Activity User Photo Url'
-addDimension 'ga:socialActivityUserProfileUrl', 'Social Activity User Profile Url'
-addDimension 'ga:socialActivityContentUrl', 'Social Activity Content Url'
-addDimension 'ga:socialActivityTagsSummary', 'Social Activity Tags Summary'
-addDimension 'ga:socialActivityAction', 'Social Activity Action'
-addDimension 'ga:socialActivityNetworkAction', 'Social Activity Network Action'
+addDimension 'ga:socialActivityUserHandle', 'Social User Handle'
+addDimension 'ga:socialActivityUserPhotoUrl', 'User Photo URL'
+addDimension 'ga:socialActivityUserProfileUrl', 'User Profile URL'
+addDimension 'ga:socialActivityContentUrl', 'Shared URL'
+addDimension 'ga:socialActivityTagsSummary', 'Social Tags Summary'
+addDimension 'ga:socialActivityAction', 'Originating Social Action'
+addDimension 'ga:socialActivityNetworkAction', 'Social Network and Action'
+
+addMetric 'ga:socialActivities', 'Data Hub Activities'

 #Page Tracking
-addMetric 'ga:entrances', 'Entrances'
-addMetric 'ga:entraceRate', 'Entrance Rate'
-addMetric 'ga:pageviews', 'Page Views'
-addMetric 'ga:pageviewsPerVisit', 'Page Views Per Visit'
-addMetric 'ga:uniquePageviews', 'Unique Page Views'
-addMetric 'ga:timeOnPage', 'Time On Page'
-addMetric 'ga:avgTimeOnPage', 'Average Time On Page'
-addMetric 'ga:exits', 'Exits'
-addMetric 'ga:exitRate', 'Exit Rate'
-
 addDimension 'ga:hostname', 'Hostname'
-addDimension 'ga:pagePath', 'Page Path'
-addDimension 'ga:pagePathLevel1', 'Page Path Level 1'
-addDimension 'ga:pagePathLevel2', 'Page Path Level 2'
-addDimension 'ga:pagePathLevel3', 'Page Path Level 3'
-addDimension 'ga:pagePathLevel4', 'Page Path Level 4'
+addDimension 'ga:pagePath', 'Page'
+addDimension 'ga:pagePathLevel1', 'Page path level 1'
+addDimension 'ga:pagePathLevel2', 'Page path level 2'
+addDimension 'ga:pagePathLevel3', 'Page path level 3'
+addDimension 'ga:pagePathLevel4', 'Page path level 4'
 addDimension 'ga:pageTitle', 'Page Title'
-addDimension 'ga:landingPagePath', 'Landing Page Path'
-addDimension 'ga:secondPagePath', 'Second Page Path'
-addDimension 'ga:exitPagePath', 'Exit Page Path'
+addDimension 'ga:landingPagePath', 'Landing Page'
+addDimension 'ga:secondPagePath', 'Second Page'
+addDimension 'ga:exitPagePath', 'Exit Page'
 addDimension 'ga:previousPagePath', 'Previous Page Path'
 addDimension 'ga:nextPagePath', 'Next Page Path'
 addDimension 'ga:pageDepth', 'Page Depth'

+addMetric 'ga:pageValue', 'Page Value'
+addMetric 'ga:entrances', 'Entrances'
+addMetric 'ga:pageviews', 'Pageviews'
+addMetric 'ga:uniquePageviews', 'Unique Pageviews'
+addMetric 'ga:timeOnPage', 'Time on Page'
+addMetric 'ga:exits', 'Exits'
+addMetric 'ga:entranceRate', 'Entrances / Pageviews'
+addMetric 'ga:pageviewsPerSession', 'Pages / Session'
+addMetric 'ga:avgTimeOnPage', 'Avg. Time on Page'
+addMetric 'ga:exitRate', '% Exit'
+
+#Content Grouping
+addDimension 'ga:landingContentGroupXX', 'Landing Page Group XX'
+addDimension 'ga:previousContentGroupXX', 'Previous Page Group XX'
+addDimension 'ga:contentGroupXX', 'Page Group XX'
+addDimension 'ga:nextContentGroupXX', 'Next Page Group XX'
+
+addMetric 'ga:contentGroupUniqueViewsXX', 'Unique Views'
+
 #Internal Search
-addMetric 'ga:searchResultViews', 'Search Result Views'
-addMetric 'ga:searchUniques', 'Unique Searches'
-addMetric 'ga:avgSearchResultViews', 'Average Search Result Views'
-addMetric 'ga:searchVisits', 'Search Visits'
-addMetric 'ga:percentVisitsWithSearch', 'Percent Visits with Search'
+addDimension 'ga:searchUsed', 'Site Search Status'
+addDimension 'ga:searchKeyword', 'Search Term'
+addDimension 'ga:searchKeywordRefinement', 'Refined Keyword'
+addDimension 'ga:searchCategory', 'Site Search Category'
+addDimension 'ga:searchStartPage', 'Start Page'
+addDimension 'ga:searchDestinationPage', 'Destination Page'
+
+addMetric 'ga:searchResultViews', 'Results Pageviews'
+addMetric 'ga:searchUniques', 'Total Unique Searches'
+addMetric 'ga:searchSessions', 'Sessions with Search'
 addMetric 'ga:searchDepth', 'Search Depth'
 addMetric 'ga:searchRefinements', 'Search Refinements'
-addMetric 'ga:searchDuration', 'Search Duration'
-addMetric 'ga:avgSearchDuration', 'Average Search Duration'
+addMetric 'ga:searchDuration', 'Time after Search'
 addMetric 'ga:searchExits', 'Search Exits'
-addMetric 'ga:searchExitRate', 'Search Exit Rate'
-addMetric 'ga:searchGoal(n)ConversionRate', 'Search Goal Conversion Rate', 'ga:searchGoal([0-9]+)ConversionRate'
-addMetric 'ga:searchGoalConversionRateAll', 'Search All Goals Conversion Rate'
-addMetric 'ga:goalValueAllPerSearch', 'Goal Value Per Search'
-
-addDimension 'ga:searchUsed', 'Search Used'
-addDimension 'ga:searchKeyword', 'Search Keyword'
-addDimension 'ga:searchKeywordRefinement', 'Search Keyword Refinement'
-addDimension 'ga:searchCategory', 'Search Category'
-addDimension 'ga:searchStartPage', 'Search Start Page'
-addDimension 'ga:searchDestinationPage', 'Search Destination Page'
+addMetric 'ga:avgSearchResultViews', 'Results Pageviews / Search'
+addMetric 'ga:percentSessionsWithSearch', '% Sessions with Search'
+addMetric 'ga:avgSearchDepth', 'Average Search Depth'
+addMetric 'ga:percentSearchRefinements', '% Search Refinements'
+addMetric 'ga:avgSearchDuration', 'Time after Search'
+addMetric 'ga:searchExitRate', '% Search Exits'
+addMetric 'ga:searchGoalXXConversionRate', 'Site Search Goal XX Conversion Rate'
+addMetric 'ga:searchGoalConversionRateAll', 'Site Search Goal Conversion Rate'
+addMetric 'ga:goalValueAllPerSearch', 'Per Search Goal Value'

 #Site Speed
-addMetric 'ga:pageLoadTime', 'Page Load Time'
+addMetric 'ga:pageLoadTime', 'Page Load Time (ms)'
 addMetric 'ga:pageLoadSample', 'Page Load Sample'
-addMetric 'ga:avgPageLoadTime', 'Average Page Load Time'
-addMetric 'ga:domainLookupTime', 'Domain Lookup Time'
-addMetric 'ga:avgDomainLookupTime', 'Average Domain Lookup Time'
-addMetric 'ga:pageDownloadTime', 'Page Download Time'
-addMetric 'ga:avgPageDownloadTime', 'Average Page Download Time'
-addMetric 'ga:redirectionTime', 'Redirection Time'
-addMetric 'ga:avgRedirectionTime', 'Average Redirection Time'
-addMetric 'ga:serverConnectionTime', 'Server Connection Time'
-addMetric 'ga:avgServerConnectionTime', 'Average Server Connection Time'
-addMetric 'ga:serverResponseTime', 'Server Response Time'
-addMetric 'ga:avgServerResponseTime', 'Average Server Response Time'
+addMetric 'ga:domainLookupTime', 'Domain Lookup Time (ms)'
+addMetric 'ga:pageDownloadTime', 'Page Download Time (ms)'
+addMetric 'ga:redirectionTime', 'Redirection Time (ms)'
+addMetric 'ga:serverConnectionTime', 'Server Connection Time (ms)'
+addMetric 'ga:serverResponseTime', 'Server Response Time (ms)'
 addMetric 'ga:speedMetricsSample', 'Speed Metrics Sample'
-addMetric 'ga:domInteractiveTime', 'DOM Interactive Time'
-addMetric 'ga:avgDomInteractiveTime', 'Average DOM Interactive Time'
-addMetric 'ga:domContentLoadedTime', 'DOM Content Loaded Time'
-addMetric 'ga:avgDomContentLoadedTime', 'Average DOM Content Loaded Time'
-addMetric 'ga:domLatencyMetricsSample', 'DOM Latency Merics Sample'
+addMetric 'ga:domInteractiveTime', 'Document Interactive Time (ms)'
+addMetric 'ga:domContentLoadedTime', 'Document Content Loaded Time (ms)'
+addMetric 'ga:domLatencyMetricsSample', 'DOM Latency Metrics Sample'
+addMetric 'ga:avgPageLoadTime', 'Avg. Page Load Time (sec)'
+addMetric 'ga:avgDomainLookupTime', 'Avg. Domain Lookup Time (sec)'
+addMetric 'ga:avgPageDownloadTime', 'Avg. Page Download Time (sec)'
+addMetric 'ga:avgRedirectionTime', 'Avg. Redirection Time (sec)'
+addMetric 'ga:avgServerConnectionTime', 'Avg. Server Connection Time (sec)'
+addMetric 'ga:avgServerResponseTime', 'Avg. Server Response Time (sec)'
+addMetric 'ga:avgDomInteractiveTime', 'Avg. Document Interactive Time (sec)'
+addMetric 'ga:avgDomContentLoadedTime', 'Avg. Document Content Loaded Time (sec)'

 #App Tracking
-addMetric 'ga:appviews', 'App Views' #deprecated
-addMetric 'ga:uniqueAppviews', 'Unique App Views' #deprecated
-addMetric 'ga:appviewsPerVisit', 'App Views Per Visit' #deprecated
-
-addMetric 'ga:screenviews', 'Screenviews'
-addMetric 'ga:uniqueScreenviews', 'Unique Screenviews'
-addMetric 'ga:screenviewsPerSession', 'Screenviews Per Session'
-addMetric 'ga:timeOnScreen', 'Time On Screen'
-addMetric 'ga:avgScreenviewDuration', 'Average Screenview Duration'
-
-addDimension 'ga:appInstallerId', 'App Installer Id'
+addDimension 'ga:appInstallerId', 'App Installer ID'
 addDimension 'ga:appVersion', 'App Version'
 addDimension 'ga:appName', 'App Name'
-addDimension 'ga:appId', 'App Id'
+addDimension 'ga:appId', 'App ID'
 addDimension 'ga:screenName', 'Screen Name'
 addDimension 'ga:screenDepth', 'Screen Depth'
-addDimension 'ga:landingScreenName', 'Landing Screen Name'
-addDimension 'ga:exitScreenName', 'Exit Screen Name'
+addDimension 'ga:landingScreenName', 'Landing Screen'
+addDimension 'ga:exitScreenName', 'Exit Screen'
+
+addMetric 'ga:screenviews', 'Screen Views'
+addMetric 'ga:uniqueScreenviews', 'Unique Screen Views'
+addMetric 'ga:timeOnScreen', 'Time on Screen'
+addMetric 'ga:avgScreenviewDuration', 'Avg. Time on Screen'
+addMetric 'ga:screenviewsPerSession', 'Screens / Session'

 #Event Tracking
+addDimension 'ga:eventCategory', 'Event Category'
+addDimension 'ga:eventAction', 'Event Action'
+addDimension 'ga:eventLabel', 'Event Label'
+
 addMetric 'ga:totalEvents', 'Total Events'
 addMetric 'ga:uniqueEvents', 'Unique Events'
 addMetric 'ga:eventValue', 'Event Value'
-addMetric 'ga:avgEventValue', 'Average Event Value'
-addMetric 'ga:visitsWithEvent', 'Visits With Event'
-addMetric 'ga:eventsPerVisitWithEvent', 'Events Per Visit With Event'
-
-addDimension 'ga:eventCategory', 'Event Category'
-addDimension 'ga:eventAction', 'Event Action'
-addDimension 'ga:eventLabel', 'Event Label'
+addMetric 'ga:sessionsWithEvent', 'Sessions with Event'
+addMetric 'ga:avgEventValue', 'Avg. Value'
+addMetric 'ga:eventsPerSessionWithEvent', 'Events / Session with Event'

 #Ecommerce
-addDimension 'ga:transactionId' , 'Transaction ID'
+addDimension 'ga:transactionId', 'Transaction Id'
 addDimension 'ga:affiliation', 'Affiliation'
-addDimension 'ga:visitsToTransaction', 'Visits to Transactions'
+addDimension 'ga:sessionsToTransaction', 'Sessions to Transaction'
 addDimension 'ga:daysToTransaction', 'Days to Transaction'
-addDimension 'ga:productSku', 'Product Stock Unit'
-addDimension 'ga:productName', 'Product Name'
+addDimension 'ga:productSku', 'Product SKU'
+addDimension 'ga:productName', 'Product'
 addDimension 'ga:productCategory', 'Product Category'
 addDimension 'ga:currencyCode', 'Currency Code'
-
-addMetric 'ga:transactions' , 'Transactions'
-addMetric 'ga:transactionRevenue', 'Transaction Revenue'
-addMetric 'ga:transactionShipping', 'Transaction Shipping Costs'
-addMetric 'ga:transactionTax', 'Transaction Tax'
-addMetric 'ga:itemQuantity', 'Item Quantity'
+addDimension 'ga:checkoutOptions', 'Checkout Options'
+addDimension 'ga:internalPromotionCreative', 'Internal Promotion Creative'
+addDimension 'ga:internalPromotionId', 'Internal Promotion ID'
+addDimension 'ga:internalPromotionName', 'Internal Promotion Name'
+addDimension 'ga:internalPromotionPosition', 'Internal Promotion Position'
+addDimension 'ga:orderCouponCode', 'Order Coupon Code'
+addDimension 'ga:productBrand', 'Product Brand'
+addDimension 'ga:productCategoryHierarchy', 'Product Category (Enhanced Ecommerce)'
+addDimension 'ga:productCategoryLevelXX', 'Product Category Level XX'
+addDimension 'ga:productCouponCode', 'Product Coupon Code'
+addDimension 'ga:productListName', 'Product List Name'
+addDimension 'ga:productListPosition', 'Product List Position'
+addDimension 'ga:productVariant', 'Product Variant'
+addDimension 'ga:shoppingStage', 'Shopping Stage'
+
+addMetric 'ga:transactions', 'Transactions'
+addMetric 'ga:transactionRevenue', 'Revenue'
+addMetric 'ga:transactionShipping', 'Shipping'
+addMetric 'ga:transactionTax', 'Tax'
+addMetric 'ga:itemQuantity', 'Quantity'
 addMetric 'ga:uniquePurchases', 'Unique Purchases'
-addMetric 'ga:itemRevenue', 'Item Revenue'
-addMetric 'ga:localTransactionRevenue', 'Local Transaction Revenue'
-addMetric 'ga:localTransactionShipping', 'Local Transaction Shipping Costs'
-addMetric 'ga:localTransactionTax', 'Local Transaction Tax'
-addMetric 'ga:localItemRevenue', 'Local Item Revenue'
+addMetric 'ga:itemRevenue', 'Product Revenue'
+addMetric 'ga:localTransactionRevenue', 'Local Revenue'
+addMetric 'ga:localTransactionShipping', 'Local Shipping'
+addMetric 'ga:localTransactionTax', 'Local Tax'
+addMetric 'ga:localItemRevenue', 'Local Product Revenue'
+addMetric 'ga:buyToDetailRate', 'Buy-to-Detail Rate'
+addMetric 'ga:cartToDetailRate', 'Cart-to-Detail Rate'
+addMetric 'ga:internalPromotionClicks', 'Internal Promotion Clicks'
+addMetric 'ga:internalPromotionViews', 'Internal Promotion Views'
+addMetric 'ga:localProductRefundAmount', 'Local Product Refund Amount'
+addMetric 'ga:localRefundAmount', 'Local Refund Amount'
+addMetric 'ga:productAddsToCart', 'Product Adds To Cart'
+addMetric 'ga:productCheckouts', 'Product Checkouts'
+addMetric 'ga:productDetailViews', 'Product Detail Views'
+addMetric 'ga:productListClicks', 'Product List Clicks'
+addMetric 'ga:productListViews', 'Product List Views'
+addMetric 'ga:productRefundAmount', 'Product Refund Amount'
+addMetric 'ga:productRefunds', 'Product Refunds'
+addMetric 'ga:productRemovesFromCart', 'Product Removes From Cart'
+addMetric 'ga:quantityAddedToCart', 'Quantity Added To Cart'
+addMetric 'ga:quantityCheckedOut', 'Quantity Checked Out'
+addMetric 'ga:quantityRefunded', 'Quantity Refunded'
+addMetric 'ga:quantityRemovedFromCart', 'Quantity Removed From Cart'
+addMetric 'ga:refundAmount', 'Refund Amount'
+addMetric 'ga:totalRefunds', 'Refunds'
+addMetric 'ga:transactionsPerSession', 'Ecommerce Conversion Rate'
+addMetric 'ga:revenuePerTransaction', 'Average Order Value'
+addMetric 'ga:transactionRevenuePerSession', 'Per Session Value'
+addMetric 'ga:totalValue', 'Total Value'
+addMetric 'ga:revenuePerItem', 'Average Price'
+addMetric 'ga:itemsPerPurchase', 'Average QTY'
+addMetric 'ga:internalPromotionCTR', 'Internal Promotion CTR'
+addMetric 'ga:productListCTR', 'Product List CTR'
+addMetric 'ga:productRevenuePerPurchase', 'Product Revenue per Purchase'

 #Social Interactions
-addMetric 'ga:socialInteractions', 'Social Interactions'
-addMetric 'ga:uniqueSocialInteractions', 'Unique Social Interactions'
-addMetric 'ga:socialInteractionsPerVisit', 'Social Interactions Per Visit'
-
-addDimension 'ga:socialInteractionNetwork', 'Social Interaction Network'
-addDimension 'ga:socialInteractionAction', 'Social Interaction Action'
-addDimension 'ga:socialInteractionNetworkAction', 'Social Interaction Network Action'
-addDimension 'ga:socialInteractionTarget', 'Social Interaction Target'
+addDimension 'ga:socialInteractionNetwork', 'Social Source'
+addDimension 'ga:socialInteractionAction', 'Social Action'
+addDimension 'ga:socialInteractionNetworkAction', 'Social Source and Action'
+addDimension 'ga:socialInteractionTarget', 'Social Entity'
+addDimension 'ga:socialEngagementType', 'Social Type'
+
+addMetric 'ga:socialInteractions', 'Social Actions'
+addMetric 'ga:uniqueSocialInteractions', 'Unique Social Actions'
+addMetric 'ga:socialInteractionsPerSession', 'Actions Per Social Session'

 #User Timings
-addMetric 'ga:userTimingValue', 'User Timing Value'
+addDimension 'ga:userTimingCategory', 'Timing Category'
+addDimension 'ga:userTimingLabel', 'Timing Label'
+addDimension 'ga:userTimingVariable', 'Timing Variable'
+
+addMetric 'ga:userTimingValue', 'User Timing (ms)'
 addMetric 'ga:userTimingSample', 'User Timing Sample'
-addMetric 'ga:avgUserTimingValue', 'Average User Timing Value'
-
-addDimension 'ga:userTimingCategory', 'User Timing Category'
-addDimension 'ga:userTimingLabel', 'User Timing Label'
-addDimension 'ga:userTimingVariable', 'User Timing Variable'
-
-#Exception Tracking
+addMetric 'ga:avgUserTimingValue', 'Avg. User Timing (sec)'
+
+#Exceptions
+addDimension 'ga:exceptionDescription', 'Exception Description'
+
 addMetric 'ga:exceptions', 'Exceptions'
-addMetric 'ga:fatalExceptions', 'Fatal Exceptions'
-addMetric 'ga:exceptionDescription', 'Exception Description'
-addMetric 'ga:exceptionsPerScreenview', 'Exceptions Per Screenview'
-addMetric 'ga:fatalExceptionsPerScreenview', 'Fatal Exceptions Per Screenview'
-
-#Experiments
-addDimension 'ga:experimentId', 'Experiment Id'
-addDimension 'ga:experimentVariant', 'Experiment Variant'
-
-#Custom Variables
-addDimension 'ga:customVarName(n)', 'Custom Var Name', 'ga:customVarName([0-9]+)'
-addDimension 'ga:customVarValue(n)', 'Custom Var Value', 'ga:customVarValue([0-9]+)'
-
-#Custom
-addDimension 'ga:dimension(n)', 'Custom Dimension', 'ga:dimension([0-9]+)'
-addMetric 'ga:metric(n)', 'Custom Metric', 'ga:metric([0-9]+)'
+addMetric 'ga:fatalExceptions', 'Crashes'
+addMetric 'ga:exceptionsPerScreenview', 'Exceptions / Screen'
+addMetric 'ga:fatalExceptionsPerScreenview', 'Crashes / Screen'
+
+#Content Experiments
+addDimension 'ga:experimentId', 'Experiment ID'
+addDimension 'ga:experimentVariant', 'Variation'
+
+#Custom Variables or Columns
+addDimension 'ga:dimensionXX', 'Custom Dimension XX'
+addDimension 'ga:customVarNameXX', 'Custom Variable (Key XX)'
+addDimension 'ga:customVarValueXX', 'Custom Variable (Value XX)'
+
+addMetric 'ga:metricXX', 'Custom Metric XX Value'

 #Time
 addDimension 'ga:date', 'Date'
 addDimension 'ga:year', 'Year'
-addDimension 'ga:month', 'Month'
-addDimension 'ga:week', 'Week'
-addDimension 'ga:day', 'Day'
+addDimension 'ga:month', 'Month of the year'
+addDimension 'ga:week', 'Week of the Year'
+addDimension 'ga:day', 'Day of the month'
 addDimension 'ga:hour', 'Hour'
-addDimension 'ga:nthMonth', 'Nth Month'
-addDimension 'ga:nthWeek', 'Nth Week'
-addDimension 'ga:nthDay', 'Nth Day'
-addDimension 'ga:dayOfWeek', 'Day Of Week'
+addDimension 'ga:minute', 'Minute'
+addDimension 'ga:nthMonth', 'Month Index'
+addDimension 'ga:nthWeek', 'Week Index'
+addDimension 'ga:nthDay', 'Day Index'
+addDimension 'ga:nthMinute', 'Minute Index'
+addDimension 'ga:dayOfWeek', 'Day of Week'
 addDimension 'ga:dayOfWeekName', 'Day of Week Name'
-addDimension 'ga:dateHour', 'Date Hour'
-addDimension 'ga:isoWeek', 'ISO Week'
-addDimension 'ga:yearMonth', 'Year Month'
-addDimension 'ga:yearWeek', 'Year Week'
+addDimension 'ga:dateHour', 'Hour of Day'
+addDimension 'ga:yearMonth', 'Month of Year'
+addDimension 'ga:yearWeek', 'Week of Year'
+addDimension 'ga:isoWeek', 'ISO Week of the Year'
+addDimension 'ga:isoYear', 'ISO Year'
+addDimension 'ga:isoYearIsoWeek', 'ISO Week of ISO Year'
+addDimension 'ga:nthHour', 'Hour Index'
+
+#Audience
+addDimension 'ga:userAgeBracket', 'Age'
+addDimension 'ga:userGender', 'Gender'
+addDimension 'ga:interestOtherCategory', 'Other Category'
+addDimension 'ga:interestAffinityCategory', 'Affinity Category (reach)'
+addDimension 'ga:interestInMarketCategory', 'In-Market Segment'
+
+#Adsense
+addMetric 'ga:adsenseRevenue', 'AdSense Revenue'
+addMetric 'ga:adsenseAdUnitsViewed', 'AdSense Ad Units Viewed'
+addMetric 'ga:adsenseAdsViewed', 'AdSense Ads Viewed'
+addMetric 'ga:adsenseAdsClicks', 'AdSense Ads Clicked'
+addMetric 'ga:adsensePageImpressions', 'AdSense Page Impressions'
+addMetric 'ga:adsenseExits', 'AdSense Exits'
+addMetric 'ga:adsenseCTR', 'AdSense CTR'
+addMetric 'ga:adsenseECPM', 'AdSense eCPM'
+
+#Channel Grouping
+addDimension 'ga:channelGrouping', 'Default Channel Grouping'
+
+#Related Products
+addDimension 'ga:correlationModelId', 'Correlation Model ID'
+addDimension 'ga:queryProductId', 'Queried Product ID'
+addDimension 'ga:queryProductName', 'Queried Product Name'
+addDimension 'ga:queryProductVariation', 'Queried Product Variation'
+addDimension 'ga:relatedProductId', 'Related Product ID'
+addDimension 'ga:relatedProductName', 'Related Product Name'
+addDimension 'ga:relatedProductVariation', 'Related Product Variation'
+
+addMetric 'ga:correlationScore', 'Correlation Score'
+addMetric 'ga:queryProductQuantity', 'Queried Product Quantity'
+addMetric 'ga:relatedProductQuantity', 'Related Product Quantity'

 #
 # Build Regex


fix reveal.js cdn.js path

fix reveal.js cdn.js path

--- lib/markdown-preview-enhanced-view.coffee
+++ lib/markdown-preview-enhanced-view.coffee
@@ -1004,8 +1004,8 @@
         <script src='file:///#{path.resolve(__dirname, '../dependencies/reveal/js/reveal.js')}'></script>"
       else
         presentationScript = "
-        <script src='https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.0/lib/js/head.min.js'></script>
-        <script src='https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.0/js/reveal.min.js'></script>"
+        <script src='https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/lib/js/head.min.js'></script>
+        <script src='https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.4.1/js/reveal.min.js'></script>"

       presentationConfig = yamlConfig['presentation'] or {}
       dependencies = presentationConfig.dependencies or []


Removed debug code

Removed debug code

--- core/app/backbone/views/channels/filtered_suggested_topics_view.coffee
+++ core/app/backbone/views/channels/filtered_suggested_topics_view.coffee
@@ -50,8 +50,6 @@

     @bindTo @filtered_collection, 'add remove reset change', @updateVisibilities, @

-    console.info @collection
-
   onRender: ->
     @suggestedTopicsRegion.show new SuggestedTopicsView
       collection: @filtered_collection


Use new form validation; display the error message if there is one

--- components/auth_modal/view.coffee
+++ components/auth_modal/view.coffee
@@ -60,13 +60,17 @@
     @state.set 'mode', $(e.target).data('mode')

   submit: (e) ->
+    return unless @validateForm()
+
     e.preventDefault()

-    if @validateForm()
-      @$('button').attr 'data-state', 'loading'
-      new modelMap[@state.get 'mode']().save @serializeForm(),
-        success: @onSubmitSuccess
-        error: (m, xhr) => @errorMessage xhr
+    @$('button').attr 'data-state', 'loading'
+
+    new modelMap[@state.get 'mode']().save @serializeForm(),
+      success: @onSubmitSuccess
+      error: (model, xhr) =>
+        message = @errorMessage xhr
+        @showError message

   onSubmitSuccess: (model, res, options) =>
     if res.error?


Update shit-candidates-say.coffee

Update shit-candidates-say.coffee

--- src/shit-candidates-say.coffee
+++ src/shit-candidates-say.coffee
@@ -29,6 +29,7 @@
     "candidate: I run a horse farm full time so I need to work remotely.",
     "candidate: I have to go, I have another phone interview in a minute.",
     "candidate: I created a charity because it's the only way children's hospitals will let me in.",
+    "candidate: I have a very strong understanding of javascript - so all frameworks are easy to pick up.",
     "candidate: Stop! Look no further you have found the Perl developer that you need!"
   ]


additional fix

additional fix

--- src/smc-util/syncstring.coffee
+++ src/smc-util/syncstring.coffee
@@ -1512,6 +1512,11 @@
     save_to_disk: (cb) =>
         #dbg = @dbg("save_to_disk(cb)")
         #dbg("initiating the save")
+        if not @has_unsaved_changes()
+            # no unsaved changes, so don't save -- CRITICAL: this optimization is assumed by autosave, etc.
+            cb?()
+            return
+
         @_save_to_disk()
         if not @_syncstring_table?
             cb("@_syncstring_table must be defined")


Update Brian job title

Update Brian job title


Fixing some paths.

Fixing some paths.

--- src/toaster/core/script.coffee
+++ src/toaster/core/script.coffee
@@ -23,23 +23,28 @@

     # assemble some information about the file
     @filepath = @realpath.replace "#{@folderpath}#{path.sep}", ''
-
-    # computes release paths for saving js files
-    @relative_path = @filepath.replace '.coffee', '.js'
-    @relative_path = @relative_path.substr 1 if @relative_path[0] is path.sep
-
-    release_path = path.dirname @builder.release
-    absolute_path = path.resolve (path.join release_path, @relative_path)
-
-    folder_path = path.dirname absolute_path
-    @release =
-      folder: folder_path
-      file: absolute_path
-
     @filepath = (@filepath.substr 1) if (@filepath.substr 0, 1) is path.sep
-
     @filename = path.basename @filepath
     @filefolder = path.dirname @filepath
+
+    # compute all necessary release paths
+    release_file = path.join @builder.toaster.basepath, @builder.release
+    release_folder = path.dirname release_file
+
+    release_file = path.join release_folder, @filepath
+    release_file = release_file.replace '.coffee', '.js'
+
+    release_folder = path.dirname release_file
+
+    relative_path = release_file.replace @builder.toaster.basepath, ''
+    relative_path = relative_path.substr 1 if relative_path[0] is path.sep
+
+    @release =
+      folder: release_folder
+      file: release_file
+      relative: relative_path
+
+    # cleaning filepath and
     @namespace = ""

     # if the file is in the top level
@@ -153,7 +158,7 @@
     fs.writeFileSync @release.file, compiled

     # notify user through cli
-    console.log "[#{now}] #{'Compiled'.bold} #{@relative_path}".green
+    console.log "[#{now}] #{'Compiled'.bold} #{@release.relative}".green

   compile_to_str:->
     compiled = cs.compile @raw, bare: @builder.bare