FIXED Accept self-signed certificates

FIXED Accept self-signed certificates

--- src/zombie/resources.coffee
+++ src/zombie/resources.coffee
@@ -475,6 +475,7 @@
       followRedirect: false
       encoding:       null
       timeout:        request.timeout || 0
+      strictSSL:      false

     Request httpRequest, (error, response)=>
       if error


updated context panel coffee to update link url (not just link text) when website is updated/saved +  selector speed refactor

--- app/coffee/context_panel.coffee
+++ app/coffee/context_panel.coffee
@@ -39,8 +39,12 @@
       @contextView.showProfile()

       # Is this the best way to do this? Or should we use data coming back?
+
       $profileDetails = $('.profile .details')
-      $profileDetails.find('.website').text($('#user_link_attributes_url').val())
+      $website = $profileDetails.find('.website')
+
+      $website.text($('#user_link_attributes_url').val()) # update link text
+      $website.attr('href',$('#user_link_attributes_url').val()) # update link url
       $profileDetails.find('.email').text($('#user_email').val())
       $profileDetails.find('.phone').text($('#user_phone').val())
       $profileDetails.find('.skype span').text($('#user_skype').val())


Start collecting Stripe ZIP codes for better accounting

--- app/core/services/stripe.coffee
+++ app/core/services/stripe.coffee
@@ -19,6 +19,7 @@
         handler.trigger 'received-token', { token }
         Backbone.Mediator.publish 'stripe:received-token', { token: token }
       locale: 'auto'
+      zipCode: true
     })
     handler.id = _.uniqueId()
     handler.openAsync = (options) ->


Always submit classifications via the stored queue (#3737)

Don't resubmit 422 errors.

--- app/pages/project/classify.cjsx
+++ app/pages/project/classify.cjsx
@@ -239,29 +239,13 @@

     classification = @state.classification
     console?.info 'Completed classification', classification
-    savingClassification = if @state.demoMode
-      Promise.resolve classification
-    else if @props.simulateSaveFailure
-      Promise.reject new Error 'Simulated failure of classification save'
-    else
-      classification.save()

     Split.classificationCreated(classification)
     {workflow, subjects} = classification.links
     seenThisSession.add workflow, subjects
-    savingClassification
-      .then (classification) =>
-        if @state.demoMode
-          console?.log 'Demo mode: Did NOT save classification'
-        else
-          console?.log 'Saved classification', classification.id
-          classification.destroy()
-        @saveAllQueuedClassifications()
-      .catch (error) =>
-        console?.warn 'Failed to save classification:', error
-        @queueClassification classification
-
-    return savingClassification
+    @queueClassification classification unless @state.demoMode
+    @saveAllQueuedClassifications()
+    Promise.resolve classification

   queueClassification: (classification) ->
     queue = JSON.parse localStorage.getItem FAILED_CLASSIFICATION_QUEUE_NAME
@@ -280,6 +264,7 @@
       for classificationData in queue then do (classificationData) =>
         apiClient.type('classifications').create(classificationData).save()
           .then (actualClassification) =>
+            console?.log 'Saved classification', actualClassification.id
             actualClassification.destroy()
             indexInQueue = queue.indexOf classificationData
             queue.splice indexInQueue, 1
@@ -290,6 +275,14 @@
               console?.error 'Failed to update classification queue:', error
           .catch (error) =>
             console?.error 'Failed to save a queued classification:', error
+            switch error.status
+              when 422
+                indexInQueue = queue.indexOf classificationData
+                queue.splice indexInQueue, 1
+                try
+                  localStorage.setItem FAILED_CLASSIFICATION_QUEUE_NAME, JSON.stringify queue
+                catch error
+                  console?.error 'Failed to update classification queue:', error

   loadAnotherSubject: ->
     # Forget the old classification so a new one will load.


Spelling change

Spelling change

--- app/schemas/models/level.coffee
+++ app/schemas/models/level.coffee
@@ -120,10 +120,10 @@
     )
     animation: c.shortString(
       title: 'Element Animation'
-      description: 'How to animation the target'
+      description: 'How to animate the target'
       enum: [
+        'Outline'
         'Shake'
-        'Highlight'
         'Zoom'
       ]
     )


Fix typo in comments.

Fix typo in comments.

--- src/transparency.coffee
+++ src/transparency.coffee
@@ -86,13 +86,12 @@

 # Chainable method decorator (example in node.js console).
 #
-#    > o       = {}
-#    > o.hello = "Hello"
-#    > o.foo   = chainable(function(){console.log(this.hello + " World")});
-#    > o.foo().hello
-#    Hello World
-#    "Hello"
-#    >
+#     > o = {}
+#     > o.hello = "Hello"
+#     > o.foo = chainable(function(){console.log(this.hello + " World")});
+#     > o.foo().hello
+#     Hello World
+#     "Hello"
 #
 chainable = (method) -> -> method.apply(this, arguments); this


fix pagination stream tests on node v0.10 (#39)

--- test/test-pagination-stream.coffee
+++ test/test-pagination-stream.coffee
@@ -33,8 +33,6 @@
       expect(array).to.deep.equal expected
       done()

-    stream.resume()
-
   it "should preserve order with asynchronous data sources", (done) ->
     count = 9
     pages = [
@@ -52,5 +50,3 @@

       expect(array).to.deep.equal expected
       done()
-
-    stream.resume()


Disable quicksand for now

Disable quicksand for now

--- static/js/topics.coffee
+++ static/js/topics.coffee
@@ -45,7 +45,7 @@
         tagcloud_el.tag_cloud tags

         ul = @$el.find('.tab-pane ul')
-        if ul.length
+        if false and ul.length
             ul.quicksand tagcloud_el.find('li')
         else
             @$el.find('.tab-pane').empty().append tagcloud_el


fix: testcase for user model

fix: testcase for user model

--- tests/unit/models/user-test.coffee
+++ tests/unit/models/user-test.coffee
@@ -2,7 +2,7 @@

 moduleForModel 'user', 'Unit | Model | user', {
   # Specify the other units that are required for this test.
-  needs: ['model:project', 'model:submission', 'model:collaboration']
+  needs: ['model:project', 'model:submission', 'model:collaboration', 'model:pricing']
 }

 test 'it exists', (assert) ->


Update specs

Update specs

--- apps/fairs/test/template.coffee
+++ apps/fairs/test/template.coffee
@@ -35,8 +35,8 @@
       benv.teardown()

     it 'renders correctly', ->
-      $('.fairs-page-fairs-featured .fairs-page-subheader').first().text().should.equal 'Current Fairs'
-      $('.fpff-fair').length.should.equal 6
+      $('.aggregate-page-items-featured .aggregate-page-subheader').first().text().should.equal 'Current Fairs'
+      $('.ap-featured-item').length.should.equal 6

   describe 'without current fairs', ->
     before (done) ->
@@ -54,5 +54,5 @@
       benv.teardown()

     it 'renders correctly', ->
-      $('.fairs-page-fairs-featured .fairs-page-subheader').first().text().should.equal 'Past Fairs'
-      $('.fpff-fair').length.should.equal 4
+      $('.aggregate-page-items-featured .aggregate-page-subheader').first().text().should.equal 'Past Fairs'
+      $('.ap-featured-item').length.should.equal 4


tab 2 spaces(2)

tab 2 spaces(2)

--- appscode/applicationMain.coffee
+++ appscode/applicationMain.coffee
@@ -1,8 +1,8 @@
 class applicationMain extends JSObject
-	constructor:(@rootView)-> super()
-	didFinishLaunching:->
-		###
-		Please describe the user code below from here.
-		Please arrange an indent with the head of this comment.
-		###
-
+    constructor:(@rootView)-> super()
+    didFinishLaunching:->
+        ###
+        Please describe the user code below from here.
+        Please arrange an indent with the head of this comment.
+        ###
+


When the page opens, inspector panel should be shown by default.

--- src/code/views/wireframes/inspector-panel-view.coffee
+++ src/code/views/wireframes/inspector-panel-view.coffee
@@ -8,7 +8,7 @@
   displayName: 'InspectorPanelView'

   getInitialState: ->
-    expanded: false
+    expanded: true

   collapse: ->
     @setState {expanded: false}


Fix missing formatting

Fix missing formatting

--- src/main/resources/syntax-templates/atom/default.cson
+++ src/main/resources/syntax-templates/atom/default.cson
@@ -6,7 +6,7 @@
   '.msa'
   '.ms'
 ]
-patterns: [
+'patterns': [
   {
     'captures':
       '1':


activity: remove unnecessary render methods

--- client/activity/lib/components/channelthreadpane/index.coffee
+++ client/activity/lib/components/channelthreadpane/index.coffee
@@ -54,30 +54,12 @@
     </ThreadHeader>

-  renderFeed: ->
-    return null  unless @props.feed
-
-    React.cloneElement @props.feed,
-      thread   : @state.channelThread
-      messages : @state.popularMessages
-
-
   renderChat: ->
     return null  unless @props.chat

     React.cloneElement @props.chat,
       thread   : @state.channelThread
       messages : @state.channelThreadMessages
-
-
-  renderPost: ->
-
-    return null  unless @props.post
-
-    React.cloneElement @props.post,
-      thread        : @state.messageThread
-      messages      : @state.messageThreadComments
-      channelThread : @state.channelThread

   renderSidebar: ->
@@ -104,14 +86,8 @@
           {@renderHeader()}

-

-            {@renderFeed()}
-

             {@renderChat()}
-

-

-            {@renderPost()}


Koding-Admin: TeamListController: add pagination support for team listing

--- client/admin/lib/views/koding-admin/teamlistcontroller.coffee
+++ client/admin/lib/views/koding-admin/teamlistcontroller.coffee
@@ -10,34 +10,89 @@

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

-    options.noItemFoundText  ?= 'No teams found!'
+    options = kd.utils.extend {}, options,
+      limit               : 30
+      noItemFoundText     : 'No teams found!'
+      useCustomScrollView : yes
+      startWithLazyLoader : yes
+      lazyLoadThreshold   : .99
+      lazyLoaderOptions   :
+        spinnerOptions    :
+          size            : width: 28
+
     super options, data

-    @loadItems()
+    @states =
+      skip  : 0
+      busy  : no
+      query : {}
+
+
+  followLazyLoad: ->
+
+    @on 'LazyLoadThresholdReached', kd.utils.debounce 300, =>
+
+      return  @hideLazyLoader()  if @states.busy
+
+      @states.busy  = yes
+      @states.skip += @getOption 'limit'
+
+      @fetch @states.query, (err, teams) =>
+
+        @hideLazyLoader()
+
+        if err or not teams
+          return @states.busy = no
+
+        @instantiateListItems teams
+        @states.busy = no
+
+      , { skip : @states.skip }
+
+
+  fetch: (query, callback, options = {}) ->
+
+    { JGroup } = remote.api
+
+    options.limit ?= @getOption 'limit'
+    options.sort   = '_id' : -1
+
+    JGroup.someWithRelationship query, options, (err, teams) =>
+
+      if err
+        @hideLazyLoader()
+        showError err, \
+          KodingError : "Failed to fetch data, try again later."
+        return
+
+      callback err, teams

   loadItems: (slug) ->

     @removeAllItems()
-    @getListView()._currentItem = null
     @showLazyLoader()

-    { JGroup } = remote.api
-    query      = {
+    @states.skip = 0
+
+    query = {
       slug: { $nin: ['koding', 'guests'] }
     }

     if slug
       query.slug.$in = [ slug ]

-    # TODO Add Pagination here ~ GG
-    JGroup.someWithRelationship query, { limit: 30 }, (err, teams) =>
+    @states.query = query
+
+    @fetch @states.query, (err, teams) =>

       @hideLazyLoader()
-
-      return if showError err, \
-        KodingError : "Failed to fetch teams, try again later."
-
       @instantiateListItems teams

-      @emit 'ItemsLoaded', teams
+
+  loadView: ->
+
+    super
+
+    @loadItems()
+    @followLazyLoad()


Make sure the getMoreAppsButton is always positioned at the end

--- client/app/Applications/StartTab.kdapplication/AppView.coffee
+++ client/app/Applications/StartTab.kdapplication/AppView.coffee
@@ -204,7 +204,7 @@
     @removeAppIcon app  for app in removedApps
     @createAppsIcons @appsController.getManifests()  if newApps.length > 0

-  createAppIcon:(app, appData)->
+  createAppIcon:(app, appData, bulk=no)->

     log "ADDING:", appData
     @appIcons[app]?.destroy()
@@ -212,10 +212,13 @@
       delegate : @
     , appData

+    # To make sure its always the last icon
+    @createGetMoreAppsButton()  unless bulk
+
   createAppsIcons:(apps)->
     for app, appData of apps
       do (app, appData)=>
-        @createAppIcon app, appData
+        @createAppIcon app, appData, yes

     # To make sure its always the last icon
     @createGetMoreAppsButton()


EnvironmentMachineState: lazy fetch stack from machine id

Since the userMachines coming from payload, we need to wait until an action taken

--- client/app/lib/providers/environmentsmachinestatemodal.coffee
+++ client/app/lib/providers/environmentsmachinestatemodal.coffee
@@ -54,8 +54,6 @@
     @show()

     {computeController} = kd.singletons
-
-    @stack = computeController.findStackFromMachineId @machine._id

     computeController.ready => whoami().isEmailVerified (err, verified) =>

@@ -182,8 +180,8 @@
     computeController.on "stop-#{@machineId}",  @bound 'updateStatus'

     # Stack build events
-    if @stack
-      computeController.on "apply-#{@stack._id}", @bound 'updateStatus'
+    if stack = computeController.findStackFromMachineId @machine._id
+      computeController.on "apply-#{stack._id}", @bound 'updateStatus'

     computeController.on "reinit-#{@machineId}", (event) =>
       @updateStatus event, 'reinit'
@@ -576,19 +574,21 @@

   turnOnMachine: ->

+    computeController = kd.getSingleton 'computeController'
+
     trackEvent 'Turn on machine, click',
       category : 'userInteraction'
       label    : 'turnedOnVM'
       action   : 'clicks'

     target     = @machine
-
-    if @stack and @state is NotInitialized and \
+    stack      = computeController.findStackFromMachineId @machine._id
+
+    if stack and @state is NotInitialized and \
        @machine.jMachine.generatedFrom?.templateId?
       action   = 'buildStack'
-      target   = @stack
-
-    computeController = kd.getSingleton 'computeController'
+      target   = stack
+
     computeController.off  "error-#{target._id}"

     @emit 'MachineTurnOnStarted'


Don't use jQuery to check for native support in the sticky polyfill.

This fixes an issue with Firefox when the loaded content isn’t yet
visible.

--- src/scripts/polyfills/position-sticky-polyfill.coffee
+++ src/scripts/polyfills/position-sticky-polyfill.coffee
@@ -111,10 +111,10 @@
   # it does, we'll just skip the polyfill altogether.
   #
   isSupportedNatively = ->
-    testElement = ($ '<test-element>')
+    testElement = document.createElement('test-element')
     for prefix in [ '', '-webkit-', '-moz-', '-ms-' ]
-      testElement.css('position', "#{prefix}sticky")
-      return true if testElement.css('position').indexOf('sticky') != -1
+      testElement.style.position = "#{prefix}sticky"
+      return true if testElement.style.position.indexOf('sticky') != -1
     false

   #


comment out the avatar thing

comment out the avatar thing

--- src/packages/collaboration/lib/participant-view.coffee
+++ src/packages/collaboration/lib/participant-view.coffee
@@ -22,8 +22,8 @@
     @video.click =>
       @toggleClass('large')

-    emailMd5 = crypto.createHash('md5').update(@participant.email).digest('hex')
-    @avatar.css('background-image': "http://www.gravatar.com/avatar/#{emailMd5}?s=160")
+    #emailMd5 = crypto.createHash('md5').update(@participant.email).digest('hex')
+    #@avatar.css('background-image': "http://www.gravatar.com/avatar/#{emailMd5}?s=160")

     @removeButton.click @onClickRemove
     @toggleVideoButton.click @onClickToggleVideo


we need to set this for the initial bar, otherwise there's a small jump at the beginning

--- src/packages/editor-stats/src/editor-stats-view.coffee
+++ src/packages/editor-stats/src/editor-stats-view.coffee
@@ -32,9 +32,10 @@
     w = @rootView.vertical.width()
     h = @height()
     data = d3.entries @stats.eventLog
+    max  = d3.max data, (d) -> d.value

     @x.rangeBands [0, w - @pl - @pr], 0.2
-    @y.range [h - @pt - @pb, 0]
+    @y.domain([0, max]).range [h - @pt - @pb, 0]

     @xaxis ?= d3.svg.axis().scale(@x).orient('top')
       .tickSize(-h + @pt + @pb)


Send annotation after clear on IE11/IE11, fix #2467

--- src/resources-packaged/xbl/orbeon/wpaint/wpaint.coffee
+++ src/resources-packaged/xbl/orbeon/wpaint/wpaint.coffee
@@ -55,7 +55,7 @@
                 # tabindex="-1" allows div to have the focus, used to send change on blur
                 @wpaintElC = $('<div class="fr-wpaint-container-c" tabindex="-1"/>')
                 @wpaintElB.append(@wpaintElC)
-                @wpaintElC.blur(=> @blur())
+                @wpaintElC.on('focusout', => @blur())
                 @wpaintElC.css('width',  @imageEl.width()  + 'px')
                 @wpaintElC.css('height', @imageEl.height() + 'px')
                 annotation = @annotationEl.attr('src')
@@ -71,7 +71,8 @@
         @wpaintElC.focus()

     # When looses focus, send drawing to the server right away (incremental)
-    blur: -> @_sendAnnotationToServer()
+    blur: ->
+        @_sendAnnotationToServer()

     _imgIsEmpty: (imgEl) ->
         imgSrc = imgEl.attr('src')


Sorting Hub and Producer filter selectors by name

--- app/assets/javascripts/admin/bulk_order_management.js.coffee
+++ app/assets/javascripts/admin/bulk_order_management.js.coffee
@@ -1,6 +1,6 @@
 angular.module("ofn.admin").controller "AdminOrderMgmtCtrl", [
-  "$scope", "$http", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
-  ($scope, $http, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
+  "$scope", "$http", "$filter", "dataFetcher", "blankOption", "pendingChanges", "VariantUnitManager", "OptionValueNamer", "SpreeApiKey"
+  ($scope, $http, $filter, dataFetcher, blankOption, pendingChanges, VariantUnitManager, OptionValueNamer, SpreeApiKey) ->
     $scope.loading = true

     $scope.initialiseVariables = ->
@@ -42,10 +42,10 @@
         if $scope.spree_api_key_ok
           $http.defaults.headers.common["X-Spree-Token"] = SpreeApiKey
           dataFetcher("/api/enterprises/accessible?template=bulk_index&q[is_primary_producer_eq]=true").then (data) ->
-            $scope.suppliers = data
+            $scope.suppliers = $filter('orderBy')(data, 'name')
             $scope.suppliers.unshift blankOption()
             dataFetcher("/api/enterprises/accessible?template=bulk_index&q[sells_in][]=own&q[sells_in][]=any").then (data) ->
-              $scope.distributors = data
+              $scope.distributors = $filter('orderBy')(data, 'name')
               $scope.distributors.unshift blankOption()
               ocFetcher = dataFetcher("/api/order_cycles/accessible?as=distributor&q[orders_close_at_gt]=#{formatDate(daysFromToday(-90))}").then (data) ->
                 $scope.orderCycles = data


admin: fixed nav menu after edit in modal moved to right

--- app/assets/javascripts/camaleon_cms/admin/nav_menu.js.coffee
+++ app/assets/javascripts/camaleon_cms/admin/nav_menu.js.coffee
@@ -79,7 +79,7 @@
           return false
         showLoading()
         $.post(form.attr('action'), form.serialize(), (res)->
-          link.closest('li').replaceWith(res)
+          link.closest('li').replaceWith($(res).html())
           modal.modal("hide")
           hideLoading()
         )


switched dashboard over to inherit straight from Spine.Model.

--- app/assets/javascripts/habberdash/models/dashboard.js.coffee
+++ app/assets/javascripts/habberdash/models/dashboard.js.coffee
@@ -1,3 +1,2 @@
-class Habberdash.Dashboard extends Habberdash.Model
-  @options 'title', 'color', 'backgroundColor', 'image', 'centerImage'
-  @configure 'Dashboard'
+class Habberdash.Dashboard extends Spine.Model
+  @configure 'Dashboard', 'title', 'color', 'backgroundColor', 'image', 'centerImage'


Removed $translate service from account controller

--- app/assets/javascripts/sprangular/controllers/account.coffee
+++ app/assets/javascripts/sprangular/controllers/account.coffee
@@ -4,8 +4,7 @@
   $routeParams,
   Status,
   Account,
-  user,
-  $translate
+  user
 ) ->
   Status.setPageTitle('nav.my_account')


fix feature flags at the course level.

fix feature flags at the course level.

fixes CNVS-9708

test plan:
  * navigate to a course with an available feature flag;
  * attempt to turn the flag on/off and verify that your
    changes persist across page refreshes.

Change-Id: I12ab472fa40d7d321a17d0a9dc5bbab4e386653b
Reviewed-on: https://gerrit.instructure.com/26731
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
QA-Review: Steven Shepherd <e794458448443812fb2685675aab3bbd1a3891bc@instructure.com>
Reviewed-by: Jon Willesen <eb5ce5e6a76c243326fecfa94534101600f87bd9@instructure.com>
Product-Review: Zach Pendleton <514dbb4d54d4f29e454990df7d075678f43f92aa@instructure.com>

--- app/coffeescripts/views/feature_flags/FeatureFlagView.coffee
+++ app/coffeescripts/views/feature_flags/FeatureFlagView.coffee
@@ -29,7 +29,7 @@
       @$detailToggle.toggleClass('icon-mini-arrow-down')

     shouldDelete: (action) ->
-      ENV.ACCOUNT.site_admin && @model.get('hidden') && action == 'off'
+      ENV.ACCOUNT?.site_admin && @model.get('hidden') && action == 'off'

     toggleValue: ($target) ->
       $target.siblings().removeClass('active').attr('aria-checked', false)


removed ununsed classname

removed ununsed classname

--- core/app/backbone/views/sub_comments/react_sub_comment.coffee
+++ core/app/backbone/views/sub_comments/react_sub_comment.coffee
@@ -22,7 +22,7 @@
           Factlink.Global.t.ago

       R.span
-        className: "subcomment-content spec-subcomment-content",
+        className: "spec-subcomment-content",
         dangerouslySetInnerHTML: {__html: @model().get('formatted_comment_content')}

       if @model().can_destroy()


Change an erroneous `logger.error` to `logger.log`

--- services/web/app/coffee/Features/DocumentUpdater/DocumentUpdaterHandler.coffee
+++ services/web/app/coffee/Features/DocumentUpdater/DocumentUpdaterHandler.coffee
@@ -224,7 +224,7 @@
 				logger.error {error, url, project_id}, "error update project structure in doc updater"
 				callback(error)
 			else if res.statusCode >= 200 and res.statusCode < 300
-				logger.error {project_id}, "updated project structure in doc updater"
+				logger.log {project_id}, "updated project structure in doc updater"
 				callback(null)
 			else
 				logger.error {project_id, url}, "doc updater returned a non-success status code: #{res.statusCode}"


Add `merge` static method to ActivateClientModules for convenience.

--- base/ActivateClientModules.cjsx
+++ base/ActivateClientModules.cjsx
@@ -24,3 +24,13 @@
         <script dangerouslySetInnerHTML={
             __html: _script
         }/>
+
+    statics:
+        # Merges last-to-first for cleaner usage syntax, unlike normal
+        # underscore.extend.
+        merge: (module_deps...) ->
+            modules = {}
+            while module_deps.length > 0
+                for k,v of module_deps.pop()
+                    modules[k] = v
+            return modules


align interfaces

align interfaces

--- js/src/engine/KryptnosticEngine.coffee
+++ js/src/engine/KryptnosticEngine.coffee
@@ -60,7 +60,7 @@
     getEncryptedSearchToken: (token) ->
       return new Module.KryptnosticClient().getEncryptedSearchToken(token)

-    getTokenAddress: (token, documentKey) ->
+    getTokenAddress: (token, objectAddressFunction, objectSearchKey) ->
       throw new Error 'unimplemented'

   return KryptnosticEngine


Update news.coffee

Update news.coffee

--- server/materials/data/news.coffee
+++ server/materials/data/news.coffee
@@ -3,6 +3,12 @@

 export default allNews = () ->
     return news([
+        newsItem("Окончание очных занятий в этом году", String.raw"""
+            Последние очные занятия в этом учебном году состоятся 25 мая в лицее 40 и 29 мая во ВШЭ. Летом очных занятий не будет.
+            В следующем учебном году занятия начнутся ориентировочно в середине сентября, следите за объявлениями на сайте.
+        """),
+
+
         newsItem("28 мая пройдет XVIII олимпиада им В. Д. Лелюха", String.raw"""
             28 мая 2022 года состоится XVIII Нижегородская городская олимпиада школьников по информатике им. В.Д. Лелюха. Подробнее
         """),
@@ -14,11 +20,6 @@
             В этом году летом опять будет проходить стажировка на алгопроге. Кто хочет поучаствовать, пишите.
         """),

-        newsItem("Занятия в майские праздники", String.raw"""
-            1, 8 и 15 мая занятий во ВШЭ не будет. 22 мая занятие будет.

-            4 и 11 мая занятий в лицее 40 не будет. 27 апреля занятие будет, 18 мая тоже, скорее всего, будет.
-        """),
-
         newsItem("Опрос про алгопрог", String.raw"""
             Ответьте, пожалуйста, на несколько вопросов. Тем, кто уже отвечал — я там добавил несколько вопросов, можете ответить еще раз.
         """),


make symlink for shared folder in user's home

--- kites/sharedHosting/fileSharing.coffee
+++ kites/sharedHosting/fileSharing.coffee
@@ -7,6 +7,7 @@

 config =
   baseSharedDir : '/Shared'
+  baseDir : '/Users'
   setfacl : '/usr/bin/setfacl'

@@ -21,44 +22,71 @@
       return true

+linkToHome = (owner, username, callback) ->
+  sharedDir = path.join config.baseSharedDir, owner
+  symlink   = path.join config.baseDir, username, "Shared", owner
+  link  = "/bin/ln -s #{sharedDir} #{symlink}"
+  exec link, (err, stdout, stderr) ->
+    if err?
+      log.error err = "[ERROR] Can't link #{sharedDir} to #{symlink}"
+      callback err
+    else
+      log.info "[OK] shared dir #{sharedDir} linked to #{symlink}"
+      callback null

-setOwnerAcl = (username, callback) ->
-  if not username?
+setOwnerAcl = (owner, callback) ->
+  if not owner?
     log.error err = "[ERROR] username should be defined"
     callback err
   else
-    sharedDir = path.join config.baseSharedDir, username
-    if not execFacl(username, sharedDir)
+    sharedDir = path.join config.baseSharedDir, owner
+    if not execFacl(owner, sharedDir)
       callback "[ERROR] can't share dir #{sharedDir}"
+    else
+      callback null

-createSharedDir = (username, callback) ->
-  sharedDir = path.join config.baseSharedDir, username
+createSharedDir = (owner, callback) ->
+  sharedDir = path.join config.baseSharedDir, owner
+  console.log owner
   fs.mkdir sharedDir, 0720, (err, stat) ->
     if err?
       log.error err
       callback err
     else
-      setOwnerAcl username,(err)->
+      setOwnerAcl owner,(err)->
         if err?
           callback err
         else
-          log.info "[OK] shared dir #{sharedDir} for user #{username} successfully created "
-          callback null
+          linkToHome owner, owner, (err) ->
+            if err?
+              log.error err = "[ERROR] Couldnt create shared dir for #{owner}"
+              callback err
+            else
+              log.info "[OK] shared dir #{sharedDir} for user #{owner} successfully created"
+              callback null

-shareWithUser = (owner, user, callback)->
+shareWithUser = (owner, username, callback)->

   sharedDir = path.join config.baseSharedDir, owner
-  setfacl   = "#{config.setfacl} -m d:u:#{user}:rwx #{sharedDir} && #{config.setfacl} -R -m u:#{user}:rwx #{sharedDir}"
-
-  exec setfacl, (err, stdout, stderr) ->
-    if err?
-      log.error err = "[ERROR] Can't execute #{setfacl}: #{stderr}"
-      callback err
-    else
-      log.info "[OK] acl on #{sharedDir} changed with #{setfacl}"
-      callback null
+  if not execFacl(username, sharedDir)
+    callback "[ERROR] can't share dir #{sharedDir} for user #{username}"
+  else
+     linkToHome owner, username, (err) ->
+       if err?
+         log.error err = "[ERROR] Couldnt share  dir #{sharedDir} with #{username}"
+         callback err
+       else
+         log.info "[OK] dir #{sharedDir} successfully shared with #{username}"
+         callback null

+#createSharedDir "alekseymykhailov", (err)->
+#  if err?
+#    log.error err
+
+#shareWithUser "alekseymykhailov", "devrim",(err)->
+#  if err?
+#    log.error err


move extra controller to controller

move extra controller to controller

--- shared/ironTableController.coffee
+++ shared/ironTableController.coffee
@@ -208,7 +208,7 @@
                 recordDisplayName: @_recordName() + ' ' + record[@_colToUseForName()]
                 editOk: @collection().editOk?(record)
                 deleteOk: @collection().deleteOk?(record)
-                extraControls: @collection().extraControls?(record)
+                extraControls: @extraControls?(record)

         recordDisplayStop = @skip() + recordData.length


filter changes

filter changes

--- shared/ironTableController.coffee
+++ shared/ironTableController.coffee
@@ -104,12 +104,10 @@
         for key, col of @_cols()
             #if not (col.hide?() or col.hide)
             dataKey = col.dataKey or key
-            if col.noFilterOn?
-                noFilterOn = col.noFilterOn
-            else if col.type in ['boolean']
-                noFilterOn = true
+            if col.canFilterOn? and not col.hide?()
+                canFilterOn= col.canFilterOn
             else
-                noFilterOn = false
+                canFilterOn = false
             rtn.push
                 key: key
                 dataKey: dataKey
@@ -119,7 +117,7 @@
                 desc: @sortDirection is -1
                 sortDirection: if dataKey is @sortColumn then -@sortDirection else @sortDirection
                 filterOnThisCol: dataKey is @_sess('filterColumn')
-                canFilterOn: col.canFilterOn
+                canFilterOn: canFilterOn
                 hide: col.hide?()
         rtn


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/flickerable.coffee
+++ test/flickerable.coffee
@@ -26,7 +26,7 @@

   5.times (n) ->
     if n is 0
-      pl
+

   player.update()
   equals player.I.alpha, 0.2


adding elapsedTime

adding elapsedTime

--- test/game_object.coffee
+++ test/game_object.coffee
@@ -38,7 +38,7 @@

   gameObject.update()

-test
+test "elapsed"

 test "[event] destroy", 2, ->
   GameObject


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/game_object.coffee
+++ test/game_object.coffee
@@ -19,7 +19,8 @@
 test "#closest", ->
   o = GameObject()

-  other =
+  other = GameObject
+    x:

   equals o.closest([]), null


FINALLY got unit tests working

FINALLY got unit tests working

--- spec/NetworkInteractions.spec.coffee
+++ spec/NetworkInteractions.spec.coffee
@@ -1,62 +1,71 @@
 soda = require("soda")
 describe "networkInteractions", ->
-  it "should give a player an id", ->
-    browser1 = soda.createClient(
+  it "should give each player a unique id", ->
+
+    ###
+    HOW THIS WORKS
+    1. Define the browser settings and set them up
+    2. Do the stuff we want to do using the browsers
+    3. In the mean time, wait until the browsers are finished doing what we want
+    4. Use the stuff we got from the browsers to do the actual jasmine test.
+
+    ###
+
+    #Define what URL will be in each browser etc.
+    browserSettings =
       host: "localhost"
       port: 4444
       url: "http://localhost:8080"
       browser: "firefox"
-    )

-    browser2 = soda.createClient(
-      host: "localhost"
-      port: 4444
-      url: "http://localhost:8080"
-      browser: "firefox"
-    )
+    # Define two browser windows.
+    browser1 = soda.createClient(browserSettings)
+    browser2 = soda.createClient(browserSettings)

+    # These are the ids we are going to get from the browser windows
     id1 = undefined
     id2 = undefined
-    finishedFirst = false
-    finishedSecond = false
+
+    # A busy-wait lock that gets released when browsers close
+    browsersClosed = false

+    # Open browser 1
+    browser1.session (err) ->
+      browser1.open "/", (err, body) ->
+        # Wait for the page (dom) to load. If more than 5000 milliseconds pass and the page hasn't loaded, exit.
+        browser1.waitForPageToLoad 5000, (err, body) ->
+          # Page is now loaded. Now, repeatedly check if Game.myPlayerId is defined. 20000 is the timeout
+          browser1.waitForCondition "typeof window.Game.myPlayerId !== 'undefined'", 20000, (err, body) ->
+            # Game.myPlayerId is finally defined. Now, get it's result and store it in body (the param call back)
+            browser1.getEval "storedVars['evalResult'] = window.Game.myPlayerId;", (err, body) ->
+              id1 = body
+              #OK, we're done with browser 1 but don't want to close it yet because we need to open
+              #a new browser window to check what tha player id for *it* is.
+              #Open a new browser
+              browser2.session (err) ->
+                browser2.open "/", (err, body) ->
+                  # Wait for the page to load
+                  browser2.waitForPageToLoad 5000, (err, body) ->
+                    # Wait up to 20000 milliseconds ultil the myPlayerId is defined.
+                    browser2.waitForCondition "typeof window.Game.myPlayerId !== 'undefined'", 20000, (err, body) ->
+                      # Get Game.myPlayerId
+                      browser2.getEval "storedVars['evalResult'] = window.Game.myPlayerId;", (err, body) ->
+                        id2 = body
+                        #Great, we now have the player id of browser 1 and browser two. Close browser 2.
+                        browser2.testComplete (err, body) ->
+                          # Browser 2 is now closed. Now close browser 1.
+                          browser1.testComplete (err, body) ->
+                            #Browser 1 *and* browser 2 are now close. We can now release the lock.
+                            browsersClosed = true
+
+
+    # Busy wait until the browsers close. Uses finishedTest to test this.
+    waitsFor(->
+      return browsersClosed == true
+    , "Browser test never completed", 100000);
+
+    # We need a 'runs' here to say "only run the runs code AFTER the waiting is done"
     runs(->
-      browser1.session (err) ->
-        browser1.open "/", (err, body) ->
-          browser1.waitForPageToLoad 5000, (err, body) ->
-            console.log err
-            evalResult = undefined
-            browser1.getEval "var tetris = 'JAMES'; storedVars['evalResult'] = tetris;", (err, body) ->
-              console.log "<<<<<<<<<<<<<INSIDE getEval>>>>>>>>>>>>>>>>"
-              console.log err
-              console.log body
-              console.log "<<<<<<<<<<<<<>>>>>>>>>>>>>>>>"
-              browser1.testComplete (err, body) ->
-                console.log "done"
-                finishedFirst = true
-                finishedSecond = true
-
+      # Finally, do the unit test (this is normal jasmine stuff)
+      expect(id1).not.toEqual(id2)
     )
-
-
-    waitsFor(->
-      return finishedFirst == true
-    , "First browser never completed", 20000);
-
-    runs(->
-      #browser2.chain.session().open("/").waitForPageToLoad(5000).end (err) ->
-      #  browser2.testComplete ->
-      #    console.log "done 2"
-      #    finishedSecond = true
-      #    throw err  if err
-    )
-
-    waitsFor( ->
-      return finishedSecond == true
-    , "Second browser never completed", 20000);
-
-    runs(->
-      console.log browserTitle1
-      console.log browserTitle2
-      expect(browserTitle1).toEqual(browserTitle2)
-    )


fix var name

fix var name


Update spec behavior for new logic

Update spec behavior for new logic

--- spec/package-detail-view-spec.coffee
+++ spec/package-detail-view-spec.coffee
@@ -64,14 +64,16 @@
     expect(view.element.querySelectorAll('.package-card').length).toBe(0)

   it "shows an error when package metadata cannot be loaded from the cache and the network is unavailable", ->
+    localStorage.removeItem('settings-view:packages/some-package')
+
     spyOn(AtomIoClient.prototype, 'online').andReturn(false)
-    spyOn(AtomIoClient.prototype, 'request').andCallThrough()
-    spyOn(AtomIoClient.prototype, 'fetchFromCache').andReturn({})
+    spyOn(AtomIoClient.prototype, 'request').andCallFake (path, callback) ->
+      callback(new Error('getaddrinfo ENOENT atom.io:443'))
+    spyOn(AtomIoClient.prototype, 'fetchFromCache').andCallThrough()

     view = new PackageDetailView({name: 'some-package'}, new SettingsView(), packageManager, SnippetsProvider)

     expect(AtomIoClient.prototype.fetchFromCache).toHaveBeenCalled()
-    expect(AtomIoClient.prototype.request).not.toHaveBeenCalled()

     expect(view.refs.errorMessage.classList.contains('hidden')).not.toBe(true)
     expect(view.refs.loadingMessage.classList.contains('hidden')).toBe(true)


Increase sweet spot for selecting a link [#117645883]

--- src/code/utils/js-plumb-diagram-toolkit.coffee
+++ src/code/utils/js-plumb-diagram-toolkit.coffee
@@ -157,7 +157,7 @@
   addLink: (source, target, label, color, magnitude, isDashed, isSelected, isEditing, gradual, useGradient, useVariableThickness, linkModel) ->
     paintStyle = @_paintStyle @defaultLinkColor
     paintStyle.outlineColor = "none"
-    paintStyle.outlineWidth = 1
+    paintStyle.outlineWidth = 10

     startColor = @defaultLinkColor
     finalColor = @defaultLinkColor


Typos

Typos

--- src/coffee/services/product-projections.coffee
+++ src/coffee/services/product-projections.coffee
@@ -242,7 +242,7 @@
   #
   # Examples
   #
-  #   service = client.products
+  #   service = client.productProjections
   #   service
   #   .text('Red Shirt')
   #   .sort('createdAt desc')
@@ -259,12 +259,13 @@
   #
   # Examples
   #
-  #   service = client.products
+  #   service = client.productProjections
   #   service
   #   .asSearch()
   #   .process(...)
   asSearch: ->
     @_currentEndpoint = '/product-projections/search'
+    debug 'setting search endpoint: %s', @_currentEndpoint
     this

   ###*
@@ -280,10 +281,11 @@
   #
   # Examples
   #
-  #   service = client.products
+  #   service = client.productProjections
   #   service.searchKeywords('Swiss Army Knife', 'en').suggest()
   suggest: ->
     @_currentEndpoint = '/product-projections/suggest'
+    debug 'setting suggest endpoint: %s', @_currentEndpoint
     @fetch()

   # Public Unsupported: Not supported by the API


Use properties instead of local variables

--- test/parser_spec.coffee
+++ test/parser_spec.coffee
@@ -3,13 +3,13 @@

 Parser = require('../lib/parser')

-
 describe 'Parser', ->
-  dummy  = fs.createReadStream('./test/fixtures/dummy.html')
-  parser = new Parser(dummy)
+  beforeEach ->
+    @dummy  = fs.createReadStream('./test/fixtures/dummy.html')
+    @parser = new Parser(@dummy)

   it 'lists available years', (done) ->
-    parser.getYears (err, years) ->
+    @parser.getYears (err, years) ->
       expect(err).to.be.null
       expect(years).to.be.eql years: ['2001', '2002', '2003', '2004']
       done()


Update admins

Update admins

--- workers/social/lib/social/models/account/index.coffee
+++ workers/social/lib/social/models/account/index.coffee
@@ -693,9 +693,9 @@
     , (err, count)=>
       @update ($set: 'counts.topics': count), ->

-  dummyAdmins = [ "sinan", "devrim", "gokmen", "chris", "blum", "neelance", "halk"
-                  "fatihacet", "chrisblum", "sent-hil", "kiwigeraint", "cihangirsavas"
-                  "fkadev" ]
+  dummyAdmins = [ "sinan", "devrim", "gokmen", "chris", "halk", "neelance",
+                  "fatihacet", "sent-hil", "kiwigeraint", "cihangirsavas",
+                  "fkadev", "bahadir", "arslan" ]

   userIsExempt: (callback)->


MachineSettingsPopup: Removed hidden class from share section.

--- client/app/lib/providers/machinesettingspopup.coffee
+++ client/app/lib/providers/machinesettingspopup.coffee
@@ -293,7 +293,6 @@

           "
           itemClass    : ManageSharedView
-          cssClass     : 'hidden'
           machine      : @machine
         domains        :
           label        : "


Fix checkbox handling in options page.

Fix checkbox handling in options page.

Seems like an entire 'else' clause was somehow dropped.

--- options/options.coffee
+++ options/options.coffee
@@ -84,6 +84,8 @@
   unless field.getAttribute("type") is "checkbox"
     field.value = value
     field.setAttribute "savedValue", value
+  else
+    field.checked = value

 openAdvancedOptions = (event) ->
   elements = document.getElementsByClassName("advancedOption")


made links open in new window

made links open in new window

--- client/app/lib/providers/machinesettingsdiskusageview.coffee
+++ client/app/lib/providers/machinesettingsdiskusageview.coffee
@@ -55,7 +55,7 @@

     @addSubView new KDCustomHTMLView
       cssClass : 'footline'
-      partial  : "If you have a paid plan or storage through referrals, you can resize your VM.  Share Koding and get more storage for free!"
+      partial  : "If you have a paid plan or storage through referrals, you can resize your VM.
Share Koding and get more storage for free!"
       click    : (e) =>
         if e.target.tagName is 'A'


Added focus method and called it when ace is ready.

--- client/landing/app/Applications/Ace.kdapplication/ace.coffee
+++ client/landing/app/Applications/Ace.kdapplication/ace.coffee
@@ -31,6 +31,7 @@
           @utils.wait => @emit "ace.ready"
           @setContents contents if contents
           @editor.gotoLine 0
+          @focus()
           @show()

   prepareEditor:->
@@ -241,6 +242,8 @@
     @setUseWordWrap no if value is "off"

     @appStorage.setValue 'softWrap', value, =>
+
+  focus: -> @editor?.focus()

   ###
   HELPERS


Fix origin on subparts of function type

Fix origin on subparts of function type

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1674,7 +1674,7 @@
           call.tea = op.tea =
             if body and body.tea
               new Constrained (join body.tea.constraints, deferredConstraints),
-                withOrigin (typeFn paramTypeVars..., body.tea?.type), call
+                mapOriginOnFunction (typeFn paramTypeVars..., body.tea?.type), call
             else if explicitType
               (copyOrigin (freshInstance ctx, explicitType), compiledType)
           # """λ#{paramNames.length}(function (#{listOf paramNames}) {
@@ -5020,6 +5020,13 @@
     mutateMarkingOrigin to, from.origin
   to

+mapOriginOnFunction = (type, expression) ->
+  if isFunctionType type
+    withOrigin type, expression
+    withOrigin type.op, expression
+    mapOriginOnFunction type.arg, expression
+  type
+
 mapOrigin = (type, expression) ->
   mutateMappingOrigin type, expression
   type


Reindent

Reindent

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -1234,15 +1234,15 @@
     node.tea = subExp s, node.tea if node.tea

 inferWheres = (context, pairs, nameIndex) ->
-    for [name, def] in pairs
-      addToMap context, name.token, freshName nameIndex++
-    for [name, def] in pairs
-      [s1, nameIndex, def] = infer context, def, nameIndex
-      s2 = unify (subExp s1, (inSet context, name.token)), def.tea
-      context = subContext (concatMaps s2, s1), context
-    for [name, def] in pairs
-      name.tea = def.tea = (inSet context, name.token)
-      [name, def]
+  for [name, def] in pairs
+    addToMap context, name.token, freshName nameIndex++
+  for [name, def] in pairs
+    [s1, nameIndex, def] = infer context, def, nameIndex
+    s2 = unify (subExp s1, (inSet context, name.token)), def.tea
+    context = subContext (concatMaps s2, s1), context
+  for [name, def] in pairs
+    name.tea = def.tea = (inSet context, name.token)
+    [name, def]

 infer = (context, expression, nameIndex) ->
   switch expression.label


Fixed printing of quantified vars, although not sure why I have them there

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -5376,6 +5376,10 @@
           niceName type.name
         else
           "#{type.name}"
+  else if type.QuantifiedVar
+    themize (if type.error
+      'malformed'
+    else 'typename'), niceName type.var
   else if type.TypeConstr
     kindedToHtml type, type.name
   else if type.TypeApp


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -17,7 +17,7 @@
     x: 0
     y: 15

-
+  equals engine.closest

 test "#each", ->
   engine = Engine()


Remove redundant labeling and use backslash for characters

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -9,7 +9,7 @@
       | [#{controls}] # delims
       | /([^\\x20]|\\/)([^/]|\\/)*?/ # regex
       | "[^"]*?" # strings
-      | '\\?[^']' # char
+      | \\[^\x20] # char
       | [^#{controls}"'\s]+ # normal tokens
       )///
     if not match
@@ -61,8 +61,10 @@
   labelMapping atom,
     ['numerical', /^-?\d+/.test symbol]
     ['label', isLabel atom]
-    ['string', /^["']/.test symbol]
+    ['string', /^"/.test symbol]
+    ['char', /^\\/.test symbol]
     ['regex', /^\/[^ \/]/.test symbol]
+    ['const', /^[A-Z][^\s]*$/.test symbol] # TODO: instead label based on context
     ['paren', symbol in ['(', ')']]
     ['bracket', symbol in ['[', ']']]
     ['brace', symbol in ['{', '}']]
@@ -1061,15 +1063,7 @@
     yes

 atomCompile = (ctx, atom) ->
-  {symbol} = atom
-  # Syntax
-  atom.label = regexMapping symbol,
-    ['numerical', /^~?\d+/]
-    ['const', /^[A-Z][^\s]*$/]
-    ['string', /^["]/]
-    ['char', /^[']/]
-    ['regex', /^\/[^ \/]/]
-  {label} = atom
+  {symbol, label} = atom
   # Typing and Translation
   {type, translation, pattern} =
     switch label


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/engine_selector.coffee
+++ test/engine_selector.coffee
@@ -17,7 +17,7 @@
     x: 0
     y: 15

-  equals engine.closest ".enemy", pl
+  equals engine.closest)".enemy", player.position()

 test "#each", ->
   engine = Engine()


TAP5-2362: Client-side regular expression field validation should ensure that the entire value matches the pattern

--- tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/validation.coffee
+++ tapestry-core/src/main/coffeescript/META-INF/modules/t5/core/validation.coffee
@@ -1,5 +1,3 @@
-# Copyright 2012 The Apache Software Foundation
-#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
@@ -143,7 +141,11 @@
         re = new RegExp(@attr "data-validate-regexp")
         @meta REGEXP_META, re

-      unless re.test memo.translated
+      groups = memo.translated.match re
+
+      # Unlike Java, there isn't an easy way to match the entire string. This
+      # gets the job done.
+      if (groups is null) or (groups[0] isnt memo.translated)
         memo.error = (@attr "data-regexp-message") or "INVALID"
         return false


Visually display capturing in Client

Visually display capturing in Client

Still a little buggy, sometimes needs a refresh. Percentage in Database
not set/updated correctly or fast enough?

--- client.coffee
+++ client.coffee
@@ -103,8 +103,36 @@

 addProgressBar = ->
 	Db.shared.observeEach 'game', 'beacons', (beacon) !->
-		if beacon.get('inRange', Plugin.userId())?
-			nextColor = Db.shared.get('colors', Db.shared.get('game', 'beacons', beacon.n, 'owner'), 'hex')
+		if beacon.get('inRange', Plugin.userId())?
+			dbPercentage = beacon.get("percentage")
+			nextPercentage = -1
+			nextColor = ""
+			action = beacon.get('action')
+			if action == "capture"
+				nextPercentage=100
+				dbPercentage += (new Date() /1000 -beacon.get("actionStarted"))/30 * 100
+				log "actionStarted = " + beacon.get("actionStarted")
+				if dbPercentage > 100
+					dbPercentage = 100
+				nextColor = Db.shared.get('colors', Db.shared.get('game', 'beacons', beacon.n, 'nextOwner'), 'hex')
+			else if action == "neutralize"
+				nextPercentage=0
+				dbPercentage -= (new Date() /1000 -beacon.get("actionStarted"))/30 * 100
+				if dbPercentage < 0
+					dbPercentage = 0
+				nextColor = Db.shared.get('colors', Db.shared.get('game', 'beacons', beacon.n, 'owner'), 'hex')
+			else
+				nextPercentage = dbPercentage
+				if beacon.get("owner")==-1
+					nextColor = Db.shared.get('colors', Db.shared.get('game', 'beacons', beacon.n, 'nextOwner'), 'hex')
+				else
+					nextColor = Db.shared.get('colors', Db.shared.get('game', 'beacons', beacon.n, 'owner'), 'hex')
+			time = 0
+
+
+			if nextPercentage != dbPercentage
+				time = Math.abs(dbPercentage-nextPercentage) * 300
+			log "nextPercentage = ", nextPercentage, ", dbPercentage = ", dbPercentage, ", time = ", time, ", action = ", action
 			Dom.div !->
 				Dom.style
 					height: "20px"
@@ -116,9 +144,15 @@
 				Dom.div !->
 					Dom.style
 						height: "20px"
-						width: "20%"
 						backgroundColor: nextColor
 						zIndex: "10"
+					Dom._get().style.width = dbPercentage + "%"
+					Dom._get().style.transition = "width " + time + "ms linear"
+					window.progressElement = Dom._get()
+					blabla = () -> window.progressElement.style.width = nextPercentage + "%"
+					window.setTimeout(blabla, 1)
+
+

 # Home page with map


Update test_coffeelint to be a better assertion

--- test/test_coffeelint.coffee
+++ test/test_coffeelint.coffee
@@ -41,9 +41,11 @@
             assert.lengthOf(errors, 1)
             error = errors[0]
             assert.equal(error.rule, 'coffeescript_error')
-            m = "Error: Parse error on line 3: Unexpected 'RELATION'"
-            assert.notEqual(error.message.indexOf('RELATION'), -1)
-            assert.notEqual(error.message.indexOf('Error'), -1)
+            if error.message.indexOf('on line') != -1
+                m = "Error: Parse error on line 3: Unexpected 'RELATION'"
+            else
+                m = "SyntaxError: unexpected RELATION"
+            assert.equal(error.message, m)
             assert.equal(error.lineNumber, 3)

 }).export(module)


test(macAffix): Removed jQuery dependency

Related to #7

--- test/unit/affix.spec.coffee
+++ test/unit/affix.spec.coffee
@@ -20,7 +20,7 @@
     $compile(element) $rootScope

     $rootScope.$digest()
-    angular.element(window).trigger "scroll"
+    angular.element(window).triggerHandler "scroll"

     $rootScope.affixDisabled = true
     $rootScope.$digest()


Fix polyfills error handling

Fix polyfills error handling

--- test/utils/polyfills.coffee
+++ test/utils/polyfills.coffee
@@ -27,10 +27,10 @@
     faulty = ->
       document.write

-    faulty().should.throw
+    faulty().should.throw Error

   it 'should throw error on document.writeln', ->
     faulty = ->
       document.writeln

-    faulty().should.throw
+    faulty().should.throw Error


Removed unit test file

Removed unit test file

--- spec/bookmarklet-view-spec.coffee
+++ spec/bookmarklet-view-spec.coffee
@@ -1,5 +0,0 @@
-BookmarkletView = require '../lib/bookmarklet-view'
-
-describe "BookmarkletView", ->
-  it "has one valid test", ->
-    expect("life").toBe "easy"


Update package name to language-gfm

Update package name to language-gfm

--- spec/markdown-preview-spec.coffee
+++ spec/markdown-preview-spec.coffee
@@ -3,7 +3,7 @@

 describe "Markdown preview package", ->
   beforeEach ->
-    atom.activatePackage('gfm')
+    atom.activatePackage('language-gfm', sync: true)
     window.rootView = new RootView
     atom.activatePackage("markdown-preview", immediate: true)
     spyOn(MarkdownPreviewView.prototype, 'renderMarkdown')


Minor js fix so edit form gets more reliably placed

--- app/assets/javascripts/flyover_comments/comments.coffee
+++ app/assets/javascripts/flyover_comments/comments.coffee
@@ -61,8 +61,8 @@
         textarea = $f.find("textarea")
         textarea.attr("id", "comment_content_"+commentId)
         textarea.text(content.text().trim())
+        $f.insertAfter(content)
         content.hide()
-        $(@).prepend($f)

   $(document).on "ajax:success", ".flyover-comment-edit-form", (e, response, status, err)->
     $(@).remove()


Adding more specificity around event triggers for empty collection views

--- app/assets/javascripts/luca/core/collection_view.coffee
+++ app/assets/javascripts/luca/core/collection_view.coffee
@@ -123,7 +123,10 @@
     @trigger("before:refresh", models, query, options)

     if models.length is 0
-      @trigger("empty:results")
+      @trigger("empty:results", query, options)
+
+    if @getCollection()?.length > 0 and models.length is 0
+      @trigger("empty:filter", query, options)

     index = 0
     for model in models


do not set class on state-update in js.

do not set class on state-update in js.

--- app/assets/javascripts/ontology_version-state.js.coffee
+++ app/assets/javascripts/ontology_version-state.js.coffee
@@ -17,9 +17,7 @@
         current_state = state

         # display the new state
-        container
-          .attr('class', state)
-          .find("span").text(state)
+        container.find("span").text(state)

         if state == "pending"
           $(".pending_message").show()


Assert for sane SQL SET options

Assert for sane SQL SET options

--- specs/tsql/tsql-utils.spec.coffee
+++ specs/tsql/tsql-utils.spec.coffee
@@ -67,7 +67,8 @@
     it 'should retrieve SQL options', (done) ->
         utils.getOptions (err, opt) ->
             return done(err) if err
-            console.log(opt)
+            opt.should.eql([ 'ANSI_WARNINGS', 'ANSI_PADDING', 'ANSI_NULLS', 'ARITHABORT',
+                'QUOTED_IDENTIFIER', 'ANSI_NULL_DFLT_ON', 'CONCAT_NULL_YIELDS_NULL' ])
             done()

 )


if parent if embbedable is a "p", replace it, instead

--- src/scripts/modules/media/body/body.coffee
+++ src/scripts/modules/media/body/body.coffee
@@ -257,7 +257,10 @@
       embeddableItem.$el = @$el.find(embeddableItem.selector) if embeddableItem.selector

       $parent = embeddableItem.$el.parent()
-      embeddableItem.$el.replaceWith(embeddableItem.html)
+      if $parent.prop('tagName')?.toLowerCase() is 'p'
+        $parent.replaceWith(embeddableItem.html)
+      else
+        embeddableItem.$el.replaceWith(embeddableItem.html)

       embeddableItem.onRender?($parent)


removed a console.log leftover

removed a console.log leftover

--- app/assets/javascripts/d3/bezier.coffee
+++ app/assets/javascripts/d3/bezier.coffee
@@ -41,7 +41,6 @@
         .attr("transform", "translate(#{margins.left}, #{margins.top})")

       legend_columns = if @model.series.length > 6 then 2 else 1
-      console.log legend_columns
       @draw_legend
         svg: @svg
         series: @model.series.models


Login: setting background logic has changed

--- client/Login/AppView.coffee
+++ client/Login/AppView.coffee
@@ -1,8 +1,6 @@
 class LoginView extends JView

   stop = KD.utils.stopDOMEvent
-
-  @backgroundImageNr = backgroundImageNr = KD.utils.getRandomNumber 15

   backgroundImages  = [

@@ -72,8 +70,14 @@

   ]

-
-
+  @backgroundImageNr = backgroundImageNr = KD.utils.getRandomNumber 15
+
+  do ->
+    image      = new Image
+    bgImageUrl = "../a/images/unsplash/#{backgroundImageNr}.jpg"
+    image.src  = bgImageUrl
+
+    image.classList.add 'off-screen-login-image'

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


Login: remove changing cookie

Login: remove changing cookie

--- client/Login/AppView.coffee
+++ client/Login/AppView.coffee
@@ -385,9 +385,7 @@
       @$('.flex-wrapper').removeClass 'shake'
       KD.utils.defer => @$('.flex-wrapper').addClass 'animate shake'
     else
-      {account, replacementToken} = params
-      $.cookie 'clientId', replacementToken  if replacementToken
-
+      {account} = params
       # check and set preferred BE domain for Koding
       # prevent user from seeing the main wiev
       KD.utils.setPreferredDomain account if account


Remove workspace snapshot when machine is terminated

--- client/ide/lib/index.coffee
+++ client/ide/lib/index.coffee
@@ -461,7 +461,15 @@
         if event.status in actionRequiredStates
           @showStateMachineModal machineItem, event

+        switch event.status
+          when Terminated then @handleMachineTerminated()
+
       .on "reinit-#{machineItem._id}", @bound 'handleMachineReinit'
+
+
+  handleMachineTerminated: ->
+
+    @once 'IDEDidQuit', @bound 'removeWorkspaceSnapshot'

   handleMachineReinit: ({status}) ->
@@ -470,6 +478,7 @@
       when 'Building'
         environmentDataProvider.ensureDefaultWorkspace kd.noop
       when 'Running'
+        @once 'IDEDidQuit', @bound 'removeWorkspaceSnapshot'
         @quit()


removed chatstream client hooks

removed chatstream client hooks

--- client/notifications.coffee
+++ client/notifications.coffee
@@ -22,11 +22,6 @@
     stack: true
     offset: 40

-  # publish alerts for new chat messages
-  chatStream = new Meteor.Stream 'notificationStream'
-  chatStream.on 'chatMessage', (message) ->
-    sAlert.info "New Chat Message
#{message.text}"
-
   Meteor.subscribe 'events', ->
     starting = true
     Events.find().observe added: (e) ->


Oops, should have been part of 290cf5178f4b10790c0ce057ce0a731900cf6e92 (tx-builder changes related to p2sh outputs support)

--- client/tx/tx-builder.coffee
+++ client/tx/tx-builder.coffee
@@ -1,10 +1,12 @@
 { Bitcoin, Crypto, BigInteger } = require '../../lib/bitcoinjs-lib.js'
 { iferr, error_displayer } = require '../util.coffee'
-{ get_address, parse_address, parse_key_bytes, get_pub, ADDR_PUB, ADDR_PRIV } = require '../bitcoin.coffee'
+{ get_address, parse_address, parse_key_bytes, get_pub
+  create_out_script, get_script_address
+  ADDR_PUB, ADDR_PRIV, ADDR_P2SH } = require '../bitcoin.coffee'
 { sign_tx, calc_total_in, sum_inputs, decode_raw_tx } = require './lib.coffee'
 { tx_listen, load_unspent } = require './networking.coffee'
 { bytesToHex } = Crypto.util
-{ Transaction, Util: BitUtil } = Bitcoin
+{ Transaction, TransactionOut, Util: BitUtil } = Bitcoin

 # Initialize the transaction builder interface,
 # and return a teardown function
@@ -92,11 +94,9 @@
   # Read outputs from DOM
   $form.find('.address').each ->
     $this = $ this
-    try tx.addOutput
-      hash: parse_address $this.find('[name=address]').val(), ADDR_PUB
-      BitUtil.parseValue $this.find('[name=value]').val()
-    # just ignore invalid addresses/amount, the user still have to
-    # confirm the transaction after that and should see it missing
+    tx.addOutput new TransactionOut
+      script: create_out_script $this.find('[name=address]').val()
+      value: BitUtil.parseValue($this.find('[name=value]').val()).toByteArrayUnsigned().reverse()
   tx

 # Display the transaction dialog
@@ -112,7 +112,7 @@

     dialog = $ view {
       outs: for { script: out_script, value } in tx.outs
-        address: get_address out_script.simpleOutHash(), ADDR_PUB
+        address: get_script_address out_script
         value: BitUtil.formatValue value.slice().reverse()
       has_priv: priv?
       pub_address: get_address pub, ADDR_PUB


Adding patient again now appends surgical path numbers

--- collections/patients.coffee
+++ collections/patients.coffee
@@ -1,5 +1,14 @@
 if Meteor.isServer
     Hashids = Meteor.require "hashids"
+
+    mergeSurgicalPathologyNumbers = (oldNumbers, newNumbers) ->
+        surgicalPathologyNumbers = oldNumbers.concat newNumbers
+        # Based on http://coffeescriptcookbook.com/chapters/arrays/removing-duplicate-elements-from-arrays
+        output = {}
+        output[JSON.stringify(surgicalPathologyNumbers[key])] = JSON.stringify(surgicalPathologyNumbers[key]) for key in [0...surgicalPathologyNumbers.length]
+        return (JSON.parse(value) for key, value of output)
+
+
     Meteor.methods
         patient: (patientAttributes) ->
             user = Meteor.user()
@@ -10,17 +19,19 @@
             if not Roles.userIsInRole @userId, ["admin", "tech"] then throw new Meteor.Error 401, "You are not authorized to add patients"
             if not hasAttributes patientAttributes, ["firstName", "lastName", "mrn"]
                 throw new Meteor.Error 422, "Patient first name, last name, and MRN are required"
-            if patientWithSameMRN then throw new Meteor.Error 302, "This patient has already been created", patientWithSameMRN._id

-            # Generate Short ID
-            hasher = new Hashids Meteor.uuid(), 6
-            shortId = hasher.encrypt parseInt patientAttributes.mrn, 10
+            if patientWithSameMRN # Update Patient with any new Surgical Path #'s
+                surgicalPathologyNumbers = mergeSurgicalPathologyNumbers patientWithSameMRN.surgicalPathologyNumbers, patientAttributes.surgicalPathologyNumbers
+                Patients.update patientWithSameMRN._id, $set: surgicalPathologyNumbers: surgicalPathologyNumbers
+                return patientWithSameMRN.shortId

-            patient = _.extend patientAttributes,
-                added: new Date().getTime()
-                addedBy: user._id
-                shortId: shortId

-            patientId = Patients.insert(patient)
-
-            return shortId
+            else # Create a new patient
+                hasher = new Hashids Meteor.uuid(), 6
+                shortId = hasher.encrypt parseInt patientAttributes.mrn, 10 # Generate Short ID
+                patient = _.extend patientAttributes,
+                    added: new Date().getTime()
+                    addedBy: user._id
+                    shortId: shortId
+                patientId = Patients.insert(patient)
+                return shortId


checkout the correct version

checkout the correct version

--- server-ce/Gruntfile.coffee
+++ server-ce/Gruntfile.coffee
@@ -132,7 +132,9 @@
 		["check:make"].concat(
 			("install:#{service.name}" for service in SERVICES)
 		).concat([ "install:dirs"])
+
 	grunt.registerTask 'install', 'install:all'
+
 	grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services",
 		["check:make"].concat(
 			("update:#{service.name}" for service in SERVICES)
@@ -194,14 +196,19 @@
 			if !fs.existsSync(dir)
 				proc = spawn "git", [
 					"clone",
-					"-b", service.version,
 					repo_src,
 					dir
 				], stdio: "inherit"
 				proc.on "close", () ->
-					callback()
+					Helpers.checkoutVersion service, callback
 			else
 				console.log "#{dir} already installed, skipping."
+				callback()
+
+		checkoutVersion: (service, callback = (error) ->) ->
+			dir = service.name
+			proc = spawn "git", ["checkout", service.version], stdio: "inherit", cwd: dir
+			proc.on "close", () ->
 				callback()

 		updateGitRepo: (service, callback = (error) ->) ->


fix for noun project api

fix for noun project api

--- server/api/use/noun.coffee
+++ server/api/use/noun.coffee
@@ -29,8 +29,9 @@
     body: res

 API.use.noun.icon = (term,set) ->
-  res = API.http.cache(term, 'noun_icon') if not set?
-  if not res?
+  #res = API.http.cache(term, 'noun_icon') if not set?
+  #if not res?
+  if true
     res = API.use.noun.search {icon:(if set? then set else term)}
     if res?.icon?
       API.http.cache term, 'noun_icon', res
@@ -39,8 +40,9 @@
   return res

 API.use.noun.icons = (term) ->
-  res = API.http.cache term, 'noun_icons'
-  if not res?
+  #res = API.http.cache term, 'noun_icons'
+  #if not res?
+  if true
     res = API.use.noun.search {icons:term}
     if res?.icons?
       API.http.cache term, 'noun_icons', res
@@ -53,9 +55,9 @@
   return {} if JSON.stringify(params) is '{}'
   url = 'http://api.thenounproject.com/' #icon/6324'
   if params.icons?
-    url += 'icons/' + params.icons.replace(/ing$/,'e')
+    url += 'icons/' + params.icons
   else if params.icon?
-    url += 'icon/' + params.icon.replace(/ing$/,'e')
+    url += 'icon/' + params.icon
   API.log 'Using noun project for ' + url
   # search_for is required
   try


Better debug output

Better debug output

--- server/lib/download.coffee
+++ server/lib/download.coffee
@@ -36,7 +36,7 @@
             return page
         catch e
             logger.info "Error downloading " + href + " " + i + " will re-download", e.message
-            logger.info e, e.stack
+            logger.info e.stack
             await sleep(delay)
             delay *= 2
     addStats("fail")


Gave the hidden collections their own variable

--- server/publications.coffee
+++ server/publications.coffee
@@ -50,7 +50,8 @@
   else
     Houston._collections.collections.insert {name, count: collection.find().count(), fields: fields}

-collections = {'users': Meteor.users, 'meteor_accounts_loginServiceConfiguration': undefined}
+hidden_collections = {'users': Meteor.users, 'meteor_accounts_loginServiceConfiguration': undefined}
+collections = {}
 sync_collections = ->
   Dummy.findOne()  # hack. TODO: verify this is still necessary

@@ -60,7 +61,7 @@
            (col.collectionName.indexOf "houston_") isnt 0)

     collection_names.forEach (name) ->
-      unless name of collections
+      unless name of collections or name of hidden_collections
         try
           collections[name] = new Meteor.Collection(name)
         catch e


update rectangle mark details when details form changes

--- overrides.coffee
+++ overrides.coffee
@@ -100,9 +100,9 @@
     else
       task.next = 'details'

-classify_page.el.on 'decision-tree:task-confirm', ({originalEvent: {detail}})->
-  console.log 'confirm'
+classify_page.el.on decisionTree.CHANGE, ({originalEvent: {detail}})->
+  {key, value} = detail

-  if detail?.details?
-    current_tool.mark.details = detail.details
+  if key is 'details'
+    current_tool.mark.details = value.details


KodingRouter: changed opensection logic

KodingRouter: changed opensection logic

removed:
- setting initial route
- change group on every opensection

--- client/Main/kodingrouter.coffee
+++ client/Main/kodingrouter.coffee
@@ -15,9 +15,8 @@
     @openRoutes     = {}
     @openRoutesById = {}
     KD.singleton('display').on 'DisplayIsDestroyed', @bound 'cleanupRoute'
-    @ready = no
+
     KD.getSingleton('mainController').once 'AccountChanged', =>
-      @ready = yes
       @utils.defer => @emit 'ready'

     super()
@@ -81,22 +80,15 @@
     delete @openRoutes[@openRoutesById[contentDisplay.id]]

   openSection:(app, group, query)->
-    return @once 'ready', @openSection.bind this, arguments...  unless @ready
-
-    KD.getSingleton('groupsController').changeGroup group, (err)=>
-      if err then new KDNotificationView title: err.message
-      else
-        # temp fix for not showing homepage to loggedin users
-        # app = 'Activity' if app is 'Home' and KD.isLoggedIn()
-
+
+    @ready =>
+      {appManager, groupsController} = KD.singletons
+      groupsController.ready =>
         @setPageTitle nicenames[app] ? app
-        appManager  = KD.getSingleton "appManager"
         handleQuery = appManager.tell.bind appManager, app, "handleQuery", query

         appManager.once "AppCreated", handleQuery  unless appWasOpen = appManager.get app
-
-        appManager.open app, (appInstance)=>
-          appInstance.setOption "initialRoute", @getCurrentPath()
+        appManager.open app

         handleQuery()  if appWasOpen

@@ -288,7 +280,6 @@
       '/:name?/Logout'         : ({params:{name}})-> requireLogin -> mainController.doLogout()

       '/:name?/Topics/:slug'   : createContentHandler 'Topics'
-      '/:name?/Activity/:slug' : createContentHandler 'Activity'

       '/:name/Groups'          : createSectionHandler 'Groups'
       '/:name/Followers'       : createContentHandler 'Members', yes


AppController: Refactor for ace.removeModifiedFromTab.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -656,9 +656,7 @@

     @forEachSubViewInIDEViews_ 'editor', (editorPane) ->
       {ace} = editorPane.aceView
-      ace.once 'FileContentRestored', ->
-        ace.removeModifiedFromTab editorPane.aceView
-
+      ace.once 'FileContentRestored', -> ace.removeModifiedFromTab()
       editorPane.emit 'SaveRequested'


Collaboration: Fixed typo in ParticipantWantsToLeave.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1572,7 +1572,7 @@
       when 'ParticipantWantsToLeave'

         @statusBar.removeParticipantAvatar origin
-        @removeParticipantCursorWidget targetUser
+        @removeParticipantCursorWidget data.target

       when 'ParticipantKicked'


Collaboration: Quit IDE if current user is left

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1682,7 +1682,10 @@

     {origin, type} = data

-    return  if origin is KD.nick()
+    if origin is KD.nick()
+      if type is 'ParticipantWantsToLeave'
+      then return @quit()
+      else return

     switch type


activity: don't emit feed-new events since we're listening to PostIsCreated

--- workers/social/lib/social/models/activity/index.coffee
+++ workers/social/lib/social/models/activity/index.coffee
@@ -40,7 +40,7 @@
     sharedEvents      :
       instance        : []
       static          : ['BucketIsUpdated', 'cacheWorker'
-                         'ActivityIsCreated', 'feed-new']
+                         'ActivityIsCreated']
     sharedMethods     :
       static          : [
         'fetchFolloweeContents'
@@ -76,12 +76,6 @@
       originType      : String
       originId        : ObjectId
       group           : String
-
-  @on 'feed-new', (activities)->
-    JGroup = require '../group'
-    grouped = groupBy activities, 'group'
-    for own groupName, items of grouped
-      JGroup.broadcast groupName, 'feed-new', items

   @fetchLastActivityTimestamp = (callback) ->
     selector  = {}


CustomPartials: Added preview related fields to model.

--- workers/social/lib/social/models/custompartials.coffee
+++ workers/social/lib/social/models/custompartials.coffee
@@ -6,14 +6,16 @@
   @share()

   @set
-    indexes         :
-      partialType   : 'sparse'
-    schema          :
-      name          : String
-      partialType   : String
-      partial       : String
-      isActive      : Boolean
-      viewInstance  : String
+    indexes           :
+      partialType     : 'sparse'
+    schema            :
+      name            : String
+      partialType     : String
+      partial         : String
+      isActive        : Boolean
+      isPreview       : Boolean
+      previewInstance : String
+      viewInstance    : String

     sharedMethods :
       static      :


Referral: remove unnecessary signature

Referral: remove unnecessary signature

--- workers/social/lib/social/models/referral/index.coffee
+++ workers/social/lib/social/models/referral/index.coffee
@@ -34,10 +34,8 @@
   @set
     sharedMethods     :
       static          :
-        addExtraReferral:[
+        addExtraReferral:
           (signature Object, Function)
-          (signature Object, Object, Function)
-        ]
         redeem:
           (signature Object, Function)
         changeBaseVMForUsers:[


Don't clear entries when switching feeds.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -363,8 +363,6 @@
         $('.app').addClass('nothing-selected').removeClass('feed-selected entry-selected')

       $(document).on 'click', '[data-behavior~=show_entries]', (event) ->
-        unless $(event.target).hasClass('back-button')
-          feedbin.clearEntries()
         $('.app').addClass('feed-selected').removeClass('nothing-selected entry-selected')

       $(document).on 'click', '[data-behavior~=show_entry_content]', ->


menu closes itself once a link is clicked

--- app/assets/javascripts/homepage.coffee
+++ app/assets/javascripts/homepage.coffee
@@ -23,6 +23,10 @@
           else
             target = jumpobj.attr('href')
             offset = jQuery(target).offset().top
+          $('#toggle_menu').slideToggle ->
+            $('body > header').toggleClass('menu-open')
+            if $('#toggle_menu').is(':hidden')
+              $('#toggle_menu').removeAttr 'style'
           thespeed = 1000
           jQuery('html,body').animate { scrollTop: offset }, thespeed, 'swing'
           e.preventDefault()


Remove broken image fix for now. (#5)

Remove broken image fix for now. (#5)

There are too many difference in how Chrome and Firefox handles broken image events to make this code feasible. I may put avatar images into background images in order to solve this in the long run.

--- app/assets/javascripts/pants.js.coffee
+++ app/assets/javascripts/pants.js.coffee
@@ -11,17 +11,11 @@
   #
   $('[autofocus="autofocus"]').focus()

-  # When images fail loading, replace them with our magic transparent pixel.
-  #
-  $("img").error ->
-    $(this).attr("src", "/images/1x1.png")
-
   # Run dem trackers if available.
   #
   _gs('track') if (_gs?)
   ga('send', 'pageview') if (ga?)

-
 $(document)
   .on 'page:load', initPage
   .on 'ready', initPage


Better option element selector

Better option element selector

--- app/assets/javascripts/postages.coffee
+++ app/assets/javascripts/postages.coffee
@@ -5,7 +5,7 @@
 $ ->
   $('#prefectures').change ->

-    name = $('option:selected').html()
+    name = $(this).children().filter(':selected').html()
     # .val() will gets an id

     jsonPref = { "name": name }


Pass detail through to event.

Pass detail through to event.

--- app/assets/javascripts/s3_relay.coffee
+++ app/assets/javascripts/s3_relay.coffee
@@ -26,7 +26,7 @@
       public_url: publicUrl
     success: (data, status, xhr) ->
       privateUrl = data.private_url
-      publishEvent "upload:success", "detail"
+      publishEvent "upload:success", { uuid: uuid }
     error: (xhr) ->
       console.log xhr.responseText


fix tabIndex for subTask OK button

fix tabIndex for subTask OK button

--- app/classifier/drawing-tools/root.cjsx
+++ app/classifier/drawing-tools/root.cjsx
@@ -70,7 +70,7 @@
               <TaskComponent autoFocus={i is 0} key={detailTask._key} task={detailTask} annotation={toolProps.mark.details[i]} onChange={@handleDetailsChange.bind this, i} />}

-              <button autoFocus={toolProps.details[0].type in ['single', 'multiple']} type="submit" className="standard-button" disabled={not detailsAreComplete}>OK</button>
+              <button tabIndex="0" autoFocus={toolProps.details[0].type in ['single', 'multiple']} type="submit" className="standard-button" disabled={not detailsAreComplete}>OK</button>

           </ModalFocus>
         </StickyModalForm>}


implementing hypothesis deletion. refs #8

--- app/components/hypothesis-block.coffee
+++ app/components/hypothesis-block.coffee
@@ -3,4 +3,9 @@
 hypothesisComponent = Ember.Component.extend
   classNames: ['panel', 'panel-default']

+  actions:
+    remove: ->
+      if confirm "Are you sure you want to delete that hypothesis?"
+        @getAttr('hypothesis').destroyRecord()
+
 `export default hypothesisComponent`


No need this, my mistake. It breaks reset in TagController

--- components/autocomplete/KDAutoCompleteController.coffee
+++ components/autocomplete/KDAutoCompleteController.coffee
@@ -32,11 +32,9 @@
     @selectedItemCounter = 0

   reset:->
-    {itemClass} = @getOptions()
     subViews    = @itemWrapper.getSubViews().slice()
     for item in subViews
-      if item instanceof itemClass
-        @removeFromSubmitQueue item
+      @removeFromSubmitQueue item

   loadView:(mainView)->
     @createDropDown()


Better error messages in tests, tweaked large_message test data.

--- tests/html/src/tests.coffee
+++ tests/html/src/tests.coffee
@@ -29,9 +29,8 @@
                 r.send(a[0])
         r.onclose = (e) ->
             if a.length
-                ok(false, "Transport closed prematurely.")
+                ok(false, "Transport closed prematurely. " + e)
             else
-                log('onclose ' + e)
                 ok(true)
             start()

@@ -122,11 +121,12 @@
     # Should be larger than 128k - the limit for a single request in
     # some streaming transports.
     messages = [
-        Array(4096).join('x'),
-        Array(4096*2).join('x'),
-        Array(4096*4).join('x'),
-        Array(4096*8).join('x'),
-        Array(Math.pow(2,18)).join('x'),
+        Array(Math.pow(2,1)).join('x'),
+        Array(Math.pow(2,2)).join('x'),
+        Array(Math.pow(2,4)).join('x'),
+        Array(Math.pow(2,8)).join('x'),
+        Array(Math.pow(2,16)).join('x'),
+        Array(Math.pow(2,17)).join('x'),
         Array(Math.pow(2,18)).join('x'),
     ]
     return echo_factory_factory(protocol, messages)
@@ -148,7 +148,10 @@
             if counter is messages.length
                 r.close()
         r.onclose = (e) ->
-            ok(true)
+            if counter isnt messages.length
+                ok(false, "Transport closed prematurely. " + e)
+            else
+                ok(true)
             start()

 factor_batch_large = (protocol) ->


Testing CI

Testing CI

--- spec/e2e.stubs.spec.coffee
+++ spec/e2e.stubs.spec.coffee
@@ -295,5 +295,6 @@
           createRequest context

           waitsFor ( -> context.done ), 'body match', 1000, ->
-            assert context.response.data is 'body contents!'
-            done()
+            console.log context.response.data
+            assert context.response.data.length isnt 0
+            done()


failing test for clearInterval/clearTimeout which should not throw exceptions with invalid timers

--- spec/eventloop_spec.coffee
+++ spec/eventloop_spec.coffee
@@ -52,6 +52,11 @@
           browser.wait 300, @callback
         "should fire only uncancelled timeout events": (browser)->
           assert.equal browser.document.title, "One Two"
+        "should not choke on invalid timers": (browser)->
+          assert.doesNotThrow ->
+            # clearTimeout should not choke when clearing an invalid timer
+            # https://developer.mozilla.org/en/DOM/window.clearTimeout
+            browser.window.clearTimeout undefined

     "outside wait":
       Browser.wants "http://localhost:3003/eventloop/timeout"
@@ -119,6 +124,10 @@
             browser.wait 200, @callback
         "should fire only uncancelled interval events": (browser)->
           assert.equal browser.document.title, ".."
+        "should not throw an exception with invalid interval": (browser)->
+          assert.doesNotThrow ->
+            # clearInterval should not choke on invalid interval
+            browser.window.clearInterval undefined

     "outside wait":
       Browser.wants "http://localhost:3003/eventloop/interval"


:bug: Fix deprecated require in events helper file

--- spec/helpers/events.coffee
+++ spec/helpers/events.coffee
@@ -1,4 +1,4 @@
-{$} = require 'atom'
+{$} = require 'atom-space-pen-views'

 objectCenterCoordinates = (obj) ->
   {top, left} = obj.offset()


:white_check_mark: Add operator tests for multiple indents.

--- spec/operators-spec.coffee
+++ spec/operators-spec.coffee
@@ -1327,24 +1327,38 @@
           it "outdents all three lines", ->
             expect(editor.getText()).toBe "12345\nabcde\nABCDE"

-    describe "in visual mode", ->
+    describe "in visual mode linewise", ->
       beforeEach ->
         editor.setCursorScreenPosition([0, 0])
         keydown('v', shift: true)
-        keydown('>')
-
-      it "indents the current line and exits visual mode", ->
-        expect(editorElement.classList.contains('normal-mode')).toBe(true)
-        expect(editor.getText()).toBe "  12345\nabcde\nABCDE"
-        expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
-
-      it "allows repeating the operation", ->
-        keydown(".")
-        expect(editor.getText()).toBe "    12345\nabcde\nABCDE"
+        keydown('j')
+
+      describe "single indent multiple lines", ->
+        beforeEach ->
+          keydown('>')
+
+        it "indents both lines once and exits visual mode", ->
+          expect(editorElement.classList.contains('normal-mode')).toBe(true)
+          expect(editor.getText()).toBe "  12345\n  abcde\nABCDE"
+          expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
+
+        it "allows repeating the operation", ->
+          keydown('.')
+          expect(editor.getText()).toBe "    12345\n    abcde\nABCDE"
+
+      describe "multiple indent multiple lines", ->
+        beforeEach ->
+          keydown('2')
+          keydown('>')
+
+        it "indents both lines twice and exits visual mode", ->
+          expect(editorElement.classList.contains('normal-mode')).toBe(true)
+          expect(editor.getText()).toBe "    12345\n    abcde\nABCDE"
+          expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 4], [0, 4]] ]

   describe "the < keybinding", ->
     beforeEach ->
-      editor.setText("  12345\n  abcde\nABCDE")
+      editor.setText("    12345\n    abcde\nABCDE")
       editor.setCursorScreenPosition([0, 0])

     describe "when followed by a <", ->
@@ -1352,9 +1366,9 @@
         keydown('<')
         keydown('<')

-      it "indents the current line", ->
-        expect(editor.getText()).toBe "12345\n  abcde\nABCDE"
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      it "outdents the current line", ->
+        expect(editor.getText()).toBe "  12345\n    abcde\nABCDE"
+        expect(editor.getCursorScreenPosition()).toEqual [0, 2]

     describe "when followed by a repeating <", ->
       beforeEach ->
@@ -1362,25 +1376,43 @@
         keydown('<')
         keydown('<')

-      it "indents multiple lines at once", ->
-        expect(editor.getText()).toBe "12345\nabcde\nABCDE"
-        expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+      it "outdents multiple lines at once", ->
+        expect(editor.getText()).toBe "  12345\n  abcde\nABCDE"
+        expect(editor.getCursorScreenPosition()).toEqual [0, 2]

       describe "undo behavior", ->
         beforeEach -> keydown('u')

         it "indents both lines", ->
+          expect(editor.getText()).toBe "    12345\n    abcde\nABCDE"
+
+    describe "in visual mode linewise", ->
+      beforeEach ->
+        keydown('v', shift: true)
+        keydown('j')
+
+      describe "single outdent multiple lines", ->
+        beforeEach ->
+          keydown('<')
+
+        it "outdents the current line and exits visual mode", ->
+          expect(editorElement.classList.contains('normal-mode')).toBe(true)
           expect(editor.getText()).toBe "  12345\n  abcde\nABCDE"
-
-    describe "in visual mode", ->
-      beforeEach ->
-        keydown('v', shift: true)
-        keydown('<')
-
-      it "indents the current line and exits visual mode", ->
-        expect(editorElement.classList.contains('normal-mode')).toBe(true)
-        expect(editor.getText()).toBe "12345\n  abcde\nABCDE"
-        expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 0], [0, 0]] ]
+          expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
+
+        it "allows repeating the operation", ->
+          keydown('.')
+          expect(editor.getText()).toBe "12345\nabcde\nABCDE"
+
+      describe "multiple outdent multiple lines", ->
+        beforeEach ->
+          keydown('2')
+          keydown('<')
+
+        it "outdents both lines twice and exits visual mode", ->
+          expect(editorElement.classList.contains('normal-mode')).toBe(true)
+          expect(editor.getText()).toBe "12345\nabcde\nABCDE"
+          expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 0], [0, 0]] ]

   describe "the = keybinding", ->
     oldGrammar = []


Remove window handling in catch block

Remove window handling in catch block

The catch block in index.html takes care of this

--- spec/spec-bootstrap.coffee
+++ spec/spec-bootstrap.coffee
@@ -8,10 +8,7 @@
   document.title = "Spec Suite"
   runSpecSuite './spec-suite'
 catch error
-  unless atom.getLoadSettings().exitWhenDone
-    atom.getCurrentWindow().setSize(800, 600)
-    atom.getCurrentWindow().center()
-    atom.openDevTools()
-
-  console.error(error.stack ? error)
-  atom.exit(1) if atom.getLoadSettings().exitWhenDone
+  if atom?.getLoadSettings().exitWhenDone
+    atom.exit(1)
+  else
+    throw error


Fix flavored file stat

Fix flavored file stat

--- compilation/gulp-flavors.coffee
+++ compilation/gulp-flavors.coffee
@@ -38,7 +38,7 @@
       @push new File(cwd: cwd, base: base, path: path, contents: files[files.length - 1].contents, stat: files[0].stat)
     else
       buffer = ''
-      stat = files[0]
+      stat = files[0].stat
       for file in files
         buffer += file.contents.toString() + gutil.linefeed
         stat = file.stat if file.stat.mtime > stat.mtime


Remove Backbone dependency

Remove Backbone dependency

--- components/split_test/split_test.coffee
+++ components/split_test/split_test.coffee
@@ -1,5 +1,4 @@
 _ = require 'underscore'
-Backbone = require 'backbone'
 { CURRENT_USER, NODE_ENV } = require('sharify').data
 { load, getProperty, setProperty, unsetProperty, setDimension } = require '../../lib/analytics.coffee'
 IS_TEST_ENV = not _.contains(['production', 'staging', 'development'], NODE_ENV)


Correctly remove deleted comment (#3433)

--- angular/core/components/thread_page/comment_form/delete_comment_form.coffee
+++ angular/core/components/thread_page/comment_form/delete_comment_form.coffee
@@ -6,6 +6,9 @@
     $scope.submit = ->
       $scope.comment.destroy().then ->
         $scope.$close()
-        Records.events.find(commentId: $scope.comment.id)[0].delete()
+        _.find($scope.comment.discussion().events(), (event) ->
+          event.kind == 'new_comment' and
+          event.eventable.id == $scope.comment.id
+        ).delete()
       , ->
         $rootScope.$broadcast 'pageError', 'cantDeleteComment'


Fixed bug in ExplorativeTracingListView (via Airbrake)

--- app/assets/javascripts/dashboard/views/explorative_tracing_list_view.coffee
+++ app/assets/javascripts/dashboard/views/explorative_tracing_list_view.coffee
@@ -94,14 +94,18 @@
       data : "isActive=true"
     )

-    @datasetRegion = new Marionette.Region(
-      el : ".dataset-selection"
-    )
+    # NO DEV: Don't merge to dev
+    if not @model.get("isAdminView")
+      @datasetRegion = new Marionette.Region(
+        el : ".dataset-selection"
+      )

   onShow : ->

-    @datasetRegion.show(@datasetSelectionView)
+    # NO DEV: Don't merge to dev
+    if @datasetRegion
+      @datasetRegion.show(@datasetSelectionView)

   selectFiles : (event) ->


Prevent consoles access from unauthenticated users (temp fix #73).

--- app/scripts/controllers/console.coffee
+++ app/scripts/controllers/console.coffee
@@ -1,7 +1,7 @@
 'use strict'

 angular.module('xoWebApp')
-  .controller 'ConsoleCtrl', ($scope, $stateParams, xo) ->
+  .controller 'ConsoleCtrl', ($scope, $stateParams, xoApi, xo) ->
     {id} = $stateParams
     {get} = xo
     push = Array::push.apply.bind Array::push
@@ -15,6 +15,11 @@
     $scope.$watch(
       -> xo.revision
       ->
+        unless xoApi.user
+          $scope.consoleUrl = ''
+          $scope.VDIs = []
+          return
+
         VM = $scope.VM = xo.get id
         return unless VM? and VM.power_state is 'Running'


Only show user messages if in explore bucket

--- components/layout/client.coffee
+++ components/layout/client.coffee
@@ -71,8 +71,8 @@
       prefillSuccess: (data)-> mediator.trigger 'current_user:prefetched'
       success: (user, response)->
         mediator.trigger 'current_user:fetched'
-        # ensureFreshUser response.user
-        showNewUserMessages() if user.get('show_tour')
+        if user.get('show_tour') and sd.AFTER_ONBOARDING == 'explore'
+          showNewUserMessages()

   pusher= mediator.shared.pusher = new Pusher(sd.PUSHER_KEY) if Pusher?
   chan = mediator.shared.current_user_channel = pusher.subscribe "user_#{user.id}" if user.id and Pusher?


Correct logic for invite message

Correct logic for invite message

--- components/layout/client.coffee
+++ components/layout/client.coffee
@@ -160,7 +160,7 @@
 showInviteMessage = ->
   # Don't show this message if the current user is not logged in
   # or if they have a pending confirmation
-  return if CURRENT_USER?.is_pending_confirmation
+  return if !sd.CURRENT_USER or sd.CURRENT_USER?.is_pending_confirmation

   model = new Backbone.Model
     id: 'invite_friend'


config: fix email.host

config: fix email.host

--- config/main.kontrol-prod.coffee
+++ config/main.kontrol-prod.coffee
@@ -125,7 +125,7 @@
     disconnectTimeout: 3e3
     vhost       : 'kite'
   email         :
-    address     : "#{version}.x.koding.com"
+    host        : "#{version}.x.koding.com"
     protocol    : 'http:'
     defaultFromAddress: 'hello@koding.com'
   emailWorker   :


Lowercase port

Lowercase port

--- components/ClearRect.coffee
+++ components/ClearRect.coffee
@@ -17,6 +17,6 @@
         datatype: 'number'
         required: true

-    ArrayableHelper @, 'clearRect', ports
+    ArrayableHelper @, 'clearrect', ports

 exports.getComponent = -> new ClearRect


iterate over the proper thing

iterate over the proper thing

--- src/model/storage_adapters/rest_storage.coffee
+++ src/model/storage_adapters/rest_storage.coffee
@@ -157,7 +157,7 @@
       data = json

     if env.options.only?
-      for key of env.options.data
+      for key of data
         delete data[key] if !env.options.only.indexOf(key)

     if env.options.except?


fix chrome app unload listener

fix chrome app unload listener

--- client/landing/app/Applications/WebTerm.kdapplication/webtermappview.coffee
+++ client/landing/app/Applications/WebTerm.kdapplication/webtermappview.coffee
@@ -92,7 +92,6 @@
   chromeAppMode: ->
     windowController = KD.getSingleton("windowController")
     mainController   = KD.getSingleton("mainController")
-    windowController.clearUnloadListeners "window"

     # talking with chrome app
     if window.parent?.postMessage


Handle options not being passed

Handle options not being passed

--- services/real-time/app/coffee/Router.coffee
+++ services/real-time/app/coffee/Router.coffee
@@ -79,8 +79,22 @@
 					if err?
 						Router._handleError null, err, client, "leaveProject"

+			# Variadic. The possible options:
+			# doc_id, callback
+			# doc_id, fromVersion, callback
+			# doc_id, options, callback
+			# doc_id, options, fromVersion, callback
+			client.on "joinDoc", (doc_id, options, fromVersion, callback) ->
+				# options is optional
+				if typeof options == "function"
+					options = {}
+					callback = options
+					fromVersion = -1
+				else if typeof options == "number"
+					options = {}
+					fromVersion = options
+					callback = fromVersion

-			client.on "joinDoc", (doc_id, options, fromVersion, callback) ->
 				# fromVersion is optional
 				if typeof fromVersion == "function"
 					callback = fromVersion


Colors for teams (server)

Colors for teams (server)

woop 2

--- client.coffee
+++ client.coffee
@@ -110,7 +110,7 @@
 # Help page
 helpContent = ->
 	Dom.h2 "King of the Hill instructions!"
-	Dom.text "You are playing this game with " + Plugin.users.count().get() + " users that are randomly divided over X teams"
+	Dom.text "You are playing this game with " + Plugin.users.count().get() + " users that are randomly divided over " + Db.shared.get('game','numberOfTeams') + " teams"
 	Dom.br()
 	Dom.br()
 	Dom.text "On the main map there are several beacons. You need to venture to the real location of a beacon to conquer it. "
@@ -137,16 +137,29 @@
 	Dom.text "The last tab in the bar shows your current team score. You can tap it to quickly find out some personal details! "

 scoresContent = ->
-	Dom.text "The scores of all players:"
+	teamscore = 0
 	Dom.div ->
+		Dom.br()
 		Db.shared.observeEach 'game', 'teams', (team) !->
 			log 'team', team.n
-			Dom.h1 tr("Scores of team %1", team.n)
+			teamcolor = Db.shared.get('colors', team.n, 'hex')
+			teamname = Db.shared.get('colors', team.n, 'name')
+			log 'teamcolor', teamcolor
+			Dom.div !->
+				Dom.cls 'teampage'
+				Dom.style
+					color: teamcolor
+				Dom.text tr("Scores of team %1", teamname)
 			Db.shared.observeEach 'game', 'teams', team.n , 'users', (user) !->
 				log 'user', user.n
-				Dom.text tr("%1 has a score of: %2", user.n, user.get('userScore'))
+				teamscore = teamscore + user.get('userScore')
+				Dom.text tr("%1 has a score of: %2", Plugin.userName(user.n), user.get('userScore'))
 				Dom.br()
-
+			Dom.text tr("------------------------------")
+			Dom.br()
+			Dom.text tr("%Total teamscore: %1", teamscore)
+			Dom.br()
+			Dom.br()

 logContent = ->
 	Dom.text "The log file of all events"


Revert "Added settings page"

Revert "Added settings page"

This reverts commit 3f7776dcd8d84edd7471fcdb7dde36191514dc69.

--- client.coffee
+++ client.coffee
@@ -8,8 +8,6 @@
 Ui = require 'ui'
 CSS = require 'css'
 Geoloc = require 'geoloc'
-Form = require 'form'
-Num = require 'num'

 exports.render = ->

@@ -31,7 +29,6 @@
         logContent()
 	if !Geoloc.isSubscribed()
 		Geoloc.subscribe()
-
 	if Geoloc.isSubscribed()
 		state = Geoloc.track()
 		location = state.get('latlong');
@@ -42,26 +39,7 @@
 			marker.addTo(window.map)
 		else
 			log 'location could not be found'
-
-
-
-exports.renderSettings = !->
-	Dom.div !->
-		Dom.style Box: "middle", padding: '12px 40px 12px 8px'
-		Dom.div !->
-			Dom.style Flex: 'true'
-			Dom.text tr "Round time in hours "
-		Num.render
-			name: 'time'
-			value: 0||7*24
-	if Db.shared
-		Form.check
-			name: 'restart'
-			text: tr 'Restart'
-			sub: tr 'Check this to destroy the current game and start a new one.'
-
-
-
+

 # Load the javascript necessary for the map
 loadMap = ->


Fix applyInfo when cannon is not yet loaded

--- src/public/scripts/models/entity.player.coffee
+++ src/public/scripts/models/entity.player.coffee
@@ -252,7 +252,7 @@
 			if info.baseExtended?
 				@baseExtended = info.baseExtended

-			@cannon.applyInfo(info.cannon, timestamp)
+			@cannon?.applyInfo(info.cannon, timestamp)

 		# Returns the current info in an object.
 		#


base.coffe changes

base.coffe changes

--- src/scripts/helpers/backbone/views/base.coffee
+++ src/scripts/helpers/backbone/views/base.coffee
@@ -93,16 +93,17 @@
        parentId = @getTemplateData().parentId
        headTag = document.getElementsByTagName('head')[0]
        links = headTag.querySelectorAll('link')
-       if links.length
+       numberOfLinks = links.length
+       if numberOfLinks
         i = 0
-       while i < links.length
+       while i < numberOfLinks
         el = links[i]
         el.parentElement.removeChild el  if el.getAttribute('rel') is 'canonical'
         i++
        if parentId?
         canonicalLink = document.createElement('link')
         canonicalLink.rel = 'canonical'
-        canonicalLink.href = location.href + '/' + parentId
+        canonicalLink.href = location.hostname + '/' + parentId
         headTag.appendChild canonicalLink


Listen to change:content events

Listen to change:content events

--- src/scripts/modules/media/header/header.coffee
+++ src/scripts/modules/media/header/header.coffee
@@ -24,7 +24,7 @@

     initialize: () ->
       super()
-      @listenTo(@model, 'changePage', @render)
+      @listenTo(@model, 'changePage changePage:content', @render)

     onRender: () ->
       @attachPopover new BookPopoverView


Don't offer to derive pages in published books

--- src/scripts/modules/media/header/header.coffee
+++ src/scripts/modules/media/header/header.coffee
@@ -33,7 +33,7 @@
         currentPage: currentPageData
         hasDownloads: (_.isArray(downloads) and downloads?.length) or
           (_.isArray(pageDownloads) and pageDownloads?.length)
-        underivable: not currentPage?.isDraft()
+        underivable: not currentPage?.isDraft() and @model.isDraft()
         authenticated: session.get('username')
       }


style(cleanup): remove unnecessary log

style(cleanup): remove unnecessary log

--- src/spec/integration/products-sync.spec.coffee
+++ src/spec/integration/products-sync.spec.coffee
@@ -373,5 +373,4 @@
       )
       .catch (error) ->
         done(_.prettify(error))
-        console.log(JSON.stringify(error, null, 2))
     , 10000 # 10sec


[master] PP

[master] PP

--- translator/baidu-web.coffee
+++ translator/baidu-web.coffee
@@ -27,7 +27,8 @@
 )

 translate = (q) ->
-  q = q.trim()
+  # preprocessing
+  q = q.trim().replace /\u001d|\u2586/g, ' '
   query =
     from: 'zh'
     to: 'en'
@@ -68,8 +69,8 @@
 exports.translate = translate

 if require.main == module
-  a = '福音\n日本发生了一件千真万确的事：有人为了装修家里，拆开了墙；日式住宅的墙壁通常是中间架了木板后，两边批上泥土，其实里面是空的。他拆墙壁的时候，发现一只\u001d 壁虎被困'
-  translate a.replace(/\u001d/g, '')
+  a = '福音\n日本发生了一件千真万确的事：有人为了装修家里，拆开了墙；日式住宅的墙壁通常是中间架了木板后，两边批上泥土，其实里面是空的。他拆墙壁的时候，发现一只壁虎被困\u2586'
+  translate a.replace(/\u001d|\u2586/g, ' ')
   .then (i) ->
     console.log i
   .done()


CLEANUP - get ready - PointLayout creates 2 functions for every layout instance; this is probably a big perf hit; We don't need to do it that way! Fix coming as soon as I have some performance tests to measure the changes.

--- source/Art/Engine/Layout/PointLayout.coffee
+++ source/Art/Engine/Layout/PointLayout.coffee
@@ -20,7 +20,7 @@
       applyFunction v, newPointLayout

     newPointLayout.layoutX = if newPointLayout._hasXLayout
-      layoutX = @_buildXLayoutFromComponents(maxLayout)
+      layoutX = @_buildXLayoutFromComponents maxLayout
       newPointLayout._detectXRelativity layoutX if @needToDetectXRelativity
       layoutX
     else if previousLayout?._hasXLayout
@@ -208,11 +208,11 @@

     wpw:                      xpw
     hph:                      yph
+    wph:                      xph
+    hpw:                      ypw
+
     wcw:                      xcw
     hch:                      ych
-
-    wph:                      xph
-    hpw:                      ypw

     width:                    x
     height:                   y


validates strand (#115)

validates strand (#115)

--- exercises/nucleotide-count/nucleotide-count_test.spec.coffee
+++ exercises/nucleotide-count/nucleotide-count_test.spec.coffee
@@ -36,11 +36,17 @@
     dna.count('T')
     expect(dna.count('T')).toEqual 2

+  xit 'validates strand', ->
+    dna = new DNA('AGTXCG')
+    expect ->
+      dna.count 'G'
+    .toThrow new Error('Invalid nucleotide strand')
+
   xit 'validates nucleotides', ->
     dna = new DNA('GGTTGG')
     expect ->
       dna.count 'X'
-    .toThrow new Error('Invalid Nucleotide')
+    .toThrow new Error('Invalid nucleotide')

   xit 'counts all nucleotides', ->
     dna = new DNA('AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC')


Fix settings email select population

Fix settings email select population

--- public/settings.coffee
+++ public/settings.coffee
@@ -26,7 +26,7 @@

   # settings.default_email will contain either 'main', which is a directive to
   # use the main email address in settings.emails.main, or an email address
-  d.getElementById('default_email').value = if settings.default_email is 'main' then settings.emails.main else settings.default_email
+  d.getElementById('default_email').value = settings.default_email

   # TODO: populate the values and names of each Organization