vm: introducing .createVmByNonce

vm: introducing .createVmByNonce

also add the relevant fields to the bongo schema:

MaxMemoryInMB: Number
DiskSizeInMB: Number
AlwaysOn: Boolean
PinnedToHost: String

--- workers/social/lib/social/models/vm.coffee
+++ workers/social/lib/social/models/vm.coffee
@@ -39,10 +39,18 @@
       ]
     sharedMethods       :
       static            : [
-                           'fetchVms','fetchVmsByContext', 'fetchVmInfo'
-                           'fetchDomains', 'removeByHostname', 'someData'
-                           'count', 'fetchDefaultVm', 'fetchVmRegion' #'calculateUsage'
-                          ]
+          'fetchVms'
+          'fetchVmsByContext'
+          'fetchVmInfo'
+          'fetchDomains'
+          'removeByHostname'
+          'someData'
+          'count'
+          'fetchDefaultVm'
+          'fetchVmRegion'
+          'createVmByNonce'
+          #'calculateUsage'
+        ]
       instance          : []
     schema              :
       ip                :
@@ -74,25 +82,25 @@
         default         : 'user'
       users             : Array
       groups            : Array
-      usage             : # TODO: usage seems like the wrong term for this.
-        cpu             :
-          type          : Number
-          default       : 1
-        ram             :
-          type          : Number
-          default       : 0.25
-        disk            :
-          type          : Number
-          default       : 0.5
       isEnabled         :
         type            : Boolean
         default         : yes
       shouldDelete      :
         type            : Boolean
         default         : no
+      pinnedToHost      : String
+      alwaysOn          :
+        type            : Boolean
+        default         : no
+      maxMemoryInMB     :
+        type            : Number
+        default         : 1024
       diskSizeInMB      :
         type            : Number
         default         : 1200
+      numCPUs           :
+        type            : Number
+        default         : 1

   suspend: (callback)->
     @update { $set: { hostKite: '(banned)' } }, (err)=>
@@ -206,8 +214,51 @@
         return {groupSlug, prefix, nickname, uid, type:'user', alias}
     return null

-
-  @createVmByNonce
+  vmProductMap =
+    "f34ba4e35041fea7e519dc20a96d3e1b": { core  : 1 }
+    "04d5a80edbde8c2b4be2c4fc0da4d527": { ram   : 1024 }
+    "7029c74b6f16ed328cd1c41a454c02f3": { disk  : 1200 }
+
+  @createVmByNonce = secure (client, nonce, callback) ->
+    JPaymentFulfillmentNonce  = require './payment/nonce'
+    JPaymentPack              = require './payment/pack'
+
+    JPaymentFulfillmentNonce.one { nonce }, (err, nonceObject) =>
+      return callback err  if err
+      return { message: "Unrecognized nonce!", nonce }  unless nonceObject
+
+      { planCode } = nonceObject
+
+      JPaymentPack.one { planCode }, (err, pack) =>
+        return callback err  if err
+
+        pack.fetchProducts (err, products) =>
+          return callback err  if err
+
+          { delegate: account } = client.connection
+          { group: groupSlug } = client.context
+
+          attributes = products
+            .map (product) ->
+              vmProductMap[product.planCode]
+            .reduce( (memo, attr) ->
+              memo[key] = val  for own key, val of attr
+              memo
+            , {})
+
+          @createVm {
+            account
+            groupSlug
+            planCode
+            type          : 'user'
+            maxMemoryInMB : attributes.ram
+            diskSizeInMB  : attributes.disk
+            numCPUs       : attributes.core
+          }, (err, vm) ->
+            return callback err  if err
+
+            callback null, vm
+
   # TODO: this needs to be rethought in terms of bundles, as per the
   # discussion between Devrim, Chris T. and Badahir  C.T.
   @createVm = ({account, type, groupSlug, usage, planCode}, callback)->


bubble up defaults like other models

bubble up defaults like other models

--- bokehjs/src/coffee/common/tool_events.coffee
+++ bokehjs/src/coffee/common/tool_events.coffee
@@ -1,3 +1,4 @@
+_ = require "underscore"
 HasProperties = require "./has_properties"
 {logger} = require "./logging"

@@ -5,10 +6,8 @@
   type: 'ToolEvents'

   defaults: () ->
-    return {
+    return _.extend {}, super(), {
       geometries: []
-      name: null
-      tags: []
     }

 module.exports =


Trying to work around ko.dependencyDetection not being published

--- src/knockback-core/knockback-core.coffee
+++ src/knockback-core/knockback-core.coffee
@@ -236,6 +236,11 @@
   observable[fn] = kb._.bind(instance[fn], instance) for fn in methods
   return

+# republish minified
+_republishBySignature = (obj, name, methods) ->
+  return obj[name] = value for key, value of obj when _.all(methods, (method) -> not _.isUndefined(value[method]))
+console.log "ko.dependencyDetection", ko.dependencyDetection, _republishBySignature(ko, 'dependencyDetection', ['begin', 'end', 'registerDependency']), ko.dependencyDetection
+
 # From Backbone.js (https:github.com/documentcloud/backbone)
 copyProps = (dest, source) ->
   (dest[key] = value) for key, value of source


Changed some variable names to bring coffeescript more into alignment with description of semantics in 'Big-step Semantics' paper.

--- src/main/coffeescript/scxml/SCXML.coffee
+++ src/main/coffeescript/scxml/SCXML.coffee
@@ -320,46 +320,46 @@
 			eventNames = (event.name for event in eventSet.iter())

 			#debugger
-			allTransitions = new @opts.TransitionSet
+			enabledTransitions = new @opts.TransitionSet
 			for state in states
 				for t in @opts.transitionSelector state,eventNames,e
-					allTransitions.add t
+					enabledTransitions.add t

 			if @opts.printTrace then console.debug("allTransitionsForEachState",allTransitionsForEachState)
-			consistentTransitions = @_makeTransitionsConsistent allTransitions
-			if @opts.printTrace then console.debug("consistentTransitions",consistentTransitions)
-			return consistentTransitions
-
-		_makeTransitionsConsistent: (transitions) ->
-			consistentTransitions = new @opts.TransitionSet()
-
-			[transitionsNotInConflict, transitionsPairsInConflict] = @_getTransitionsInConflict transitions
-			consistentTransitions.union transitionsNotInConflict
-
-			if @opts.printTrace then console.debug "transitions",transitions
-			if @opts.printTrace then console.debug "transitionsNotInConflict",transitionsNotInConflict
-			if @opts.printTrace then console.debug "transitionsPairsInConflict",transitionsPairsInConflict
+			priorityEnabledTransitions = @_selectPriorityEnabledTransitions enabledTransitions
+			if @opts.printTrace then console.debug("priorityEnabledTransitions",priorityEnabledTransitions)
+			return priorityEnabledTransitions
+
+		_selectPriorityEnabledTransitions: (enabledTransitions) ->
+			priorityEnabledTransitions = new @opts.TransitionSet()
+
+			[consistentTransitions, inconsistentTransitionsPairs] = @_getInconsistentTransitions enabledTransitions
+			priorityEnabledTransitions.union consistentTransitions
+
+			if @opts.printTrace then console.debug "enabledTransitions",enabledTransitions
 			if @opts.printTrace then console.debug "consistentTransitions",consistentTransitions
-
-			while not transitionsPairsInConflict.isEmpty()
-
-				transitions = new @opts.TransitionSet(@opts.priorityComparisonFn t for t in transitionsPairsInConflict.iter())
-
-				[transitionsNotInConflict, transitionsPairsInConflict] = @_getTransitionsInConflict transitions
-
-				consistentTransitions.union transitionsNotInConflict
-
-				if @opts.printTrace then console.debug "transitions",transitions
-				if @opts.printTrace then console.debug "transitionsNotInConflict",transitionsNotInConflict
-				if @opts.printTrace then console.debug "transitionsPairsInConflict",transitionsPairsInConflict
+			if @opts.printTrace then console.debug "inconsistentTransitionsPairs",inconsistentTransitionsPairs
+			if @opts.printTrace then console.debug "priorityEnabledTransitions",priorityEnabledTransitions
+
+			while not inconsistentTransitionsPairs.isEmpty()
+
+				enabledTransitions = new @opts.TransitionSet(@opts.priorityComparisonFn t for t in inconsistentTransitionsPairs.iter())
+
+				[consistentTransitions, inconsistentTransitionsPairs] = @_getInconsistentTransitions enabledTransitions
+
+				priorityEnabledTransitions.union consistentTransitions
+
+				if @opts.printTrace then console.debug "enabledTransitions",enabledTransitions
 				if @opts.printTrace then console.debug "consistentTransitions",consistentTransitions
-
-			return consistentTransitions
+				if @opts.printTrace then console.debug "inconsistentTransitionsPairs",inconsistentTransitionsPairs
+				if @opts.printTrace then console.debug "priorityEnabledTransitions",priorityEnabledTransitions
+
+			return priorityEnabledTransitions

-		_getTransitionsInConflict: (transitions) ->
-
-			allTransitionsInConflict = new @opts.TransitionSet()
-			transitionsPairsInConflict = new @opts.TransitionPairSet() 	#set of tuples
+		_getInconsistentTransitions: (transitions) ->
+
+			allInconsistentTransitions = new @opts.TransitionSet()
+			inconsistentTransitionsPairs = new @opts.TransitionPairSet() 	#set of tuples

 			#better to use iterators, because not sure how to encode "order doesn't matter" to list comprehension
 			transitionList = transitions.iter()
@@ -371,13 +371,13 @@
 					t2 = transitionList[j]

 					if @_conflicts(t1,t2)
-						allTransitionsInConflict.add t1
-						allTransitionsInConflict.add t2
-						transitionsPairsInConflict.add [t1,t2]
-
-			transitionsNotInConflict = transitions.difference allTransitionsInConflict
-
-			return [transitionsNotInConflict,transitionsPairsInConflict]
+						allInconsistentTransitions.add t1
+						allInconsistentTransitions.add t2
+						inconsistentTransitionsPairs.add [t1,t2]
+
+			consistentTransitions = transitions.difference allInconsistentTransitions
+
+			return [consistentTransitions,inconsistentTransitionsPairs]

 		#this would be parameterizable


Prevent error in dev/testing when there's only single build

Recent transformer update of nullifying empty array sometimes causes error in testing.

--- resources/assets/coffee/react/changelog-build/main.coffee
+++ resources/assets/coffee/react/changelog-build/main.coffee
@@ -36,7 +36,7 @@

             div className: 'page-nav',
               div className: 'page-nav__item page-nav__item--left',
-                if @props.build.versions.previous?
+                if @props.build.versions?.previous?
                   a
                     href: _exported.OsuUrlHelper.changelogBuild @props.build.versions.previous
                     i className: 'fas fa-chevron-left'
@@ -44,7 +44,7 @@
                       @props.build.versions.previous.display_version

               div className: 'page-nav__item page-nav__item--right',
-                if @props.build.versions.next?
+                if @props.build.versions?.next?
                   a
                     href: _exported.OsuUrlHelper.changelogBuild @props.build.versions.next
                     @props.build.versions.next.display_version


prevent crash on event creation

prevent crash on event creation

--- client/app/views/popover_screens/main.coffee
+++ client/app/views/popover_screens/main.coffee
@@ -374,8 +374,8 @@
     # Display confirmation modal for sending emails invitation to attendees
     confirmEmailInvitations: (model, callback) ->
         invitationsShouldBeSent = model.isNew() or
-                                    model.startDateChanged() or
-                                        model.attendeesChanged()
+                                    model.startDateChanged or
+                                        model.attendeesChanged
         if not invitationsShouldBeSent
             callback null, false
             return
@@ -386,7 +386,7 @@
             return not guest.isSharedWithCozy and
                 (model.isNew() or
                     guest.status is not 'ACCEPTED' or
-                        model.startDateChanged())
+                        model.startDateChanged)

         if guestsToInform.length
             guestsList = guestsToInform.map((guest) -> guest.label).join ', '
@@ -515,4 +515,3 @@
             .add endOffset, 'd'
             .format tFormat
         @$('.input-end-time').timepicker('setTime', newValue)
-


debug

debug

--- src/scripts/githooks/coreos_restart/coreos_restart.coffee
+++ src/scripts/githooks/coreos_restart/coreos_restart.coffee
@@ -61,11 +61,13 @@
     {config} = services[service]

     # Render Service File
+    console.log config
     config.template = "#{service}.service.template"
     config.output = "#{service}.service"
     yield render_template config

     # Render Dockerfile
+    console.log config
     config.template = "Dockerfile.template"
     config.output = "Dockerfile"
     yield render_template config
@@ -89,19 +91,17 @@
     # Wipe away the scratch space used by hook server.
     command = "/usr/bin/ssh -A -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null " +
               "-p #{port} #{address} sudo rm -rf prelaunch/#{service}"
-    console.log command
-    console.log yield shell command
+    yield shell command

     # Copy the service files to the scratch space on the cluster
     command = "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null " +
               "-P #{port} -r #{app.path}/launch/#{service} " +
               "#{address}:/home/core/prelaunch/"
-    console.log command
-    console.log yield shell command
+    yield shell command

     # Use fleetctl to start the services.  Point it at the service files in the scratch space.
     console.log "Spinning Up #{service}"
     command = "/usr/bin/ssh -A -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null " +
               "-p #{port} #{address} " +
               "/usr/bin/fleetctl start prelaunch/#{service}/#{service}.service"
-    console.log yield shell command
+    yield shell command


Fix running android build on NVM

Fix running android build on NVM

--- cli/tasks/build/server/bundle/android.coffee
+++ cli/tasks/build/server/bundle/android.coffee
@@ -61,9 +61,6 @@
         fs.removeSync OUT_DIR
     fs.copySync RUNTIME_PATH, OUT_DIR,
         filter: (path) ->
-            # omit hidden files
-            if /\/\./i.test(path)
-                return false
             # process mustache files later
             if /\.mustache$/.test(path)
                 mustacheFiles.push path


payment : after convertin user to account route him to finish registration

--- client/Main/payment/paymentcontroller.coffee
+++ client/Main/payment/paymentcontroller.coffee
@@ -152,16 +152,11 @@
         else if createAccount
           { cardFirstName: firstName, cardLastName: lastName } = billing
           { JUser } = KD.remote.api
-
-          me = KD.whoami()
-          me.once "tokenCreated", (token) ->
-            storageController = KD.singletons.appStorageController
-            paymentApp = storageController.storage "PaymentDetails", "1.0"
-            paymentApp.setValue "UserToken", token
-
-          JUser.convert { firstName, lastName, email }, (err) ->
+          JUser.convert { firstName, lastName, email }, (err, newToken, recoveryToken) ->
             JUser.logout ->
+              window.location.href = "/Register/#{encodeURIComponent(recoveryToken)}"
               KD.singletons.dock.getView().show()
+
       .enter()

     workflow


MessagePane: Add defensive checks

MessagePane: Add defensive checks

--- client/activity/lib/views/messagepane.coffee
+++ client/activity/lib/views/messagepane.coffee
@@ -339,7 +339,10 @@
     {id, typeConstant, name} = @getData()

     app  = appManager.get 'Activity'
-    item = app.getView().sidebar.selectedItem
+
+    # TODO: Add defensive checks here because `Teams` doesn't use old sidebar.
+    # So we have to give support to old codes.
+    item = app.getView()?.sidebar?.selectedItem

     return  unless item?.count


payments: shorter, and DRY

payments: shorter, and DRY

--- client/app/MainApp/payment/buyvmmodal.coffee
+++ client/app/MainApp/payment/buyvmmodal.coffee
@@ -137,7 +137,7 @@
   preparePaymentMethods: (formData) ->
     @setState 'billing choice'

-    paymentField = @paymentMethodChoiceForm.fields['Payment method']
+    paymentField = @choiceForm.fields['Payment method']

     paymentController = KD.getSingleton 'paymentController'

@@ -152,15 +152,16 @@

           @setState 'billing entry'

-        when 1
-
-          paymentField.addSubView new BillingMethodView {}, methods[0]
-          @paymentMethodChoiceForm.addCustomData 'accountCode', methods[0].accountCode
+        when 1 then do ([method] = methods) =>
+
+          paymentField.addSubView new BillingMethodView {}, method
+
+          @choiceForm.addCustomData 'accountCode', method.accountCode

         else

           paymentField.addSubView new KDSelectBox
-            defaultValue  : preferredAccountCode ? methods[0].billing.accountCode
+            defaultValue  : preferredAccountCode ? methods[0].accountCode
             name          : 'accountCode'
             selectOptions : methods.map (method) ->
               title       : KD.utils.getPaymentMethodTitle method
@@ -174,7 +175,7 @@

   getAggregatedData: -> @aggregatedData

-  createPaymentMethodChoiceForm:->
+  createChoiceForm:->
     form = new KDFormViewWithFields
       callback              : (formData) =>
         @addAggregateData formData
@@ -200,29 +201,38 @@
           callback          : =>
             @setState 'billing entry'

-  createPaymentMethodEntryForm: ->
+  createEntryForm: ->

     form = new BillingForm

     paymentController = KD.getSingleton 'paymentController'
-    paymentController.observePaymentSave form, (err, { accountCode }) =>
+
+    paymentController.observePaymentSave form, (err, billingInfo) =>
+
+      { accountCode } = billingInfo
+
       @addAggregateData { accountCode }
-      @setState 'confirm'
+      @setState 'confirm', billingInfo

     form

-  hideAllForms: ->
-    @vmTypeForm.hide()
-    @paymentMethodChoiceForm.hide()
-    @paymentMethodEntryForm.hide()
-    @confirmForm.hide()
+  getFormNames: ->
+    [
+      'vmTypeForm'
+      'choiceForm'
+      'entryForm'
+      'confirmForm'
+    ]
+
+  hideForms: (forms = @getFormNames()) ->
+    @[form].hide() for form in forms

   setState: (state) ->
-    @hideAllForms()
+    @hideForms()
     switch state
       when 'vm type'          then @vmTypeForm.show()
-      when 'billing choice'   then @paymentMethodChoiceForm.show()
-      when 'billing entry'    then @paymentMethodEntryForm.show()
+      when 'billing choice'   then @choiceForm.show()
+      when 'billing entry'    then @entryForm.show()
       when 'confirm'
         @confirmForm.setData @getAggregatedData()
         @confirmForm.show()
@@ -235,11 +245,11 @@
     @vmTypeForm = @createVmTypeForm()
     @addSubView @vmTypeForm

-    @paymentMethodChoiceForm = @createPaymentMethodChoiceForm()
-    @addSubView @paymentMethodChoiceForm
-
-    @paymentMethodEntryForm = @createPaymentMethodEntryForm()
-    @addSubView @paymentMethodEntryForm
+    @choiceForm = @createChoiceForm()
+    @addSubView @choiceForm
+
+    @entryForm = @createEntryForm()
+    @addSubView @entryForm

     @confirmForm = @createConfirmForm()
     @addSubView @confirmForm


activity: fix channel participant bugs in activity

--- client/app/lib/notificationcontroller.coffee
+++ client/app/lib/notificationcontroller.coffee
@@ -55,10 +55,12 @@

         return unless contents

+        event = if contents.event then contents.event else event
+
         event = unless context is getGroup().slug then "#{event}-off-context" else event

         # event is mainly -> ChannelUpdateHappened // do not delete this line. here for search purposes. - SY
-        @emit contents.event, contents  if contents.event
+        @emit event, contents  if event

   setListeners:->


Change parameter name with a more meaningful one

--- client/ide/lib/views/chat/idechatview.coffee
+++ client/ide/lib/views/chat/idechatview.coffee
@@ -74,14 +74,14 @@
     @chatPane.setAvatarTalkingState nickname, state

-  handleVideoParticipantJoined: (nickname) ->
-
-    @chatPane.handleVideoParticipantJoined nickname
-
-
-  handleVideoParticipantLeft: (nickname) ->
-
-    @chatPane.handleVideoParticipantLeft nickname
+  handleVideoParticipantJoined: (participant) ->
+
+    @chatPane.handleVideoParticipantJoined participant
+
+
+  handleVideoParticipantLeft: (participant) ->
+
+    @chatPane.handleVideoParticipantLeft participant

   start: ->


components: ListenProperty: simplify callback code

--- components/ListenProperty.coffee
+++ components/ListenProperty.coffee
@@ -1,5 +1,4 @@
 noflo = require 'noflo'
-Lang = imports.lang

 class ListenProperty extends noflo.Component
   description: 'Listen to a signal on a given object'
@@ -38,7 +37,7 @@
     @disconnectListener()
     @object = object
     @property = property
-    @listener = @object.connect "notify::#{@property}", Lang.bind @, () =>
+    @listener = @object.connect "notify::#{@property}", () =>
       @sendOutputs()
     @sendOutputs() if @readback


fix job status for old job process lists

--- server/job.coffee
+++ server/job.coffee
@@ -608,6 +608,10 @@
   job_job.each 'NOT done:true', {_source:['count','processed']}, (j) ->
     console.log j
     console.log (j.count - (j.processed ? 0))
+    if typeof j.processed isnt 'number'
+      j.processed = j.processed.length
+      res.fixprocessed ?= 0
+      res.fixprocessed += 1
     res.jobs.waiting += (j.count - (j.processed ? 0))
     console.log res.jobs.waiting
   return res


Remove stray log

Remove stray log

--- services/web/app/coffee/infrastructure/GeoIpLookup.coffee
+++ services/web/app/coffee/infrastructure/GeoIpLookup.coffee
@@ -31,7 +31,6 @@
 			e = new Error("no ip passed")
 			return callback(e)
 		ip = ip.trim().split(" ")[0]
-		console.log ">> ", URL.resolve(settings.apis.geoIpLookup.url,ip)
 		opts =
 			url: URL.resolve(settings.apis.geoIpLookup.url,ip)
 			timeout: 1000


Track opening dialogs

Track opening dialogs

--- site/index.coffee
+++ site/index.coffee
@@ -114,8 +114,14 @@
 ]

 # Hook up the logic to show and hide the modal dialogs.
-$("a#about").click -> $("#about-dialog").toggle()
-$("a#feedback").click -> $("#feedback-dialog").toggle()
+$("a#about").click ->
+  if not $("#about-dialog").is ":visible"
+    mpq.track "Opened About Dialog"
+  $("#about-dialog").toggle()
+$("a#feedback").click ->
+  if not $("#feedback-dialog").is ":visible"
+    mpq.track "Opened Feedback Dialog"
+  $("#feedback-dialog").toggle()
 $(".close").click -> $(this).parent().parent().hide()

 # Hook up the logic to show the dropdown layers list.


Update the tests as well

Update the tests as well

--- spec/javascripts/unit/admin/line_items/controllers/line_items_controller_spec.js.coffee
+++ spec/javascripts/unit/admin/line_items/controllers/line_items_controller_spec.js.coffee
@@ -261,24 +261,24 @@
           scope.formattedValueWithUnitName(1,unitsProduct,unitsVariant)
           expect(Math.round).toHaveBeenCalled()

-        it "calls Math.round with the quotient of scale and value, multiplied by 1000", ->
+        it "calls Math.round with the value multiplied by 1000", ->
           unitsProduct = { variant_unit: "weight" }
           spyOn(VariantUnitManager, "getScale").and.returnValue 5
           scope.formattedValueWithUnitName(10, unitsProduct,unitsVariant)
-          expect(Math.round).toHaveBeenCalledWith 10/5 * 1000
+          expect(Math.round).toHaveBeenCalledWith 10 * 1000

         it "returns the result of Math.round divided by 1000, followed by the result of getUnitName", ->
           unitsProduct = { variant_unit: "weight" }
           spyOn(VariantUnitManager, "getScale").and.returnValue 1000
           spyOn(VariantUnitManager, "getUnitName").and.returnValue "kg"
-          expect(scope.formattedValueWithUnitName(2000,unitsProduct,unitsVariant)).toEqual "2 kg"
+          expect(scope.formattedValueWithUnitName(2,unitsProduct,unitsVariant)).toEqual "2 kg"

         it "handle correclty the imperial units", ->
           unitsProduct = { variant_unit: "weight" }
           unitsVariant = { unit_value: "453.6" }
           spyOn(VariantUnitManager, "getScale").and.returnValue 1000
           spyOn(VariantUnitManager, "getUnitName").and.returnValue "lb"
-          expect(scope.formattedValueWithUnitName(2000, unitsProduct, unitsVariant)).toEqual "2 lb"
+          expect(scope.formattedValueWithUnitName(2, unitsProduct, unitsVariant)).toEqual "2 lb"

       describe "updating the price upon updating the weight of a line item", ->


Teamwork: Implemented team up option for dashboard.

--- client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkdashboard.coffee
+++ client/landing/app/Applications/Teamwork.kdapplication/Views/teamworkdashboard.coffee
@@ -9,7 +9,10 @@
     @teamUpButton = new KDButtonView
       title       : "Team Up!"
       cssClass    : "tw-teamup-button"
-      callback    : ->
+      callback    : =>
+        delegate  = @getDelegate()
+        delegate.emit "NewSessionRequested", ->
+          delegate.emit "TeamUpRequested"

     @joinInput    = new KDHitEnterInputView
       cssClass    : "tw-dashboard-input"


fix typo that is causing contributors page to be incorrect

--- src/node_modules/round-model/round-model.coffee
+++ src/node_modules/round-model/round-model.coffee
@@ -177,7 +177,7 @@
           if not contributor.contribution
             contributor.contribution = contribution.amount
           else
-            contribution.contribution = contributor.contribution.plus(contribution.amount)
+            contributor.contribution = contributor.contribution.plus(contribution.amount)

       contributors


ActivityAppView: Cleared activity counter when clicked to show new activities button on list header.

--- client/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
+++ client/app/Applications/Activity.kdapplication/views/activitylistheader.coffee
@@ -17,9 +17,7 @@
     @showNewItemsLink = new KDCustomHTMLView
       cssClass    : "new-updates"
       partial     : "0 new items. Update"
-      click       : =>
-        @updateShowNewItemsLink yes
-        mainController.emit "ShouldResetNavigationTitleLink"
+      click       : => @updateShowNewItemsLink yes

     @headerTitle = new KDCustomHTMLView
       partial     : "Latest Activity"


Revert "intentionally failed the konacha test"

This reverts commit 29026a7bbfb69445453e3ba7f5fb2c80c997c7f7.

--- core/spec/javascripts-konacha/views/conversations/start_conversation_view_spec.coffee
+++ core/spec/javascripts-konacha/views/conversations/start_conversation_view_spec.coffee
@@ -6,4 +6,4 @@
     view = new window.StartConversationView
     view.render()
     content = view.$('.js-message-textarea').val()
-    content.should.equal "Check out this Henk!"
+    content.should.equal "Check out this Factlink!"


String to Object In Store

String to Object In Store

--- scripts/amazon-ec.coffee
+++ scripts/amazon-ec.coffee
@@ -4,6 +4,9 @@
 # Commands:
 #   hubot kindle最新刊探して <title> - kindle 版の最新刊を検索して表示
 #   hubot comic最新刊探して <title> - コミック(kindle除く)版の最新刊を検索して表示
+#   hubot kindle登録して <title> - kindle 版の最新刊を探す条件を保存する
+#   hubot comic登録して <title> - comic 版の最新刊を探す条件を保存する
+#   hubot 登録内容教えて - 登録内容を表示する
 #
 # Author:
 #   aha-oretama <sekine_y_529@msn.com>
@@ -85,19 +88,18 @@
     newReleaseSearch msg, msg.match[2], false

   robot.respond /kindle登録(\S*) (\S+)$/i, (msg) ->
+    message = msg.match[2]
+    originalArray = robot.brain.get(msg.envelope.user.name) ? []
+
     # 重複を除く
-    original = robot.brain.get(msg.envelope.user.name)
-    originalArray = if original then original.split(',') else []
-    originalArray.push(msg.match[2])
-    message = _.uniq(originalArray).join(",")
+    if !originalArray.filter((item) -> item.title is message).length
+      originalArray.push({title: message, kindle: true})

     # 保存
-    robot.brain.set msg.envelope.user.name, message
+    robot.brain.set msg.envelope.user.name, originalArray
     robot.brain.save()
-    msg.send message
-
-    for query in originalArray
-      newReleaseSearch msg, query, true
+    for obj in originalArray
+      msg.send obj.title

   robot.respond /登録内容(\S*)/i, (msg) ->
     # 呼び出し


last tweak

last tweak

--- scripts/apologize.coffee
+++ scripts/apologize.coffee
@@ -20,7 +20,7 @@
     robot.send "I'm sorry :( I'll try better next time!"

   apologizeTo = (robot) ->
-    robot.send "I'm sorry @#{robot.match[1]}"
+    robot.send "I'm sorry #{robot.match[1]}"

   robot.respond /apologize to (@?.+)/i, apologizeTo
   robot.respond /apologize/i, apologize


fix for message sending in profile page

fix for message sending in profile page

--- client/landing/app/Applications/Members.kdapplication/ContentDisplays/contactlink.coffee
+++ client/landing/app/Applications/Members.kdapplication/ContentDisplays/contactlink.coffee
@@ -33,6 +33,8 @@
         navigable             : yes
         callback              : (formOutput)=>
           callback = modal.destroy.bind modal
+          [{profile: {nickname}}] = recipient.selectedItemData
+          formOutput.recipients = [nickname]
           @emit "MessageShouldBeSent", {formOutput, callback}
         forms                 :
           sendForm            :


Added a simple print function - references #3

--- lib/funl.coffee
+++ lib/funl.coffee
@@ -41,6 +41,10 @@
     left = arr.get(0)
     right = arr.get(1)
     left.divide(right)
+
+  "print": new Type.Function (arg) ->
+    console.log(arg.toJS())
+    arg

 handlers =
   program: (ast, env) ->


contestant msg

contestant msg

--- scripts/contestant-msg.coffee
+++ scripts/contestant-msg.coffee
@@ -16,7 +16,7 @@
   currentTeam.people (err, people) ->
     return callback(err) if err
     emailable = (person for person in people when /@/.test(person.email))
-    util.log "Sending 'contestant_pre_1week' to '#{team.name}'".yellow
+    util.log "Sending 'contestant_pre_2days' to '#{team.name}'".yellow
     async.forEach emailable, msgPerson, callback

 msgPerson = (person, callback) ->


Updated the support command help messages.

--- scripts/merlin-support.coffee
+++ scripts/merlin-support.coffee
@@ -1,6 +1,7 @@
 # Track Merlin support person
 #
-# support is <person> <phone>  - tell bot who is doing support
+# <person> has support this sprint - tell lefay who is doing support
+# support can be reach at <phone number> - tell lefay how the support person can be reached
 # who is support?              - find out who is covering merlin support

 whoHasSupport = (robot) ->


Log errors on exit, log stderr in console

--- lib/ghci.coffee
+++ lib/ghci.coffee
@@ -65,9 +65,13 @@
             @responseBuffer = []
             @emitter.emit 'finished', rxres[1]
         stderr: (output) =>
+          output.split(EOL).forEach (line) ->
+            console.warn "ide-haskell-repl: #{line}"
           @errorBuffer.push output.split(EOL).slice(0, -1)...
         exit: (code) =>
           @ghci = null
+          if code isnt 0
+            @emitter.emit 'error', @errorBuffer.join(EOL) + EOL
           @emitter.emit 'exit', code

       @process.onWillThrowError ({error, handle}) ->


Add FAILED action

Add FAILED action

--- src/flux/course-listing.coffee
+++ src/flux/course-listing.coffee
@@ -12,6 +12,7 @@
   'load'
   'loaded'
   'reset'
+  'FAILED'
 ]

 CourseListingStore = flux.createStore


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


remove unused dryRun option

remove unused dryRun option

Co-Authored-By: Jakob Ackermann <caa3e4f01d56b797520cbfed54bdab4c5e3b0ebb@outlook.com>

--- services/document-updater/app/coffee/HttpController.coffee
+++ services/document-updater/app/coffee/HttpController.coffee
@@ -219,7 +219,6 @@
 		options =
 			limit : req.query.limit || 1000
 			timeout: 5 * 60 * 1000
-			dryRun : req.query.dryRun || false
 			min_delete_age: req.query.min_delete_age || 5 * 60 * 1000
 		res.send 204
 		# run the flush in the background


console monospace

console monospace

as suggested by @codyhazelwood in #128

--- lib/Components/ConsolePane.coffee
+++ lib/Components/ConsolePane.coffee
@@ -131,6 +131,7 @@
         style: {
           flex: '1'
           overflow: 'auto'
+          "font-family": "Menlo, Consolas, 'DejaVu Sans Mono', monospace"
         }
       }, state.lines.map(tokenizeLine))
       h('div.debugger-editor', style: {


use generateCreateTeamParams with callback

--- servers/lib/server/handlers/getteam.test.coffee
+++ servers/lib/server/handlers/getteam.test.coffee
@@ -44,15 +44,15 @@
     methods                   = ['post', 'get', 'put', 'patch']
     groupSlug                 = generateRandomString()

-    createTeamRequestParams   = generateCreateTeamRequestParams
-      body    :
-        slug  : groupSlug
+    queue.push ->
+      generateCreateTeamRequestParams {
+        body : { slug : groupSlug }
+      }, (createTeamRequestParams) ->

-    queue.push ->
-      request.post createTeamRequestParams, (err, res, body) ->
-        expect(err)             .to.not.exist
-        expect(res.statusCode)  .to.be.equal 200
-        queue.next()
+        request.post createTeamRequestParams, (err, res, body) ->
+          expect(err)             .to.not.exist
+          expect(res.statusCode)  .to.be.equal 200
+          queue.next()

     methods.forEach (method) ->
       getTeamRequestParams = generateGetTeamRequestParams { method, groupSlug }


use secret session secret

use secret session secret

--- server/code/index.coffee
+++ server/code/index.coffee
@@ -36,8 +36,11 @@

 app.configure ->
   app.use express.bodyParser()
-  app.use express.cookieParser('SECRET')
-  app.use express.session({ cookie: { maxAge: 60000 }, secret: 'SECRET'})
+  app.use express.cookieParser( process.env.CU_SESSION_SECRET )
+  app.use express.session
+    cookie:
+      maxAge: 60000 * 60 * 24
+    secret: process.env.CU_SESSION_SECRET

   app.use passport.initialize()
   app.use passport.session()


Log mailchimp for debugging

Log mailchimp for debugging

--- server/code/model/user.coffee
+++ server/code/model/user.coffee
@@ -191,6 +191,7 @@

     if opts.newUser?.emailMarketing
       try
+        console.log "mailchimp.MailChimpAPI =", mailchimp.MailChimpAPI
         api = new mailchimp.MailChimpAPI process.env.CU_MAILCHIMP_API_KEY,
           version: '1.3'
           secure: false


Pre-merge clean up

Pre-merge clean up

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,57 +1,49 @@
+# HACK
+# Always (and only) execute in dev-mode.
+# This means that after updating any of the grammar fixtures, the package has to be reloaded in dev-mode at least once to regenerate the grammar files.
 if atom.inDevMode()

   CSON = require 'season'
   path = require 'path'

   module.exports =
+
     data: null
     version: null
     input: '../grammars/fixtures/fenced-code.cson'
     output: '../grammars/fenced-code.compiled.cson'

     activate: ->
-      # HACK Always (and only) execute in dev-mode. This means that after updating the fixtures list, the package has to be reloaded at least once to regenerate the fenced-code-blocks grammar.
-      if @loadFixture()
-        @updateGrammar()
-
-      # unless @grammarIsUpToDate()
-      #   if @loadFixture()
-      #     @updateGrammar()
-
-    # NOTE disabled, because we temporarily don't rely on this method of updating
-    # grammarIsUpToDate: ->
-    #   filepath = path.join(__dirname, @output)
-    #   @outputVersion = CSON.readFileSync(filepath).version
-    #   @inputVersion = atom.packages.loadedPackages["language-markdown"].metadata.version
-    #   return @inputVersion >= @outputVersion
+      @updateGrammar()

     loadFixture: ->
       filepath = path.join(__dirname, @input)
       @data = CSON.readFileSync(filepath)

     updateGrammar: ->
-      grammar =
-        version: @inputVersion
-        name: @data.name
-        scopeName: @data.scopeName
-        patterns: @createPatternsFromData()
-        repository:
-          'fenced-code-info':
-            patterns: [
-              {
-                match: '([^ ]+)(=)([^ ]+)'
-                name: 'info.fenced.code.md'
-                captures:
-                  1: name: 'key.keyword.md'
-                  2: name: 'punctuation.md'
-                  3: name: 'value.string.md'
-              }
-            ]
+      if @loadFixture()

-      filepath = path.join(__dirname, @output)
-      CSON.writeFileSync filepath, grammar, do ->
-        # console.log "language-markdown: Grammar for fenced-blocks updated to #{@inputVersion}"
-        console.log "language-markdown: Grammar for fenced-blocks updated via dev-mode"
+        grammar =
+          version: @inputVersion
+          name: @data.name
+          scopeName: @data.scopeName
+          patterns: @createPatternsFromData()
+          repository:
+            'fenced-code-info':
+              patterns: [
+                {
+                  match: '([^ ]+)(=)([^ ]+)'
+                  name: 'info.fenced.code.md'
+                  captures:
+                    1: name: 'key.keyword.md'
+                    2: name: 'punctuation.md'
+                    3: name: 'value.string.md'
+                }
+              ]
+
+        filepath = path.join(__dirname, @output)
+        CSON.writeFileSync filepath, grammar, do ->
+          console.log "language-markdown: Grammar generated for 'fenced-code-blocks'"

     createPatternsFromData: ->
       patterns = []
@@ -74,9 +66,10 @@
           patterns.push pattern
       return patterns

-    # item.pattern is required; return false if omitted
-    # item.include is "source."+item.pattern if omitted
-    # item.contentName is "embedded."+item.include if omitted
+    # NOTE
+    # {item.pattern} is REQUIRED; return false if omitted
+    # if omitted {item.include} = "source."+item.pattern
+    # if omitted {item.contentName} = "embedded."+item.include
     parseItem: (item) ->
       if item.pattern?
         unless item.include then item.include = 'source.'+item.pattern


Give status indicator a priority boost

Give status indicator a priority boost

This will put it inwards of all the standard indicators. This means
the indicators that are always on the status bar will be in
their typical locations whether the deprecation cop indicator is
visible or not.

--- lib/main.coffee
+++ lib/main.coffee
@@ -24,7 +24,7 @@
       @deprecationCopStatusBarView ?= new DeprecationCopStatusBarView()
       workspaceElement = atom.views.getView(atom.workspace)
       statusBar = workspaceElement.querySelector('.status-bar')
-      statusBar?.addRightTile(item: @deprecationCopStatusBarView)
+      statusBar?.addRightTile(item: @deprecationCopStatusBarView, priority: 150)
       activatedDisposable.dispose()

     @commandSubscription = atom.commands.add 'atom-workspace', 'deprecation-cop:view', ->


:bug: Fix missing minimap when a plugin get an instance before the observer

--- lib/main.coffee
+++ lib/main.coffee
@@ -262,8 +262,6 @@
     Minimap ?= require './minimap'

     @subscriptions.add atom.workspace.observeTextEditors (textEditor) =>
-      return if @editorsMinimaps?.get(textEditor)?
-
       minimap = @minimapForEditor(textEditor)

       editorElement = atom.views.getView(textEditor)


:fire: Remove os-specific code from main

--- lib/main.coffee
+++ lib/main.coffee
@@ -1,13 +1,11 @@
 {CompositeDisposable} = require 'atom'
-
 path = require 'path'
-jsHintName = if process.platform is 'win32' then 'jshint.cmd' else 'jshint'

 module.exports =
   config:
     executablePath:
       type: 'string'
-      default: path.join(__dirname, '..', 'node_modules', '.bin', jsHintName)
+      default: path.join(__dirname, 'cli.js')
       description: 'Path of the `jshint` executable.'
     lintInlineJavaScript:
       type: 'boolean'
@@ -43,7 +41,7 @@
         if textEditor.getGrammar().scopeName.indexOf('text.html') isnt -1 and 'source.js.embedded.html' in @scopes
           parameters.push('--extract', 'always')
         parameters.push('-')
-        return helpers.exec(executablePath, parameters, {stdin: text}).then (output) ->
+        return helpers.execNode(executablePath, parameters, {stdin: text}).then (output) ->
           try
             output = JSON.parse(output).result
           catch error


Use atom.packages.onDidActivateAll

Use atom.packages.onDidActivateAll

--- lib/main.coffee
+++ lib/main.coffee
@@ -32,7 +32,7 @@
       'settings-view:uninstall-packages': -> openPanel('Packages')
       'settings-view:check-for-package-updates': -> openPanel('Updates')

-    atom.packages.once('activated', checkForUpdates)
+    atom.packages.onDidActivateAll(checkForUpdates)

 checkForUpdates = ->
   if statusBar = atom.views.getView(atom.workspace)?.querySelector('status-bar')


fix some indentation stuff

fix some indentation stuff

--- lib/main.coffee
+++ lib/main.coffee
@@ -66,15 +66,14 @@
   isHtmlSelfClosing = t[0] == '<' && t[t.length-2] == '/'
   isSelfClosed =  isPlainString || isHtmlSelfClosing || (isMustachey && !isTokenTag)
   currentTag = t.match(/\w+/)[0]
-  unless !isElse && ((isSelfClosed && prevTagIsSelfClosed) || (prevTagIsClosed && !isClosing) || prevTagIsOpening && isClosing && (prevTag == currentTag))
+  unless !isElse && (((isOpening || isSelfClosed) && prevTagIsSelfClosed) || (prevTagIsClosed && !isClosing) || prevTagIsOpening && isClosing && (prevTag == currentTag))
     indent += (if isOpening then 1 else -1)
   prevTag = currentTag
   prevTagIsOpening = isOpening
   prevTagIsClosed = isClosing
   prevTagIsElse = isElse
   prevTagIsSelfClosed = isSelfClosed
-  if indent == 0 then '' else ("  " for n in [0..indent-1]).join('')) + t
-
+  (if indent == 0 then '' else ("  " for n in [0..indent-1]).join('')) + t
 fs.writeFileSync hbsFile, spaced.join("\n")


fix consolePanel visibility

fix consolePanel visibility

--- lib/main.coffee
+++ lib/main.coffee
@@ -126,7 +126,7 @@
       bridleCmd.stderr.on 'data', (data) ->
         hasError = true
         try
-          consolePanel.error(data.toString()) if atom.config.get('language-bridlensis.alwaysShowOutput')
+          consolePanel.error(data.toString())
         catch
           console.error(data.toString())


Fix: don't change locale globally

Fix: don't change locale globally

--- packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee
+++ packages/rocketchat-channel-settings-mail-messages/server/methods/mailMessages.coffee
@@ -23,11 +23,10 @@
 			localeFn = Meteor.call 'loadLocale', data.language
 			if localeFn
 				Function(localeFn)()
-				moment.locale(data.language)

 		html = ""
 		RocketChat.models.Messages.findByRoomIdAndMessageIds(data.rid, data.messages, { sort: { ts: 1 } }).forEach (message) ->
-			dateTime = moment(message.ts).format('L LT')
+			dateTime = moment(message.ts).locale(data.language).format('L LT')
 			html += "
#{message.u.username} #{dateTime}
" + RocketChat.Message.parse(message, data.language) + "
"

 		Meteor.defer ->


update home to use cozy-clients instead of haibu-api

--- lib/paas.coffee
+++ lib/paas.coffee
@@ -1,9 +1,7 @@
-haibu = require('haibu-api')
 fs = require 'fs'
 HttpClient = require("request-json").JsonClient
 MemoryManager = require("./memory").MemoryManager
-controllerUrl = "http://localhost:9002/"
-controllerClient = new HttpClient controllerUrl
+ControllerClient = require("cozy-clients").ControllerClient

 # Class to facilitate communications with Haibu, the application server
@@ -18,59 +16,23 @@
     # Setup controller client and proxyClient.
     constructor: ->
         @proxyClient = new HttpClient "http://localhost:9104/"
-        @controllerClient = new HttpClient "http://localhost:9002/"
+        @client = new ControllerClient
+            token: @getAuthController()
         @memoryManager = new MemoryManager()
-        @client = {}

-        getAuthController = (callback) ->
-            if process.env.NODE_ENV is 'production'
-                fs.readFile '/etc/cozy/controller.token', 'utf8', (err, data) =>
-                    if err isnt null
-                        console.log "Cannot read token"
-                        callback err
-                    else
-                        token = data.split('\n')[0]
-                        callback null, token
-            else
-                callback null, ""
-
-        @client.brunch = (manifest, callback) =>
-            data = brunch: manifest
-            getAuthController (err, token) =>
-                controllerClient.setToken token
-                controllerClient.post "drones/#{manifest.name}/brunch", data, callback
-
-        @client.startApp = (manifest, callback) ->
-            data = start: manifest
-            getAuthController (err, token) =>
-                controllerClient.setToken token
-                controllerClient.post "drones/#{manifest.name}/start", data, callback
-
-        # Send a uninstall request to controller server ("clean" request).
-        @client.uninstallApp = (manifest, callback) ->
-            data = manifest
-            getAuthController (err, token) =>
-                controllerClient.setToken token
-                controllerClient.post "drones/#{manifest.name}/clean", data, callback
-
-        # Send a stop request to controller server
-        @client.stopApp = (manifest, callback) ->
-            data = stop: manifest
-            getAuthController (err, token) =>
-                controllerClient.setToken token
-                controllerClient.post "drones/#{manifest.name}/stop", data, callback
-
-        @client.lightUpdate = (manifest, callback) ->
-            data = update: manifest
-            getAuthController (err, token) =>
-                controllerClient.setToken token
-                controllerClient.post "drones/#{manifest.name}/light-update", data, callback
-
-        @client.updateApp = (manifest, callback) ->
-            data = update: manifest
-            getAuthController (err, token) =>
-                controllerClient.setToken token
-                controllerClient.post "drones/#{manifest.name}/update", data, callback
+    # Get token from token file if in production mode.
+    getAuthController: ->
+        if process.env.NODE_ENV is 'production'
+            try
+                token = fs.readFileSync '/etc/cozy/controller.token', 'utf8'
+                token = token.split('\n')[0]
+                return token
+            catch err
+                console.log err.message
+                console.log err.stack
+                return null
+        else
+            return ""

     checkMemory: (callback) ->
         @memoryManager.isEnoughMemory (err, enoughMemory) =>
@@ -107,10 +69,10 @@
         console.info "with manifest : "
         console.info JSON.stringify manifest

-        @checkMemory (err) ->
+        @checkMemory (err) =>
             return callback err if err

-            @client.startApp manifest, (err, res, body) =>
+            @client.start manifest, (err, res, body) =>

                 err ?= new Error body.error.message unless status2XX res

@@ -143,7 +105,9 @@
         manifest = app.getHaibuDescriptor()
         console.info "Request controller for cleaning #{app.name}..."

-        @client.uninstallApp manifest, (err, res, body) =>
+        console.log @client
+
+        @client.clean manifest, (err, res, body) =>

             err ?= new Error body.error.message unless status2XX res

@@ -161,15 +125,11 @@
         manifest = app.getHaibuDescriptor()
         console.info "Request controller for starting #{app.name}..."

-        @client.stopApp manifest, (err, res, body) =>
-            # ignore stop errors
-
+        @client.stop app.slug, (err, res, body) =>
             @checkMemory (err) ->
-
                 return callback err if err

-                @client.startApp manifest, (err, res, body) =>
-
+                @client.start manifest, (err, res, body) =>
                     err ?= new Error body.error.message unless status2XX res

                     if err
@@ -186,8 +146,7 @@
         manifest = app.getHaibuDescriptor()
         console.info "Request controller for stopping #{app.name}..."

-        @client.stopApp manifest, (err,res, body) =>
-
+        @client.stop app.slug, (err,res, body) =>
             err ?= new Error body.error.message unless status2XX res

             if err


change resource file to .supercolliderrc if not found then guess by platform

--- lib/repl.coffee
+++ lib/repl.coffee
@@ -2,6 +2,8 @@
 Bacon = require('baconjs')
 url = require('url')
 SuperColliderJS = require 'supercolliderjs'
+RcFinder = require('rcfinder')
+os = require('os')

 module.exports =
@@ -56,6 +58,15 @@
     @postWindow.clearPostWindow()

   getPreferences: ->
-    RcFinder = require('rcfinder')
-    prefsFinder = new RcFinder('.supercolliderjs', {})
-    prefsFinder.find(@projectRoot) || {}
+    prefsFinder = new RcFinder('.supercolliderrc', {})
+    opts = prefsFinder.find(@projectRoot)
+    unless opts
+      opts = {}
+      switch os.platform()
+        when 'win32'
+          opts.path = ''
+        when 'darwin'
+          opts.path = "/Applications/SuperCollider/SuperCollider.app/Contents/Resources"
+        else
+          opts.path = '/usr/local/bin'
+    opts


Schedule idle check when entering fullscreen

--- scripts/players.coffee
+++ scripts/players.coffee
@@ -161,6 +161,7 @@
             container.webkitRequestFullScreen() if container.webkitRequestFullScreen?
             container.msRequestFullscreen() if container.msRequestFullscreen?
             container.classList.add('fullscreen')
+            timeout = setTimeout(idleUI, 3000)
         else
             leaveFullscreen()
     , false)


Moving the usage of robot to where it is available

--- scripts/pudding.coffee
+++ scripts/pudding.coffee
@@ -55,12 +55,12 @@
     'c3.8xlarge': 16
   role: default_role

-if !host
-  robot.logger.warning('Missing HUBOT_PUDDING_HOST')
-if !token
-  robot.logger.warning('Missing HUBOT_PUDDING_AUTH_TOKEN')
-
 module.exports = (robot) ->
+  if !host
+    robot.logger.warning('Missing HUBOT_PUDDING_HOST')
+  if !token
+    robot.logger.warning('Missing HUBOT_PUDDING_AUTH_TOKEN')
+
   whitelist_respond robot, /who can do stuff with instances/i, (_, msg) ->
     msg.send "The whitelisted channels are: *#{whitelisted_channels.join("*, *")}*"


Delete wolfram.coffee

Delete wolfram.coffee

--- scripts/wolfram.coffee
+++ scripts/wolfram.coffee
@@ -1,30 +0,0 @@
-# Description:
-#   Allows hubot to answer almost any question by asking Wolfram Alpha
-#
-# Dependencies:
-#   "wolfram": "0.2.2"
-#
-# Configuration:
-#   HUBOT_WOLFRAM_APPID - your AppID
-#
-# Commands:
-#   hubot question <question> - Searches Wolfram Alpha for the answer to the question
-#
-# Author:
-#   dhorrigan
-
-Wolfram = require('wolfram').createClient(process.env.HUBOT_WOLFRAM_APPID)
-
-module.exports = (robot) ->
-  robot.respond /(question|wfa|wolfram) (.*)$/i, (msg) ->
-    #console.log msg.match
-    Wolfram.query msg.match[2], (e, result) ->
-      # console.log result
-      if !result or result.length == 0
-        msg.send 'Hmm...não tenho certeza'
-      else if result[1]['subpods'][0]['value'].length > 0
-        msg.send result[1]['subpods'][0]['value']
-      else if result[1]['subpods'][0]['image'].length > 0
-        msg.send result[1]['subpods'][0]['image']
-      else
-        msg.send 'Hmm...não tenho certeza'


Document test.coffee

Document test.coffee

--- lib/test.coffee
+++ lib/test.coffee
@@ -1,3 +1,14 @@
+# test.coffee
+# ===========
+
+# Running
+# -------
+#
+#     coffee test.coffee -w path_to_worker_file test_file1 test_file2 ...
+
+# The code
+# --------
+
 require 'fibers'
 fs = require 'fs'
 redis = require 'redis'
@@ -27,10 +38,13 @@
 passed = 0
 failed = 0

+# Print a message in verbose mode only
 debug = (args...) ->
   if verbose
     console.log args...

+# A container for other tests, who will inherit any
+# setup or expect blocks.
 describe = (name, body) ->
   clone_context()
   test_name.push name
@@ -38,10 +52,14 @@
   context = stack.pop()
   test_name.pop()

+# Push the current test context to a stack and clone it.
+# This way each test knows the specific, inherited context
+# from whence it was defined.
 clone_context = ->
   stack.push context
   context = deep_clone context

+# Create a deep clone of an object. Works for arrays too.
 deep_clone = (obj) ->
   if _.isArray(obj)
     _.map obj, deep_clone
@@ -53,28 +71,50 @@
   else
     obj

+# Add a 'setup' block to the current test context.
+# Setup blocks run in sequence before running the test
+# expectations.
 setup = (body) ->
   context.setups.push body

+# Define a worker which will be available while the test
+# runs. Has the same syntax as `Manager#worker`.
 worker = (args...) ->
   context.workers.push args

+# A shorthand way of saying that the key requested by the
+# setup block is expected to be equal to this given value.
+# This adds an expectation block, but others can be defined
+# as well.
 want = (value) ->
   context.expects.push -> wanted value

+# Add an expectation block. They will be run after the
+# setup blocks, and after the test's requested key has
+# completed running.
 expect = (body) ->
   context.expects.push body

+# Define a $.key value for the current test context. You can
+# define these in sub-tests in a `describe` block, and when
+# shared `setup` or `expect` blocks (or workers) run, they will
+# use the value set by the currently running test. You can use
+# this to reduce duplicate code in the test.
 has = (hash) ->
   for key, value of hash
     context.lets[key] = value

+# Add a test. The test inherits the current test context,
+# including all parent setup, expect, and workers. Pushes
+# the test onto the global 'test' list.
 test = (name, body) ->
   describe name, ->
     body()
     context.name = test_name.join(' ')
     tests.push context

+# Call this to indicate a test has failed. The test will
+# NOT abort, however; all tests are always run.
 fail = (msg) ->
   msg = msg.stack || msg
   console.log "#{the_test.name}: failed: #{msg}"
@@ -82,11 +122,16 @@
   failed++
   false

+# Call this to indicate a test has passed. Like `fail`, can
+# be called multiple times per test.
 pass = (msg) ->
   debug "#{the_test.name}: passed"
   passed++
   true

+# Pause execution, which also pauses the fiber; returns
+# after the given number of milliseconds. Other event handlers
+# will still be active during this time.
 wait = (time) ->
   setTimeout (->
     debug 'run from wait'
@@ -95,15 +140,33 @@
   debug 'yield from wait'
   yield()

+# Mimics functionality of Manager#pack, for packed-form keys
 pack_fields = (hash, fields) ->
   hash[field] for field in fields

+# Mimics functionality of Manager#unpack, for packed-form keys
 unpack_fields = (array, fields) ->
   hash = {}
   for field, index in fields
     hash[field] = array[index]
   hash

+# Convert an asynchronous operation into a synchronous one.
+# You must use this if you want to do something asynchronous
+# in a test. The async method provides a callback which should
+# be called with two arguments, `err` and `value`. `err` will
+# be thrown from within the fiber, if present. Otherwise, `value`
+# will be the return value of `async`. Like `wait`, other event
+# handlers will be active during this time.
+async = (callback) ->
+  callback (err, value) ->
+    fiber.run [err, value]
+  [err, value] = yield()
+  throw err if err
+  value
+
+# Get a key from the database and return its unpacked value. Commonly
+# would be called from an `expect` block.
 get = (args...) ->
   key = new Buffer(args.join ':')
   prefix = key.toString().split(':')[0]
@@ -118,6 +181,8 @@
   throw err if err
   obj

+# Set a key into the database (after packing it). Commonly would
+# be called from a `setup` block.
 set = (args..., value) ->
   key = args.join ':'
   prefix = key.split(':')[0]
@@ -135,6 +200,12 @@
   throw err if err
   null

+# Given two values are not identical, create a nested
+# diff of the two objects, which can handle both arrays and
+# objects.
+#
+# TODO: this doesn't work right when 'actual' and 'expected'
+#       are not the same type, i.e. object vs string.
 diff_message = (expected, actual, prefix='    ') ->
   if _.isArray expected
     array_diff_message expected, actual, prefix
@@ -143,9 +214,12 @@
   else
     value_diff_message expected, actual, prefix

+# Simplest diff message, for a scalar value difference
 value_diff_message = (expected, actual, prefix='') ->
   "#{prefix}- #{expected}\n#{prefix}+ #{actual}\n"

+# Compare two arrays, indicating which indices are different, and
+# with a nested diff message.
 array_diff_message = (expected, actual, prefix='    ') ->
   len = Math.max(expected.length, actual.length)
   msg = ''
@@ -161,6 +235,8 @@
       msg += "#{prefix}[#{i}] + #{JSON.stringify(b)}\n"
   msg

+# Compare two objects, indicating which properties are different,
+# and with a nested diff message.
 object_diff_message = (expected, actual, prefix='    ') ->
   msg = ''
   for k, a of expected
@@ -174,6 +250,7 @@
       msg += "#{prefix}[#{k}]\n#{prefix}  + #{JSON.stringify(b)}\n"
   msg

+# Format an error message for a particular key.
 error_message = (key, parts) ->
   list = ["Key \"#{key}\" encountered an error"]
   for item in parts
@@ -183,9 +260,13 @@
       list.push "        #{line}"
   list.join("\n") + "\n"

+# Create an error message indicating a key didn't produce
+# a value at all.
 missing_message = (key) ->
   "Key \"#{key}\" resulted in null\n"

+# Redeye keys may produce 'node' information for advanced logging;
+# cull this information before doing comparisons.
 delete_nodes = (val) ->
   if _.isArray val
     for item, i in val
@@ -194,6 +275,7 @@
     delete val.node_id
   val

+# Ultra-simple 'assert' module, only containing `that` and `equal`
 assert =
   that: (bool, msg='nope') ->
     if bool
@@ -206,7 +288,12 @@
     else
       fail(msg + "\n" + diff_message(a, b))

+# Compare two things for equality. Pass or fail the test based
+# on this, and print a recursive diff error. The 'key' argument
+# is optional and defaults to the test's requested key.
 compare = (key, actual, expected) ->
+  if arguments.length == 2
+    [key, actual, expected] = [requested, key, actual]
   if !actual?
     fail missing_message(key)
   else if actual.error
@@ -220,6 +307,9 @@
       msg = msg + diff_message(expected, actual)
       fail msg

+# Determine if two objects are recursively equal to each other.
+# However, for numbers, only assert that the numbers are within
+# a tolerance of 0.0001.
 is_equal = (a, b) ->
   return true if !a && !b
   return false if !a? || !b?
@@ -243,6 +333,8 @@
     return _.isEqual a, b
   true

+# Kick off the tests by connecting to the database, listening for
+# messages, and starting the test-runner fiber.
 start_tests = ->
   db = redis.createClient port, host, detect_buffers: true
   sub = redis.createClient port, host, return_buffers: true
@@ -256,6 +348,8 @@
   debug 'run from start'
   fiber.run()

+# Run the next test in the sequence. If all tests have been run,
+# wrap up and exit.
 run_next_test = ->
   if tests.length
     the_test = tests.shift()
@@ -263,6 +357,9 @@
   else
     finish_tests()

+# Report on what tests passed and failed, then disconnect from
+# the database, kill the test-runner fiber, and exit the process
+# with an appropriate error code.
 finish_tests = ->
   report()
   db.end()
@@ -270,15 +367,22 @@
   fiber = null
   exit()

+# Exit the process. The exit code will be 0 on success, nonzero
+# if any test failed (it will actually equal the number of failed tests)
 exit = ->
   process.exit failed

+# Check if the test even makes any sense - each test needs at least
+# one expectation portion.
 test_is_ok = ->
   if !the_test.expects.length
     fail "does not have any expectations"
   else
     true

+# Run the current test. First apply its context ($) data, then run
+# its setup blocks, then block until the manager finishes the requested
+# key. Finally, run the expect blocks.
 run_test = ->
   requested = null
   if test_is_ok()
@@ -287,12 +391,18 @@
     run_expect()
   run_next_test()

+# Create a wrapper function around a `has foo: -> bar` context,
+# such that the actual 'foo' function is only called once and its
+# value memoized.
 lazy = (fun) ->
   value = undefined
   return ->
     value = fun() if typeof(value) == 'undefined'
     value

+# Add the 'has' declarations from the test to the global '$'
+# context. Any declarations that are functions are wrapped in
+# lazy evaluators.
 add_lets = ->
   $ = {}
   for name, value of the_test.lets
@@ -300,12 +410,19 @@
       value = lazy value
     $[name] = value

+# Add all the test's defined workers to the manager; also, if the
+# -w flag was specified, require that module and initialize it on
+# the manager.
 add_workers = ->
   if argv.w
     require(argv.w).init manager
   for args in the_test.workers
     manager.worker args...

+# Set up the test scenario. create a new manager, apply test workers
+# to it, and start it running. Then run setup blocks, and wait pending
+# the manager to finish the requested key. If no key was requested,
+# continue immediately to the expectation blocks.
 run_setup = ->
   manager = new Manager { verbose, flush: true }
   add_workers()
@@ -319,12 +436,18 @@
     fail err
     manager.quit()
   debug 'yield from run_setup'
-  yield()
-
+  yield() if requested
+
+# Go get a certain key and compare it to the given expected value.
+# If only called with one argument, the key is assumed to be the
+# requested key for the test.
 wanted = (args..., expected) ->
   key = if args.length then args.join(':') else requested
   compare key, get(key), expected

+# Run the expectation blocks for the test; if an error is
+# raised, catch it and just fail the test with the error as
+# a message.
 run_expect = ->
   return if the_test.failed
   try
@@ -332,11 +455,16 @@
   catch err
     fail err

+# Report how many assertions passed and failed.
 report = ->
   console.log "#{passed} passed,",
               "#{failed} failed",
               "(#{passed + failed} total)"

+# Set the requested key for the test. Every test can have at
+# most one. The manager will request the key on the job equeue,
+# and will begin calling expectation blocks only once the key
+# has been completed.
 request = (args...) ->
   key = args.join ':'
   requested = key
@@ -348,6 +476,8 @@
   throw err if err
   null

+# Files specified to test.coffee are loaded into the test's namespace
+# with `eval`.
 load_tests = ->
   for file in argv._
     raw = fs.readFileSync(file).toString()


cleanup

cleanup

--- src/render/pageTemplate.coffee
+++ src/render/pageTemplate.coffee
@@ -35,7 +35,6 @@
     var initialProps = #{JSON.stringify options};
     var preloadComponents = #{JSON.stringify preloadComponents};
     </script>
-    <script>console.log('page', new Date());</script>
     <script>#{injectedScripts}</script>
     <script src='/plugins/kerplunk-server/js/main.js'></script>
     #{base}


Add plugin origin to created decorations

--- lib/minimap-selection-view.coffee
+++ lib/minimap-selection-view.coffee
@@ -28,10 +28,10 @@

     for selection in textEditor.getSelections()
       if not selection.isEmpty()
-        decoration = @minimap.decorateMarker(selection.marker, type: 'highlight-under', scope: '.minimap .minimap-selection .region')
+        decoration = @minimap.decorateMarker(selection.marker, type: 'highlight-under', scope: '.minimap .minimap-selection .region', plugin: 'selection')
         @decorations.push decoration if decoration?
       else if atom.config.get('minimap-selection.highlightCursorsLines')
-        decoration = @minimap.decorateMarker(selection.marker, type: 'line', scope: '.minimap .minimap-selection .cursor-line')
+        decoration = @minimap.decorateMarker(selection.marker, type: 'line', scope: '.minimap .minimap-selection .cursor-line', plugin: 'selection')
         @decorations.push decoration if decoration?


Add a tip

Add a tip

--- lib/tips.coffee
+++ lib/tips.coffee
@@ -1,4 +1,5 @@
 module.exports = [
-  'Everything Atom can do is in the Command Palette. See it by using {command-palette:toggle}',
-  'Toggle the Tree View with {tree-view:toggle}'
+  'Everything Atom can do is in the Command Palette. See it by using {command-palette:toggle}'
+  'You can toggle the Tree View with {tree-view:toggle}'
+  'You can quickly open files with the Fuzzy Finder. Try it by using {fuzzy-finder:toggle-file-finder}'
 ]


:lipstick: consistency

:lipstick: consistency

--- lib/view.coffee
+++ lib/view.coffee
@@ -7,7 +7,8 @@
     @emitter = new Emitter
     @view = new VimNormalModeInputElement().initialize(this, opts)
     @editor.normalModeInputView = @view
-    @vimState.onDidFailToCompose => @view.remove()
+    @vimState.onDidFailToCompose =>
+      @view.remove()

   onDidGetInput: (callback) ->
     @emitter.on 'did-get-input', callback


now pass json to the server

now pass json to the server

--- lib/omni-sharp-server/omni.coffee
+++ lib/omni-sharp-server/omni.coffee
@@ -42,8 +42,9 @@

       rp
         uri: @_uri path
-        method: "POST"
-        form: _.extend({}, context, d)
+        method: "POST",
+        json: true,
+        body: _.extend({}, context, d)
       .then (data) ->
         try
           parsedData = JSON.parse(data)


修改引号错误

修改引号错误

--- lib/utils/text-description.coffee
+++ lib/utils/text-description.coffee
@@ -24,7 +24,7 @@
   createAppInfo: '请填写要创建的应用信息'
   inputAppID: '请输入应用标识'
   appIDPlaceholder: '例如: com.foreveross.myapp'
-  appIDError: '只能输入字母和点('.')，且至少三级目录，例如: com.foreveross.myapp'
+  appIDError: '只能输入字母和点，且至少三级目录，例如: com.foreveross.myapp'
   inputAppName: '请输入应用名称'
   appNamePlaceholder: '应用显示的名称'
   inputAppPath: '应用创建位置'


Verify the buttons individually in the spec

The outer expand-collapse element is no longer in the view.

--- src/packages/command-panel/spec/command-panel-spec.coffee
+++ src/packages/command-panel/spec/command-panel-spec.coffee
@@ -139,7 +139,8 @@
             expect(commandPanel.previewList).toBeVisible()

           it  "shows the expand and collapse all buttons", ->
-            expect(commandPanel.find('.expand-collapse')).toBeVisible()
+            expect(commandPanel.collapseAll).toBeVisible()
+            expect(commandPanel.expandAll).toBeVisible()

           describe "when the preview list is focused", ->
             it "hides the command panel", ->


disable mangling cos something is not working

--- lineman/config/application.coffee
+++ lineman/config/application.coffee
@@ -16,7 +16,7 @@
   loadNpmTasks: ["grunt-angular-templates", "grunt-concat-sourcemap", "grunt-ng-annotate", "grunt-haml", 'grunt-sass', 'grunt-cucumber', 'grunt-contrib-copy', 'grunt-exec']

   removeTasks:
-    dist: ['uglify']
+    #dist: ['uglify']
     common: ["handlebars", "jst", 'less', 'pages', 'concat_sourcemap', 'pages:dev']

   prependTasks:
@@ -27,6 +27,8 @@
     common: ["concat_sourcemap:css", "concat_sourcemap:app", "concat_sourcemap:vendor", "concat_sourcemap:spec"]

   uglify:
+    options:
+      mangle: false
     js:
       files:
         "dist/js/vendor.js": "generated/js/vendor.js"


DEMO: use a different demo icon to better evaluate the icons in buttons (bank icon is hardly if ever used in the app)

--- demo/src/demos/ButtonDemo.coffee
+++ demo/src/demos/ButtonDemo.coffee
@@ -293,7 +293,7 @@
 		@__addDivider("Button option: appearance ")

 		@__addButtonPair("appearance: \"normal\"",
-			icon_left: new CUI.Icon(class: "fa-bank")
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			appearance: "normal"
 			text: "Normal Button"
 			onClick: (evt,button) =>
@@ -301,7 +301,7 @@
 		)

 		@__addButtonPair("appearance: \"flat\"",
-			icon_left: new CUI.Icon(class: "fa-bank")
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			appearance: "flat"
 			text: "Flat Button"
 			onClick: (evt,button) =>
@@ -309,7 +309,7 @@
 		)

 		@__addButtonPair("appearance: \"link\"",
-			icon_left: new CUI.Icon(class: "fa-bank")
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			appearance: "link"
 			text: "Link Button"
 			onClick: (evt,button) =>
@@ -323,7 +323,7 @@
 		)

 		@__addButtonPair("appearance: \"important\" (OBSOLETE ???)",
-			icon_left: new CUI.Icon(class: "fa-bank")
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			appearance: "important"
 			text: "Important Button"
 			onClick: (evt,button) =>
@@ -339,24 +339,24 @@

 		@__addDivider("Button option: size ")

-		@__addButtonPair("size: \"normal\"",
-			icon_left: new CUI.Icon(class: "fa-bank")
+		@__addButtonPair("size: \"base\"",
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			size: "normal"
 			text: "Normal Button"
 			onClick: (evt,button) =>
 				@log("Clicked: "+button.getText())
 		)

-		@__addButtonPair("size: \"mini\"",
-			icon_left: new CUI.Icon(class: "fa-bank")
+		@__addButtonPair("size: \"sm\"",
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			size: "mini"
 			text: "Mini Button"
 			onClick: (evt,button) =>
 				@log("Clicked: "+button.getText())
 		, "cui-demo-button-size-small")

-		@__addButtonPair("size: \"big\"",
-			icon_left: new CUI.Icon(class: "fa-bank")
+		@__addButtonPair("size: \"lg\"",
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			size: "big"
 			text: "Big Button"
 			onClick: (evt,button) =>
@@ -365,7 +365,7 @@

 		@__addDivider("Buttons with mixed options")
 		@__addButton("Big link button",
-			icon_left: new CUI.Icon(class: "fa-bank")
+			icon_left: new CUI.Icon(class: "fa-cloud")
 			size: "big"
 			appearance: "link"
 			class: "cui-demo-button-size-large-link "
@@ -774,7 +774,7 @@
 			]
 		)

-		@__addButtonbarPair("example 4 flat, icon and optional text, mini",
+		@__addButtonbarPair("example 4 flat, icon and optional text, small",
 			buttons: [
 				new CUI.Button(
 					appearance: "flat",


always unset param if null

always unset param if null

--- resources/assets/coffee/_classes/beatmapset-filter.coffee
+++ resources/assets/coffee/_classes/beatmapset-filter.coffee
@@ -122,7 +122,7 @@
     charParams = {}

     for own key, value of filters
-      if value? && @getDefault(filters, key) != value
+      if !value? || @getDefault(filters, key) != value
         charParams[@keyToChar()[key]] = value

     charParams


Fix blocking/unblocking

Fix blocking/unblocking

--- resources/assets/coffee/react/modding-profile/main.coffee
+++ resources/assets/coffee/react/modding-profile/main.coffee
@@ -74,6 +74,7 @@

   componentDidMount: =>
+    $.subscribe 'user:update.profilePage', @userUpdate
     $.subscribe 'profile:showMore.moddingProfilePage', @showMore
     $.subscribe 'profile:page:jump.moddingProfilePage', @pageJump
     $.subscribe 'beatmapsetDiscussions:update.moddingProfilePage', @discussionUpdate
@@ -348,6 +349,11 @@

     @pageJump null, e.currentTarget.dataset.pageId

+  userUpdate: (_e, user) =>
+    return @forceUpdate() if user?.id != @state.user.id
+
+    # this component needs full user object but sometimes this event only sends part of it
+    @setState user: _.assign({}, @state.user, user)

   users: =>
     if !@cache.users?


Fix tests

Fix tests

--- app/modules/invite-members/invite-members-form/invite-members-form.controller.spec.coffee
+++ app/modules/invite-members/invite-members-form/invite-members-form.controller.spec.coffee
@@ -26,6 +26,7 @@
     _mockProjectService = () ->
         mocks.projectService = {
             project: sinon.stub()
+            fetchProject: sinon.stub()
         }

         provide.value "tgProjectService", mocks.projectService
@@ -118,7 +119,7 @@
         inviteMembersFormCtrl.inviteContactsMessage = 'Message'
         inviteMembersFormCtrl.loading = true

-        promise = mocks.tgResources.memberships.bulkCreateMemberships.withArgs(
+        mocks.tgResources.memberships.bulkCreateMemberships.withArgs(
             1,
             [{
                 'role_id': 1
@@ -127,6 +128,8 @@
             'Message'
         ).promise().resolve()

+        mocks.projectService.fetchProject.withArgs().promise().resolve()
+
         inviteMembersFormCtrl.sendInvites().then () ->
             expect(inviteMembersFormCtrl.loading).to.be.false
             expect(mocks.rootScope.$broadcast).to.have.been.calledWith("membersform:new:success")


More robust escaping regex

More robust escaping regex

--- app/assets/javascripts/admin/models/pagination_collection.coffee
+++ app/assets/javascripts/admin/models/pagination_collection.coffee
@@ -115,7 +115,8 @@
       @state.filterQuery = ""
       @state.filter = null
     else
-      words = _.map(query.split(" "), (element) -> element.toLowerCase().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"))
+      words = _.map(query.split(" "),
+        (element) -> element.toLowerCase().replace(/[\-\[\]{}()\*\+\?\.,\\\^\$\|\#\s]/g, "\\$&"))
       uniques = _.filter(_.uniq(words), (element) -> element != '')
       pattern = "(" + uniques.join("|") + ")"
       regexp = new RegExp(pattern, "igm")


change bbox color

change bbox color

--- app/assets/javascripts/oxalis/controller/scene_controller.coffee
+++ app/assets/javascripts/oxalis/controller/scene_controller.coffee
@@ -43,7 +43,7 @@
       showCrossSections : true })
     @bb = new Cube(@model, {
       max : [0, 0, 0]
-      color : 0xff0000
+      color : 0xffaa00
       showCrossSections : true })

     # TODO: Implement text


Uncache workflows if we can't find any

Uncache workflows if we can't find any

--- app/pages/project/classify.cjsx
+++ app/pages/project/classify.cjsx
@@ -81,6 +81,7 @@
     project.get('workflows').then (workflows) ->
       if workflows.length is 0
         throw new Error "No workflows for project #{project.id}"
+        project.uncacheLink 'workflows'
       else
         randomIndex = Math.floor Math.random() * workflows.length
         # console.log 'Chose random workflow', workflows[randomIndex].id


Privatize ::bufferRangeForBufferRow

Privatize ::bufferRangeForBufferRow

--- src/editor.coffee
+++ src/editor.coffee
@@ -337,7 +337,7 @@
   # number of the editor.
   getLastBufferRow: -> @buffer.getLastRow()

-  # Public: Returns the range for the given buffer row.
+  # Returns the range for the given buffer row.
   #
   # row - A row {Number}.
   # options - An options hash with an `includeNewline` key.


Mark the current channel as viewed when scanning for notifications

--- app/assets/javascripts/notifications.coffee
+++ app/assets/javascripts/notifications.coffee
@@ -21,6 +21,10 @@
 setInterval ->
   name = "@#{TS.model.user.name}"
   total = 0
+  # Mark the current channel as viewed to mark notifications sent since we
+  # switched. Otherwise notifications for a currently-viewed muted room can
+  # stack up.
+  channelsViewedAt[TS.model.active_channel_id] = (Date.now() / 1000.0)
   for channel in TS.model.channels when channel.is_member
     count = 0


Improve scroller logic

Improve scroller logic

--- client/publication.coffee
+++ client/publication.coffee
@@ -1,3 +1,5 @@
+draggingViewport = false
+
 class @Publication extends @Publication
   constructor: (args...) ->
     super args...
@@ -182,16 +184,21 @@

 Template.publicationScroller.created = ->
   $(window).on 'scroll.publicationScroller', (e) =>
-    $(@find '.viewport').css 'top', "#{ viewportPositionPercentage() }%"
+    unless draggingViewport
+      $(@find '.viewport').css 'top', "#{ viewportPositionPercentage() }%"

 Template.publicationScroller.rendered = ->
   if Session.equals 'currentPublicationRendered', true
     $(@find '.viewport').draggable
       containment: 'parent'
+      start: (e) ->
+        draggingViewport = true
+        true # Ensure default runs
       stop: (e) ->
-        e.stopPropagation()
-        console.log e
-        scrollToOffset e.pageY - $(e.target).parent().offset().top
+        draggingViewport = false
+        $target = $(e.target)
+        scrollToOffset $target.offset().top - $target.parent().offset().top
+        true # Ensure default runs
     $(@find '.viewport').height "#{ viewportHeightPercentage() }%"

 Template.publicationScroller.destroyed = ->
@@ -210,7 +217,7 @@
 Template.publicationScroller.events
   'click': (e, template) ->
     $target = $(e.target)
-    offset = if $target.is('#scroller') then e.offsetY else e.pageY - $target.parent().offset().top
+    offset = if $target.is('#scroller') then e.offsetY else $target.offset().top - $target.parent().offset().top
     scrollToOffset offset

 Template.publicationAnnotations.annotations = ->


Add 'lint:es' task

Add 'lint:es' task

--- gulp/tasks/lint.coffee
+++ gulp/tasks/lint.coffee
@@ -2,7 +2,13 @@
 config = require("../config")
 $      = config.plugins

-gulp.task("lint", ["lint:coffee"])
+gulp.task("lint", ["lint:es", "lint:coffee"])
+
+gulp.task "lint:es", ->
+  gulp.src(config.src.babel)
+    .pipe($.plumber())
+    .pipe($.eslint(config.options.eslint))
+    .pipe($.eslint.formatEach("compact", process.stderr))

 gulp.task "lint:coffee", ->
   gulp.src(config.src.coffee)


Atom config

Atom config

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -88,8 +88,11 @@
   minimap:
     plugins:
       "find-and-replace": true
+      "find-and-replaceDecorationsZIndex": 0
       "git-diff": true
+      "git-diffDecorationsZIndex": 0
       "highlight-selected": true
+      "highlight-selectedDecorationsZIndex": 0
   "one-dark-ui":
     layoutMode: "Compact"
   "open-in":


Enable Atom minimap "absolute mode."

Enable Atom minimap "absolute mode."

--- home/.atom/config.cson
+++ home/.atom/config.cson
@@ -92,7 +92,8 @@
   "symbols-tree-view": {}
   "linter-eslint":
     useGlobalEslint: true
-  minimap: {}
+  minimap:
+    absoluteMode: true
   "atom-material-ui":
     accentColor: "Pink"
     compactTreeView: true


matrix chart preview to be colored circles(no red)

--- client/angular/components/matrix_chart/matrix_chart.coffee
+++ client/angular/components/matrix_chart/matrix_chart.coffee
@@ -21,9 +21,9 @@

     drawShape = (row, col, width, value) ->

-      color = ['#ebebeb','#d1eefd','#70C9F8'][value]
+      color = ['#ebebeb','#f3b300','#00e572'][value]

-      shapes.push(draw.rect(width-1, width-1)
+      shapes.push(draw.circle(width-1)
                       .fill(color)
                       .x(width * row)
                       .y(width * col))


SidebarStackSection: update label and order for Destroy VMs

--- client/app/lib/components/sidebarstacksection/index.coffee
+++ client/app/lib/components/sidebarstacksection/index.coffee
@@ -73,7 +73,7 @@
       when 'Update' then EnvironmentFlux.actions.reinitStackFromWidget stack
       when 'Edit' then router.handleRoute "/Stack-Editor/#{stack.get 'baseStackId'}"
       when 'Reinitialize' then EnvironmentFlux.actions.reinitStackFromWidget stack
-      when 'Destroy' then EnvironmentFlux.actions.deleteStack { stack }
+      when 'Destroy VMs' then EnvironmentFlux.actions.deleteStack { stack }
       when 'VMs' then router.handleRoute "/Home/Stacks/virtual-machines"

@@ -92,7 +92,7 @@
     if @getStackUnreadCount()
       menuItems['Update'] = { callback }

-    ['Edit', 'Reinitialize', 'Destroy', 'VMs'].forEach (name) =>
+    ['Edit', 'Reinitialize', 'VMs', 'Destroy VMs'].forEach (name) =>
       menuItems[name] = { callback }

     { top } = findDOMNode(this).getBoundingClientRect()


Remove testing auto load config

Remove testing auto load config

--- client/skr/screens/customer-projects/CustomerProjects.cjsx
+++ client/skr/screens/customer-projects/CustomerProjects.cjsx
@@ -13,18 +13,16 @@
     getHourlyRate: -> @project.rates?.hourly
     setHourlyRate: (value) ->
         @project.rates = _.extend({}, @project.rates, {hourly: value.replace(/[^0-9.]/g, '')})
-    componentDidMount: ->
-        finder = @refs.finder.refs.finder
-        finder._setValue('PENS')
-        finder.loadCurrentSelection()
-        @state.commands.toggleEdit()
-
     ColorOption: (props) ->

{props.item.name}

     setColor: (value) ->
         @project.options = _.extend({}, @project.options, {color: value.id})
         @forceUpdate()
+    getColorReadOnly: ->
+        index = @getColor()
+        color = _.findWhere(Skr.Models.CustomerProject.COLORS, id: index)
+
{color?.name}

     getColor: ->
         @project.options?.color
@@ -43,10 +41,14 @@
                 <LC.Input name="po_num" model={@project} sm=3 />
             </BS.Row>
             <BS.Row>
-
                 <LC.Input sm=2 name="rates" label='Hourly Rate' model={@project}
                     setValue={@setHourlyRate} getValue={@getHourlyRate} />
-                <LC.FormGroup sm=2 label="Entry Color">
+
+                <LC.FieldWrapper sm=2
+                    label="Entry Color"
+                    className="color-selection"
+                    value={@getColorReadOnly()}
+                >
                     <Lanes.Vendor.ReactWidgets.DropdownList
                         className='colors'
                         data={Skr.Models.CustomerProject.COLORS}
@@ -55,7 +57,8 @@
                         valueComponent={@ColorOption}
                         disabled={!@state.commands.isEditing()}
                         itemComponent={@ColorOption} />
-                </LC.FormGroup>
+                </LC.FieldWrapper>
+
                 <LC.Input name="description" model={@project} sm=8 />
             </BS.Row>


remove old unused ioredis keepalive option

--- config/settings.defaults.coffee
+++ config/settings.defaults.coffee
@@ -44,8 +44,6 @@
 			key_schema:
 				projectHistoryOps: ({project_id}) -> "ProjectHistory:Ops:{#{project_id}}"
 				projectHistoryFirstOpTimestamp: ({project_id}) -> "ProjectHistory:FirstOpTimestamp:{#{project_id}}"
-			redisOptions:
-				keepAlive: 100

 		lock:
 			port: process.env["LOCK_REDIS_PORT"] or process.env["REDIS_PORT"] or "6379"


Scripts: create-default-workspace: replace daisy with async

--- scripts/create-default-workspace/main.coffee
+++ scripts/create-default-workspace/main.coffee
@@ -1,8 +1,7 @@
-
-Bongo = require 'bongo'
+async          = require 'async'
+Bongo          = require 'bongo'
 {Relationship} = require 'jraphical'

-{daisy} = Bongo

 { join: joinPath } = require 'path'

@@ -34,8 +33,9 @@

     account = workspace = null

-    daisy queue = [
-      ->
+    queue = [
+
+      (next) ->
         process.stdout.write 'Checking default workspace'

         query =
@@ -48,10 +48,10 @@
           process.stdout.write ': ' + (if workspace_ then 'found' else 'not found') + "\n"

           workspace = workspace_
-          queue.next()
+          next()

-      ->
-        return queue.next()  if workspace
+      (next) ->
+        return next()  if workspace

         username = machine.credential

@@ -63,11 +63,11 @@
           process.stdout.write ': ' + (if account_ then 'found' else 'not found') + "\n"

           account = account_
-          queue.next()
+          next()

-      ->
-        return queue.next()  if workspace
-        return queue.next()  unless account
+      (next) ->
+        return next()  if workspace
+        return next()  unless account

         client = connection: delegate: account

@@ -78,13 +78,11 @@

           process.stdout.write ": #{workspace.getId()}\n"

-          queue.next()
-
-      ->
-
-        callback()
+          next()

     ]
+
+    async.series queue, callback

   fields = _id: 1, uid: 1, credential: 1, label: 1


wrap vessel regEx in try catch block

wrap vessel regEx in try catch block

--- imports/ui/pages/vessels/server/vessels.coffee
+++ imports/ui/pages/vessels/server/vessels.coffee
@@ -5,18 +5,23 @@
 	if typeof searchString == 'string' && searchString != '' && searchString.length >= 3
 		# TODO: verify correct permissions
 		if true # Roles.userIsInRole @userId, Permissions.shiftAndStoreAdmin, projectId
-			Vessels.find
-				$or: [
-					localName: new RegExp('.*' + searchString + '.*', 'i')
-				,
-					callsign: new RegExp('.*' + searchString + '.*', 'i')
-				,
-					eni: new RegExp('.*' + searchString + '.*', 'i')
-				,
-					imo: new RegExp('.*' + searchString + '.*', 'i')
-				,
-					mmsi: new RegExp('.*' + searchString + '.*', 'i')
-				]
+			try
+				regEx = new RegExp('.*' + searchString + '.*', 'i')
+
+				Vessels.find
+					$or: [
+						localName: regEx
+					,
+						callsign: regEx
+					,
+						eni: regEx
+					,
+						imo: regEx
+					,
+						mmsi: regEx
+					]
+			catch error
+				@ready()
 		else
 			@ready()
 	else


adds js+css to the default pages template context

This is strictly for backwards-compatibility. If
a user upgrades to the latest lineman from a project
that predates the unification of generated & dist
filenames for app.js & app.css, they'll see a super
confusing white screen. Just ran into this with a
current user.

--- config/application.coffee
+++ config/application.coffee
@@ -129,12 +129,16 @@
       files:
         "generated": "<%= files.pages.source %>",
         "generated/index.html": "app/templates/homepage.*" # backward compatibility
-      context: {}
+      context:
+        js: "js/app.js"
+        css: "css/app.css"
     dist:
       files:
         "dist": "<%= files.pages.source %>",
         "dist/index.html": "app/templates/homepage.*" # backward compatibility
-      context: {}
+      context:
+        js: "js/app.js"
+        css: "css/app.css"

   #optimizing
   uglify:


teams: create group handler error handling cleanup

--- servers/lib/server/handlers/createteam.coffee
+++ servers/lib/server/handlers/createteam.coffee
@@ -46,14 +46,7 @@

     createGroup = (err, result) ->

-      if err?
-
-        {message} = err
-
-        if err.errors?
-          message = "#{message}: #{Object.keys err.errors}"
-
-        return res.status(400).send message
+      return res.status(400).send getErrorMessage err  if err?

       # don't set the cookie we don't want that
       # bc we're going to redirect the page to the
@@ -125,3 +118,10 @@

   koding.models.JInvitation.create client, { invitations }, callback

+
+getErrorMessage = (err) ->
+
+  { message } = err
+  message     = "#{message}: #{Object.keys err.errors}"  if err.errors?
+
+  return message


Add utility methods to deal with events in mongo event store

--- lib/event_store/mongodb.coffee
+++ lib/event_store/mongodb.coffee
@@ -76,8 +76,11 @@
   findAllEventsByAggregateUid: (aggregateUid, callback) ->
     @_find aggregateUid: aggregateUid, callback

-  findSomeEventsByAggregateUidAfterVersion: (aggregateUid, version, eventCount, callback) ->
-    @_findLimited { aggregateUid: aggregateUid, version: { "$gt": version } }, eventCount, callback
+  countAllEventsByAggregateUid: (aggregateUid, callback) ->
+    @_count aggregateUid: aggregateUid, callback
+
+  findSomeEventsByAggregateUidBeforeVersion: (aggregateUid, version, eventCount, callback) ->
+    @_findLimited { aggregateUid: aggregateUid, version: { "$lte": version } }, eventCount, callback

   findAllEventsByAggregateUidAfterVersion: (aggregateUid, version, callback) ->
     @_find aggregateUid: aggregateUid, version: { $gt: version }, callback
@@ -161,7 +164,7 @@
   _findLimited: (params, eventCount, callback) ->
     p = new Profiler "MongoDbEventStore#_findLimited(db request)", @logger
     p.start()
-    @eventCollection.find(params).sort("version":1).limit(eventCount).toArray (err, items) =>
+    @eventCollection.find(params).sort("version": -1).limit(eventCount).toArray (err, items) =>
       p.end()

       if err?
@@ -183,6 +186,11 @@
         callback null, []
       else
         @_instantiateEventsFromRows items, callback
+
+  _count: (params, callback) ->
+    @eventCollection.find(params).count (err, number) ->
+      return callback err if err?
+      callback null, number

   _instantiateEventsFromRows: (rows, callback) ->
     events = []


Set grammar data attr on link

Set grammar data attr on link

--- lib/grammar-status-view.coffee
+++ lib/grammar-status-view.coffee
@@ -38,8 +38,7 @@
         grammarName = 'Plain Text'
       else
         grammarName = grammar.name ? grammar.scopeName
-      @grammarLink
-        .text(grammarName)
-        .attr('title', grammarName)
+      @grammarLink.element.textContent = grammarName
+      @grammarLink.element.dataset.grammar = grammarName
     else
       @hide()


Mekko: tweaks

Mekko: tweaks

--- app/assets/javascripts/d3/mekko.coffee
+++ app/assets/javascripts/d3/mekko.coffee
@@ -11,16 +11,12 @@
     val:   => @get('gquery').safe_future_value()
     label: => @get('label') || @get('gquery')
     key:   => "#{@get 'carrier'}_#{@get 'sector'}"
-    tooltip_text: =>
-      "#{@get 'carrier'} #{@get 'sector'}<br/>#{parseInt @val()} PJ"

   NodeGroup: class extends Backbone.Model
       initialize: -> @nodes = []
       total_value: => d3.sum @nodes, (n) -> n.val()

   View: class extends D3ChartView
-    el: "body"
-
     initialize: ->
       @series = @model.series.models
       @initialize_defaults()
@@ -90,7 +86,8 @@
       y_scale = d3.scale.linear().domain([100,0]).range([0, @series_height])

       # axis
-      @y_axis = d3.svg.axis().scale(y_scale).ticks(4).orient("left") .tickFormat((x) -> "#{x}%")
+      @y_axis = d3.svg.axis().scale(y_scale).ticks(4).orient("left")
+        .tickFormat((x) -> "#{x}%")
       @svg.append("svg:g")
         .attr("transform", "translate(0, 0.5)") # for nice, crisp lines
         .attr("class", "y_axis").call(@y_axis)
@@ -100,7 +97,7 @@
         .data(@sector_list.models, (d) -> d.get 'key' )
         .enter().append("svg:g")
         .attr("class", "sector")
-        .attr("transform", (d) -> "translate(30)")
+        .attr("transform", "translate(30)")
         .attr("data-rel", (d) -> d.get 'key')

       # Create items inside the group
@@ -114,6 +111,7 @@
         .attr("y", 10)
         .attr("x", 0)
         .attr("data-rel", (d) -> d.key())
+        .attr('data-tooltip-title', (n) -> "#{n.get 'carrier'} #{n.get 'sector'}")

       # vertical sector label
       @sectors
@@ -132,7 +130,9 @@
         columns: if @carrier_list.length > 9 then 3 else 2

       $("#{@container_selector()} rect.carrier").qtip
-        content: -> $(this).attr('data-tooltip')
+        content:
+          title: -> $(this).attr('data-tooltip-title')
+          text: -> $(this).attr('data-tooltip-text')
         position:
           my: 'bottom right'
           at: 'top center'
@@ -181,7 +181,7 @@
           offsets[d.get 'sector'] += x
           old
         )
-        .attr("data-tooltip", (d) -> d.tooltip_text())
+        .attr("data-tooltip-text", (d) -> Metric.autoscale_value d.val(), 'PJ')

 class D3.mekko.GroupCollection extends Backbone.Collection
   model: D3.mekko.NodeGroup


When adding a subscription, immediately remove the entries of the feed the user was reading previously.

--- app/assets/javascripts/feeds.js.coffee
+++ app/assets/javascripts/feeds.js.coffee
@@ -249,6 +249,7 @@
       post_data = $(this).serialize()
       # Show "loading" message
       $("#loading").removeClass "hidden"
+      $("#feed-entries").empty()
       $.post(form_url, post_data, subscription_result)
       .fail ->
         $("#loading").addClass "hidden"


deletes spelling mistake

deletes spelling mistake

--- app/assets/javascripts/games.js.coffee
+++ app/assets/javascripts/games.js.coffee
@@ -37,7 +37,7 @@
         $('.add-name').show()
       if $('.add-tag').filter(':visible').length == 0 && $(this).parent().parent().hasClass("new-tag-form")
         $('.add-tag').show()
-      if $('.add-variation').filter(':visible').length == 0 && $(this).parent().parent().hasClass("new-variation-form-form")
+      if $('.add-variation').filter(':visible').length == 0 && $(this).parent().parent().hasClass("new-variation-form")
         $('.add-variation').show()
       if $('.add-tip').filter(':visible').length == 0 && $(this).parent().parent().hasClass("new-tip-form")
         $('.add-tip').show()


Added very simple JS to show a GMap. Thinking about moving to MapBox

--- app/assets/javascripts/pages.js.coffee
+++ app/assets/javascripts/pages.js.coffee
@@ -10,8 +10,24 @@
 	  mapTypeControl: false
 	}

-	map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions)
+	window.map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions)
+
+	requestUserLocation()

 	return

+onUserLocationSuccess = (location)=>
+	console.log "User location Latitude: #{location.coords.latitude} - Longitude: #{location.coords.longitude}"
+	window.map.setCenter(new google.maps.LatLng(location.coords.latitude, location.coords.longitude))
+	window.map.setZoom(14)
+
+	return
+
+onUserLocationError = ()=>
+	alert "An error happened while getting your location"
+
+requestUserLocation = ()=>
+	if navigator.geolocation
+		navigator.geolocation.getCurrentPosition(onUserLocationSuccess, onUserLocationError);
+
 google.maps.event.addDomListener(window, 'load', initialize)


More reliable test

More reliable test

--- spec/views/cloud-variables-and-functions-view-spec.coffee
+++ spec/views/cloud-variables-and-functions-view-spec.coffee
@@ -59,11 +59,16 @@
       atom.workspaceView.trigger 'spark-ide:show-cloud-variables-and-functions'

       waitsFor ->
-        !!sparkIde.cloudVariablesAndFunctionsView && sparkIde.cloudVariablesAndFunctionsView.hasParent()
-
-      runs ->
-        @cloudVariablesAndFunctionsView = sparkIde.cloudVariablesAndFunctionsView
-
+        !!sparkIde.cloudVariablesAndFunctionsView
+
+      runs ->
+        @cloudVariablesAndFunctionsView = sparkIde.cloudVariablesAndFunctionsView
+        spyOn @cloudVariablesAndFunctionsView, 'refreshVariable'
+
+      waitsFor ->
+        @cloudVariablesAndFunctionsView.hasParent()
+
+      runs ->
         body = @cloudVariablesAndFunctionsView.find('#spark-ide-cloud-variables > .panel-body')

         expect(body.find('table')).toExist()
@@ -89,7 +94,6 @@
         expect(body.find('table > tbody > tr:eq(0) > td:eq(4) > button').hasClass('icon-eye')).toBe(true)

         # Test refresh button
-        spyOn @cloudVariablesAndFunctionsView, 'refreshVariable'
         body.find('table > tbody > tr:eq(0) > td:eq(3) > button').click()
         expect(@cloudVariablesAndFunctionsView.refreshVariable).toHaveBeenCalled()
         expect(@cloudVariablesAndFunctionsView.refreshVariable).toHaveBeenCalledWith('foo')


Delay initialization of activeElement.

Delay initialization of activeElement.

We could incorrectly initialize activeElement to document.body if the
scroller is called too early; so delay initialization.  It's safe to
leave activeElement as null.

--- content_scripts/scroller.coffee
+++ content_scripts/scroller.coffee
@@ -219,7 +219,7 @@
         window.scrollBy(0, amount)
       return

-    activatedElement ||= firstScrollableElement() || document.body
+    activatedElement ||= firstScrollableElement()
     return unless activatedElement

     # Avoid the expensive scroll calculation if it will not be used.  This reduces costs during smooth,
@@ -230,8 +230,8 @@
       CoreScroller.scroll element, direction, elementAmount

   scrollTo: (direction, pos) ->
-    return unless document.body or activatedElement
-    activatedElement ||= firstScrollableElement() || document.body
+    activatedElement ||= firstScrollableElement()
+    return unless activatedElement

     element = findScrollableElement activatedElement, direction, pos, 1
     amount = getDimension(element,direction,pos) - element[scrollProperties[direction].axisName]


fix #414

fix #414

--- app/coffee/modules/backlog/main.coffee
+++ app/coffee/modules/backlog/main.coffee
@@ -319,7 +319,7 @@

     addNewUs: (type) ->
         switch type
-            when "standard" then @rootscope.$broadcast("usform:new")
+            when "standard" then @rootscope.$broadcast("usform:new", @scope.project.default_us_status)
             when "bulk" then @rootscope.$broadcast("usform:bulk")

     addNewSprint: () ->


Fixes a styling issue on the static loggedin page

--- workers/social/lib/social/render/kodinghomeloggedin.coffee
+++ workers/social/lib/social/render/kodinghomeloggedin.coffee
@@ -33,7 +33,7 @@

-

+

                 #{getStatusWidget account}
                 #{getInnerNav()}


Use Likeable mixin

Use Likeable mixin

--- server/app/bongo/models/messages/post.coffee
+++ server/app/bongo/models/messages/post.coffee
@@ -6,6 +6,7 @@
   @::mixin Notifying::
   @mixin Flaggable
   @::mixin Flaggable::
+  @::mixin Likeable::

   {Base,ObjectRef,secure,dash,daisy} = bongo
   {Relationship} = jraphical
@@ -33,7 +34,7 @@
       instance        : [
         'on','reply','restComments','commentsByRange'
         'like','fetchLikedByes','mark','unmark','fetchTags'
-        'delete','modify','fetchRelativeComments'
+        'delete','modify','fetchRelativeComments','checkIfLikedBefore'
       ]
     schema            : schema
     relationships     :
@@ -254,49 +255,6 @@
       callback
     ]
     daisy queue
-
-  like: secure ({connection}, callback)->
-    {delegate} = connection
-    {constructor} = @
-    unless delegate instanceof constructor.getAuthorType()
-      callback new Error 'Only instances of JAccount can like things.'
-    else
-      Relationship.one
-        sourceId: @getId()
-        targetId: delegate.getId()
-        as: 'like'
-      , (err, likedBy)=>
-        if err
-          callback err
-        else
-          unless likedBy
-            @addLikedBy delegate, respondWithCount: yes, (err, docs, count)=>
-              if err
-                callback err
-              else
-                @update ($set: 'meta.likes': count), callback
-                @fetchActivityId (err, id)->
-                  CActivity.update {_id: id}, {
-                    $set: 'sorts.likesCount': count
-                  }, log
-                @fetchOrigin (err, origin)=>
-                  if err then log "Couldn't fetch the origin"
-                  else @emit 'LikeIsAdded', {
-                    origin
-                    subject       : ObjectRef(@).data
-                    actorType     : 'liker'
-                    actionType    : 'like'
-                    liker    		  : ObjectRef(delegate).data
-                    likesCount	  : count
-                    relationship  : docs[0]
-                  }
-          else
-            @removeLikedBy delegate, respondWithCount: yes, (err, count)=>
-              if err
-                callback err
-                console.log err
-              else
-                @update ($set: 'meta.likes': count), callback

   reply: secure (client, replyType, comment, callback)->
     {delegate} = client.connection