download export file

download export file

--- app/routes/project.coffee
+++ app/routes/project.coffee
@@ -12,11 +12,12 @@
   csvHeaders: ->
     ["Category","Label","Document","Selection"]

-  downloadCSV: (fileName, csv) ->
+  downloadFile: (fileName, fileType, data, fileExtension) ->
+    fileExtension = fileType unless fileExtension
     a = document.createElement('a')
-    a.href = 'data:attachment/csv;charset=utf-8,' + encodeURIComponent(csv)
+    a.href = 'data:attachment/' + fileType + ';charset=utf-8,' + encodeURIComponent(data)
     a.target = '_blank'
-    a.download = "#{fileName}.csv"
+    a.download = "#{fileName}.#{fileExtension}"

     document.body.appendChild(a)
     a.click()
@@ -39,13 +40,15 @@
       @projectToCSV(project).then (csv) =>
         csvString = csv.encode()
         name = project.get('name')
-        @downloadCSV(name, csvString)
+        @downloadFile(name, 'csv', csvString)

     downloadProject: ->
       project = @modelFor('project')
       json = @downloadProject(project)
       console.log json
-      return @uploadProject(json)
+      name = project.get('name')
+      @downloadFile(name, 'json', JSON.stringify(json), 'lbo')
+      # return @uploadProject(json)

 `export default ProjectRoute`


Require moment.js before bootstrap-datetimepicker

--- app/assets/javascripts/butler.js.coffee
+++ app/assets/javascripts/butler.js.coffee
@@ -7,6 +7,9 @@
 #= require dropzone_effects

 #= require bootstrap-sprockets
+
+#= require moment
+#= require moment/de
 #= require bootstrap-datetimepicker

 #= require marked.min
@@ -16,9 +19,6 @@
 # NOTE: requires api controller to render markdown preview.
 #       see echo-live for code
 # require markdown_setup
-
-#= require moment
-#= require moment/de

 #= require flyout
 #= require cocoon


added a exponential scale to the timeline

--- app/assets/javascripts/commit.js.coffee
+++ app/assets/javascripts/commit.js.coffee
@@ -4,8 +4,8 @@
     @height = @$el.height()
     @x      = d3.scale.linear().range([0, @width])
     @rx     = d3.scale.linear().domain([0, @width])
-    @y      = d3.scale.linear().range([@height, 0])
-    @ry     = d3.scale.linear().domain([@height, 0])
+    @y      = d3.scale.pow().exponent(.3).range([@height, 0])
+    @ry     = d3.scale.linear().range([@height, 0])

   get_timestamp:            (commit) -> commit.timestamp
   get_aggregated_additions: (commit) -> commit.aggregated_additions or 0
@@ -226,7 +226,6 @@
   draw: ->
     Repo.chart.attr
       height: Repo.formated_files.length * 23
-    textscale   = d3.scale.linear().domain([0, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, 100])

     Repo.sort_files()
     changes = Repo.chart.selectAll("rect").data(Repo.formated_files).enter().append("g").attr("class", "changes")
@@ -265,7 +264,7 @@
         style: (f, i) -> "fill: #333"

   animate: -> #called after the original draw function and will animate everything into place.
-    scale = d3.scale.log().base(10).domain([0.1, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, settings.width - settings.offset - 2 * settings.padding])
+    scale = d3.scale.pow().exponent(.5).domain([0.1, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, settings.width - settings.offset - 2 * settings.padding])
     Repo.chart.selectAll("rect.deletions")

       .transition(settings.duration)
@@ -331,8 +330,6 @@

   correct_object: (f) ->
     index = Repo.find_index_of(f[0], Repo.prepared_files)
-
-    #console.log(index + " " + f[0])
     return Repo.prepared_files[index]

   display_with_filtered_commits: (filtered_commits) ->
@@ -351,10 +348,8 @@

   display_with_filtered_commits_and_text_filter: (text) ->

-    scale = d3.scale.log().base(10).domain([0.1, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, settings.width - settings.offset - 2 * settings.padding])
-    console.log(Repo.saved_files)
+    scale = d3.scale.pow().exponent(.5).domain([0.1, d3.max(Repo.formated_files, (d)-> d[3] )]).range([0, settings.width - settings.offset - 2 * settings.padding])
     Repo.prepared_files = Repo.filter(text, Repo.saved_files)
-    console.log(Repo.prepared_files)

     Repo.prepared_files = Repo.prepared_files.sort (a,b) -> (b[3] - a[3])


Place bezier chart labels inside the chart boundary

--- app/assets/javascripts/d3/bezier.coffee
+++ app/assets/javascripts/d3/bezier.coffee
@@ -65,7 +65,7 @@
         .data([@start_year, @end_year])
         .enter().append('svg:text')
         .attr('class', 'year')
-        .attr("text-anchor", "middle")
+        .attr("text-anchor", (d, i) => if i == 0 then 'start' else 'end')
         .text((d) -> d)
         .attr('x', (d, i) => if i == 0 then 0 else @series_width)
         .attr('y', @series_height + 16)


Turn HTML button on

Turn HTML button on

Added the HTML button to the Editor Toolbar

--- app/assets/javascripts/editor.js.coffee
+++ app/assets/javascripts/editor.js.coffee
@@ -3,3 +3,4 @@

 $('.editor-control').wysihtml5
   stylesheets: []
+  html: true


fix typo

fix typo

--- app/assets/javascripts/header.js.coffee
+++ app/assets/javascripts/header.js.coffee
@@ -22,10 +22,9 @@
   )

   # close popup once logged!
-  if(window.opener) {
+  if window.opener
     window.opener.location.reload(true)
     window.close()
-  }

   # Show logout only if not on facebook canvas
   # http://blog.blakesimpson.co.uk/read/22-detect-if-page-is-within-facebook-iframe-or-not-javascript


Fix order of arguments when creating interpretation coded value

--- app/assets/javascripts/result.js.coffee
+++ app/assets/javascripts/result.js.coffee
@@ -39,7 +39,7 @@
   ###*
   @returns {CodedValue}
   ###
-  interpretation: -> new hQuery.CodedValue @json['interpretation'].codeSystem, @json['interpretation'].code
+  interpretation: -> new hQuery.CodedValue @json['interpretation'].code, @json['interpretation'].codeSystem

   ###*
   @returns {String}


Fix problems with template.

Fix problems with template.

--- app/assets/javascripts/templates.coffee
+++ app/assets/javascripts/templates.coffee
@@ -24,11 +24,11 @@

     {{#edit_disabled}}
-
+
       report errors

     |
-
+
       get directions

     {{/edit_disabled}}


testing ssh

testing ssh

--- app/coffeescripts/LayersMenuView.coffee
+++ app/coffeescripts/LayersMenuView.coffee
@@ -26,7 +26,7 @@
     $("##{@options.parentId}").append(@el)
     @

-  #these open and close the Layers Menu itself
+  #these open and close the Layers Menu itself
   displayOff: (e) =>
     @$el.removeClass "open"


Duplicated and null values no longer render with state selection, made scope.watch track only one property within state_district object.

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

 angular.module('appApp.controllers')
-  .controller 'DistrictCtrl', ['$scope', '$window', '$location', '$routeParams', '$compile', 'ApiGet', ($scope, $window, $location, $routeParams, $compile, ApiGet) ->
+  .controller 'DistrictCtrl', ['$scope', '$window', '$location', '$routeParams', '$compile', '$timeout', 'ApiGet', ($scope, $window, $location, $routeParams, $compile, $timeout, ApiGet) ->
     $scope.supportGeo = $window.navigator
     $scope.position = null
     $scope.selected_zip = null
@@ -16,7 +16,6 @@
       $window.navigator.geolocation.getCurrentPosition((position)->
         $scope.$apply(()->
           $scope.position = position
-          $scope.selected.position = position
           $scope.findDistrictByLongLat()
         , (error) -> console.log error)
       )
@@ -25,16 +24,13 @@
       ApiGet.congress "districts/locate?latitude=#{$scope.position.coords.latitude}&longitude=#{$scope.position.coords.longitude}", $scope.setDistrict, this

     $scope.findDistrictByZip = () ->
-      ApiGet.congress "districts/locate?zip=#{$scope.selected_zip}", $scope.setDistrict, this, $scope.selected_zip
-
-    $scope.setDistrict = (error, data, zip) ->
+      ApiGet.congress "districts/locate?zip=#{$scope.selected_zip}", $scope.setDistrict, this
+
+    $scope.setDistrict = (error, data) ->
       if not error
         unless data.length
           return $scope.warning = "No district was found for #{$scope.selected_zip}."
         $scope.state_district = {state: data[0].state, district: data[0].district}
-        $scope.selected.zip = zip
-        $scope.selected.state = data[0].state
-        $scope.selected.district = data[0].district
       else console.log "Error: ", error

     $scope.setDistrictData = (newVals, oldVals) ->
@@ -52,14 +48,15 @@
         ApiGet.congress "legislators?state=#{$scope.state_district.state}&title=Sen", (error, data) ->
           if not error
             for sen in data
-              $scope.district_reps.push(sen)
+              if sen.title then $scope.district_reps.push(sen)
           else console.log "Error: ", error
           , this
         ApiGet.congress "legislators?state=#{$scope.state_district.state}&district=#{$scope.state_district.district}", (error, data) ->
           if not error
-            $scope.district_reps.push(data[0])
+            if data[0].title then $scope.district_reps.push(data[0])
           else console.log "Error: ", error
           , this
+

     $scope.highlightDistrict = () ->
       if not $scope.state_district.district
@@ -98,8 +95,6 @@
           else
             district_id = d3.select(this).text()
             $scope.state_district = {state: district_id.slice(0, 2), district: district_id.slice(3, 6)}
-            $scope.selected.state = district_id.slice(0, 2)
-            $scope.selected.district = district_id.slice(3, 6)
             $scope.$apply()
         )
         $scope.usMap.append("path").attr("class", "district-boundaries").attr("clip-path", "url(#clip-land)").datum(topojson.mesh(congress, congress.objects.districts, (a, b) ->
@@ -197,14 +192,12 @@
       if $routeParams.bioguide_id.length > 0
         ApiGet.congress "legislators?bioguide_id=#{$routeParams.bioguide_id}", (error, data) ->
           if not error
-            if not data[0].district
+            if not data[0].district
               for state in ["AK", "DE", "MT", "ND", "SD", "VT", "WY"]
                 if data[0].state is state
                   data[0].district = "0"
               if not data[0].district then data[0].district = "1"
             $scope.state_district = {state: data[0].state, district: data[0].district}
-            $scope.selected.state = data[0].state
-            $scope.selected.district = data[0].district
           else console.log "Error, Senator/Rep not found."
       else console.log "No parameter"

@@ -279,10 +272,17 @@
     $scope.defaultFocus()

     $scope.$watch('state_district', (newVals, oldVals) ->
-      if $scope.state_district.state
+      if $scope.state_district.state and !$scope.state_district.district
+        if not $scope.state_district.district
+          for state in ["AK", "DE", "MT", "ND", "SD", "VT", "WY"]
+            if $scope.state_district.state is state
+              $scope.state_district.district = "0"
+          if not $scope.state_district.district then $scope.state_district.district = "1"
+      if $scope.state_district.state and $scope.state_district.district
         $scope.setDistrictData(newVals, oldVals)
         $scope.highlightDistrict()
     , true)
+

     $scope.$watch('district_reps', (newVals, oldVals) ->
       if $scope.district_reps.length and $scope.state_district.state


make ItemSelection react on route.url changes

--- app/scripts/mixins/ItemSelection.coffee
+++ app/scripts/mixins/ItemSelection.coffee
@@ -7,6 +7,19 @@
 Bootstrap.ItemSelection = Ember.Mixin.create(Bootstrap.ItemValue, Bootstrap.WithRouter,
     classNameBindings: ["isActive:active"]

+    init: ->
+        @_super()
+        @didRouteChange()
+
+    didRouteChange: (->
+        linkTo = @get('content.linkTo')
+        return unless linkTo?
+        itemsView = @get('parentView')
+        return unless itemsView?
+        if @get('router')?.isActive(linkTo)
+            itemsView.set('selected', @get('value'))
+    ).observes('router.url')
+
     ###
     Determine whether the current item is selected,
     if true the 'active' css class will be associated with the this DOM's element.
@@ -15,10 +28,6 @@
     in the parent ItemsView.
     ###
     isActive: (->
-        #activate default tab if current route matches a tab route
-        if @get('content.linkTo')
-            return true if @get('content.linkTo') and @get('router')?.isActive(@get('content.linkTo'))
-
         #TODO: Ensure parentView is inherited from ItemsView
         itemsView = @get('parentView')
         if not itemsView?
@@ -51,6 +60,9 @@
         if typeof(content) is 'object'
             return if content.get('disabled')

+        # items with linkTo will be dispatched in didRouteChange
+        return if @get('content.linkTo')?
+
         #Currently multi selection is not supported
         itemsView.set('selected', @get('value'))
-)+)


remove VirtualizationController#getOsKite

--- client/Main/VirtualizationController.coffee
+++ client/Main/VirtualizationController.coffee
@@ -347,28 +347,6 @@
   getKiteHostname: (vm) ->
     return null  unless vm.hostKite?
     return vm.hostKite.split('|')[1]
-
-  getOsKite: ({ hostname, region }) ->
-    new Promise (resolve) =>
-      kite = @osKites[hostname]
-
-      return resolve kite  if kite?
-
-      kontrol = KD.getSingleton 'kontrol'
-
-      kontrol.getKite
-        name      : 'oskite'
-        username  : 'devrim'
-        version   : '0.0.1'
-        hostname  : hostname
-        region    : region
-
-      .then (kite) =>
-        @osKites[hostname] = kite
-
-        kite.connect()
-        .then(-> resolve kite)
-        .catch warn

   shouldUseNewKites: ->
     new Promise (resolve, reject) ->


Pricing: Fixes "Logging in from Pricing results in No Apps" bug

--- client/Social/Activity/AppController.coffee
+++ client/Social/Activity/AppController.coffee
@@ -54,6 +54,8 @@
     @lastTo                = null
     @lastFrom              = Date.now()
     @lastQuery             = null
+
+    KD.singletons.dock.getView().show()

     # if @mainController.appIsReady then @putListeners()
     # else @mainController.on 'AppIsReady', => @putListeners()


activity: restructure react-router routes

--- client/activity/lib/reactivityroutes.coffee
+++ client/activity/lib/reactivityroutes.coffee
@@ -6,19 +6,52 @@
 PostPane                 = require 'activity/components/postpane'
 PrivateMessageThreadPane = require 'activity/components/privatemessagethreadpane'

-module.exports = [
-  {
-    path: '/Channels'
-    component: ChannelThreadPane
-    childRoutes: [
-      path: ':channelName(/:postId)'
-      components:
-        chat: PublicChatPane
-    ]
-  },
-  {
-    path: '/Messages/:privateChannelId'
-    component: PrivateMessageThreadPane
-  }
+ActivityAppComponent = require 'activity/components/appcomponent'
+
+# module.exports = [
+#   {
+#     path: '/Channels'
+#     component: ChannelThreadPane
+#     childRoutes: [
+#       path: ':channelName(/:postId)'
+#       components:
+#         chat: PublicChatPane
+#     ]
+#   },
+#   {
+#     path: '/Messages/:privateChannelId'
+#     component: PrivateMessageThreadPane
+#   }
+# ]
+
+
+module.exports = newRoutes = [
+  path: '/Channels'
+  component: ActivityAppComponent
+  childRoutes: [
+    path: ':channelName(/:postId)'
+    components:
+      content: ChannelThreadPane
+      modal: null
+  ,
+    path: 'New'
+    components:
+      content: ChannelThreadPane
+      modal: null
+  ]
+,
+  path: '/Messages'
+  component: ActivityAppComponent
+  childRoutes: [
+    path: ':privateChannelId'
+    components:
+      content: PrivateMessageThreadPane
+      modal: null
+  ,
+    path: 'New'
+    components:
+      content: PrivateMessageThreadPane
+      modal: null
+  ]
 ]


stack-editor: rework secondary buttons' show states

--- client/stack-editor/lib/editor/index.coffee
+++ client/stack-editor/lib/editor/index.coffee
@@ -398,34 +398,39 @@
           @processTemplate _stackTemplate

+  afterProcessTemplate: (method) ->
+
+    canEditGroup = kd.singletons.groupsController.canEditGroup()
+
+    switch method
+      when 'provision'
+        @generateStackButton.show()
+        @outputView.add '''
+          Your stack script has been successfully saved.
+          You can now close the stack editor or continue editing your stack.
+        '''
+      when 'reinit'
+        @reinitButton.show()
+        @outputView.add '''
+          Your stack script has been successfully saved.
+          You can now close the stack editor or continue editing your stack.
+        '''
+      when 'maketeamdefault'
+        @setAsDefaultButton.show()
+        @outputView.add '''
+          Your stack script has been successfully saved.
+
+          If you want to auto-provision this template when new users join your team,
+          you need to click "Make Team Default" after you save it.
+
+          You can now close the stack editor or continue editing your stack.
+        '''
+
+
   processTemplate: (stackTemplate) ->

     { groupsController, computeController } = kd.singletons
     canEditGroup = groupsController.canEditGroup()
-
-    setToGroup = (method = 'add') =>
-
-      if canEditGroup
-        @handleSetDefaultTemplate completed = no
-
-        # this is confusing. if there are currently 20 members using this stack
-        # their stack shouldn't be changed to this one automatically
-        # they should see a notification that says "this stack has been deleted by Gokmen"
-        # new users get the default stack should. and this button shouldn't be there each time
-        # i make a new one, it should be on the list-menu.
-        @outputView[method] '''
-          Your stack script has been successfully saved and all your new team
-          members now will see this stack by default. Existing users
-          of the previous default-stack will be notified that default-stack has
-          changed.
-
-          You can now close this window or continue working with your stack.
-        '''
-      else if method is 'addAndWarn'
-        @generateStackButton.show()
-      else
-        @reinitButton.show()
-

     @handleCheckTemplate { stackTemplate }, (err, machines) =>

@@ -442,7 +447,7 @@

       { stackTemplates }       = groupsController.getCurrentGroup()
       stackTemplate.isDefault ?= stackTemplate._id in (stackTemplates or [])
-      templateSetBefore        = stackTemplates?.length
+      hasGroupTemplates        = stackTemplates?.length

       stacks = kd.singletons.reactor.evaluateToJS ['StacksStore']
       templateIds = Object.keys(stacks).map (key) -> stacks[key].baseStackId
@@ -452,39 +457,34 @@
       # TMS-1919: This needs to be reimplemented, once we have multiple
       # stacktemplates set for a team this will be broken ~ GG

+      unless hasGroupTemplates
+
+        # this means that the created stack template will be assigned as team
+        # default, and it will be shared with the group.
+        if canEditGroup
+          @handleSetDefaultTemplate completed = no
+
+          # this is confusing. if there are currently 20 members using this stack
+          # their stack shouldn't be changed to this one automatically
+          # they should see a notification that says "this stack has been deleted by Gokmen"
+          # new users get the default stack should. and this button shouldn't be there each time
+          # i make a new one, it should be on the list-menu.
+          @outputView.addAndWarn '''
+            Your stack script has been successfully saved and all your new team
+            members now will see this stack by default. Existing users
+            of the previous default-stack will be notified that default-stack has
+            changed.
+
+            You can now close this window or continue working with your stack.
+          '''
+          return

       if hasStack
-        setToGroup()
-
-      else if templateSetBefore
-
-        unless stackTemplate.isDefault
-
-          if canEditGroup
-            @setAsDefaultButton.show()
-            @outputView.add '''
-              Your stack script has been successfully saved.
-
-              If you want to auto-provision this template when new users join your team,
-              you need to click "Make Team Default" after you save it.
-
-              You can now close the stack editor or continue editing your stack.
-            '''
-          else
-            @reinitButton.show()
-            @outputView.add '''
-              Your stack script has been successfully saved.
-              You can now close the stack editor or continue editing your stack.
-            '''
-
-          computeController.checkGroupStacks()
-
-        else
-          setToGroup()
-
+        @afterProcessTemplate 'reinit'
+      else if canEditGroup
+        @afterProcessTemplate 'maketeamdefault'
       else
-        setToGroup 'addAndWarn'
-
+        @afterProcessTemplate 'provision'

   checkAndBootstrapCredentials: (callback) ->
@@ -741,6 +741,7 @@

   handleReinit: ->
+
     stacks = kd.singletons.reactor.evaluateToJS ['StacksStore']
     { stackTemplate } = @getData()


show tooltip for the cred is diplayed correctyl

--- client/stack-editor/lib/editor/index.coffee
+++ client/stack-editor/lib/editor/index.coffee
@@ -149,6 +149,8 @@
         title  : "You need to set your #{selectedProvider.toUpperCase()}
                   credentials to be able build this stack."

+    @credentialWarning.bindTransitionEnd()
+
     @credentialStatusView = new CredentialStatusView {
       stackTemplate, selectedProvider
     }
@@ -392,7 +394,11 @@

         @checkAndBootstrapCredentials (err, credentials) =>
           if err
-            @credentialWarning.tooltip.show()
+            @credentialWarning.setClass 'in'
+            @providersPane.tabHandle.setClass 'notification'
+            @_credentialsPassed = no
+            @credentialWarning.once 'transitionend', =>
+              @credentialWarning.tooltip.show()
             return @saveButton.hideLoader()

           @outputView


Teamwork: Title moved to finder pane. Removed main header.

--- client/Teamwork/Views/teamworkapp.coffee
+++ client/Teamwork/Views/teamworkapp.coffee
@@ -32,19 +32,7 @@
       delegate            : this
       playground          : options.playground          or null
       panels              : options.panels              or [
-        title             : "Teamwork"
         hint              : "
This is a collaborative coding environment where you can team up with others and work on the same code.
"
-        buttons           : [
-          {
-            title         : "Tools"
-            cssClass      : "clean-gray tw-tools-button"
-            callback      : => @showToolsModal @teamwork.getActivePanel(), @teamwork
-          }
-          title           : "Playgrounds"
-          itemClass       : KDButtonViewWithMenu
-          cssClass        : "clean-gray playgrounds-button"
-          menu            : []
-        ]
         floatingPanes     : [ "chat" , "terminal", "preview" ]
         layout            :
           direction       : "vertical"
@@ -52,6 +40,7 @@
           splitName       : "BaseSplit"
           views           : [
             {
+              title       : "Teamwork"
               type        : "finder"
               name        : "finder"
             }


Adding ability to override document/window context; enables nanoScroller inside iframes

--- coffeescripts/jquery.nanoscroller.coffee
+++ coffeescripts/jquery.nanoscroller.coffee
@@ -89,6 +89,22 @@
       @default null
     ###
     sliderMaxHeight: null
+
+    ###*
+      an alternate document context.
+      @property documentContext
+      @type Document
+      @default null
+    ###
+    documentContext: null
+
+    ###*
+      an alternate window context.
+      @property windowContext
+      @type Window
+      @default null
+    ###
+    windowContext: null

   # Constants

@@ -281,8 +297,8 @@
     constructor: (@el, @options) ->
       BROWSER_SCROLLBAR_WIDTH or= do getBrowserScrollbarWidth
       @$el = $ @el
-      @doc = $ document
-      @win = $ window
+      @doc = $ @options.documentContext or document
+      @win = $ @options.windowContext or window
       @$content = @$el.children(".#{options.contentClass}")
       @$content.attr 'tabindex', 0
       @content = @$content[0]


Revert "Add additional assessment filter to teacher dashboard assessments tab (#142)" (#151)

This reverts commit c1676dfead95420669d2cc5556bc86bd5ca1cf47.

--- app/views/courses/TeacherClassView.coffee
+++ app/views/courses/TeacherClassView.coffee
@@ -331,7 +331,6 @@
     @courseAssessmentPairs = []
     for course in @courses.models
       assessmentLevels = @classroom.getLevels({courseID: course.id, assessmentLevels: true}).models
-      assessmentLevels = _.filter(assessmentLevels, (l) => l.get('assessment') == true)
       fullLevels = _.filter(@levels.models, (l) => l.get('original') in _.map(assessmentLevels, (l2)=>l2.get('original')))
       @courseAssessmentPairs.push([course, fullLevels])
     return @courseAssessmentPairs


Bug fix

Bug fix

--- memory_sync.coffee
+++ memory_sync.coffee
@@ -66,7 +66,7 @@

   # @private
   destroy: (query, callback) ->
-    return @resetSchema(callback) unless (keys = _.keys(query)).length
+    return @resetSchema({}, callback) unless (keys = _.keys(query)).length

     # destroy specific records
     for id, model_json of @store


Fixed not showing locked items in inventory modal.

--- app/views/play/menu/InventoryModal.coffee
+++ app/views/play/menu/InventoryModal.coffee
@@ -95,7 +95,7 @@
       null  # Don't put into a collection
     else if locked and item.get('slug') isnt 'simple-boots'
       item.classes.push 'locked'
-      if item.isSilhouettedItem or not item.get('gems')
+      if item.isSilhouettedItem() or not item.get('gems')
         # Don't even load/show these--don't add to a collection. (Bandwidth optimization.)
         null
       else


no message

no message

--- scripts/line-beacon-listener.coffee
+++ scripts/line-beacon-listener.coffee
@@ -1,8 +1,12 @@
 module.exports = (robot) ->

   robot.router.post "/line-becon", (req, res) ->
+    if (!req.body) {
+      res.end();
+      return;
+    }
     data = if req.body.payload? then JSON.parse req.body.payload else req.body
-    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{data}"
-    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{data.type}"
+    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{req.body.content}"
+    robot.logger.error "＊＊＊＊＊＊＊＊＊＊＊＊＊＊#{data.content}"
     robot.send {room: "C4LEAQHPW"}, "ビーコンに反応あり"
     res.end ""


more precise sync % calc

more precise sync % calc

--- app/js/services/info.coffee
+++ app/js/services/info.coffee
@@ -20,17 +20,21 @@

     refresh_info : () ->
         @is_refreshing = true
-        @q.all([@common_api.get_info(), @wallet.wallet_get_info()]).then (results) =>
+        @q.all([@common_api.get_info(), @wallet.wallet_get_info(), @blockchain_api.get_info()]).then (results) =>
             data = results[0]
             @info.transaction_scanning = results[1].transaction_scanning
             @info.network_connections = data.network_num_connections
             @info.wallet_open = data.wallet_open
             @info.wallet_unlocked = data.wallet_unlocked
             @info.last_block_time = data.blockchain_head_block_timestamp
+            @info.genesis_timestamp = results[2].genesis_timestamp
             @info.seconds_behind = if @info.last_block_time then (Date.now() - @utils.toDate(@info.last_block_time).getTime()) / 1000 else 0
+            @info.seconds_from_genesis = if @info.genesis_timestamp then (Date.now() - @utils.toDate(@info.genesis_timestamp).getTime()) / 1000 else 0
             @info.last_block_num = data.blockchain_head_block_num
-            last_block_age = data.blockchain_head_block_num * 10
-            @info.percent_synced = if last_block_age and last_block_age > 0 then Math.round((.5 - @info.seconds_behind / last_block_age) * 100.0) else 0
+            if @info.seconds_from_genesis and @info.seconds_from_genesis > 0 and @info.seconds_behind > 0
+                @info.percent_synced = Math.round((1.0 - @info.seconds_behind / @info.seconds_from_genesis) * 100.0)
+            else
+                @info.percent_synced = 0
             @info.blockchain_head_block_age = data.blockchain_head_block_age
             @info.share_supply = data.blockchain_share_supply
             @info.wallet_scan_progress = results[1].scan_progress


Sticky nav

Sticky nav

--- apps/user/components/sections/view.coffee
+++ apps/user/components/sections/view.coffee
@@ -1,5 +1,6 @@
 Backbone = require 'backbone'
 scrollTo = require '../../../../components/smooth_scroll/index.coffee'
+Sticky = require '../../../../components/sticky/index.coffee'
 template = -> require('./index.jade') arguments...

 module.exports = class SettingsSectionsView extends Backbone.View
@@ -22,7 +23,14 @@

     @sections.reset sections

+  postRender: ->
+    return if @stuck
+    @sticky = new Sticky
+    @sticky.add @$el
+    @stuck = true
+
   render: ->
     @$el.html template
       sections: @sections.toJSON()
+    @postRender()
     this


bumped production angular CDN links

bumped production angular CDN links

--- server/packages/assets/index.coffee
+++ server/packages/assets/index.coffee
@@ -23,9 +23,9 @@
 						'/lib/socket.io/socket.io.min.js'

 						'/before-angular.js'
-
-						'//ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js'
-						'//ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular-sanitize.min.js'
+
+						'//ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js'
+						'//ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular-sanitize.min.js'

 						'/lib/angular-ui/bootstrap/ui-bootstrap-tpls-0.10.0.min.js'


loader now a singletonClass lots of log statements remain to be removed

--- src/art/engine/file/v1_loader.coffee
+++ src/art/engine/file/v1_loader.coffee
@@ -63,16 +63,14 @@
   8: "bothStretch"

 module.exports = class V1Loader extends BaseObject
-  @load: (data, bitmapFactory) ->
-    new V1Loader bitmapFactory || Canvas.Bitmap
-    .load data
-
-  constructor: (bitmapFactory)->
-    @bitmapFactory = bitmapFactory
-
-  load: (data) ->
+  @singletonClass()
+
+  @load: (data, bitmapFactory) -> @singleton.load data, bitmapFactory
+
+  load: (data, @bitmapFactory = Canvas.Bitmap) ->
     new Promise (resolve) =>
       xbd = Xbd.parse data
+      log "V1Loader.load": xbd
       topTag = xbd.tag("art_file")
       @decodeTopTag topTag, (artFile) =>
         artFile.axis = point()
@@ -98,8 +96,10 @@
     return callBack bitmaps if index >= keys.length

     key = keys[index]
+    log "decodeBitmaps 1", bitmaps, key
     EncodedImage.toImage bitmaps[key]
     .then (decodedBitmap) =>
+      log "decodeBitmaps 2"
       bitmaps[key] = if @bitmapFactory
         @bitmapFactory.newBitmap decodedBitmap
       else
@@ -107,28 +107,35 @@
       @decodeBitmaps bitmaps, keys, index+1, callBack

   decodeBitmapsTag: (bitmapsTag, callBack) ->
+    log "decodeBitmapsTag 1", bitmapsTag
     bitmaps = {}
     for tag in bitmapsTag.tags
       id = tag.attrs["bitmap_id"] | 0
       bitmapData = tag.attrs["pixel_data"]
       bitmaps[id] = bitmapData

+    log "decodeBitmapsTag 2"
     @decodeBitmaps bitmaps, Object.keys(bitmaps), 0, callBack

   decodeContext: (topTag, callBack) ->
+    log "decodeContext 1"
     bitmapsTag = topTag.tag "bitmaps"

     postDecodeBitmaps = (bitmaps)=>
+      log "decodeContext 2"
       @bitmaps = bitmaps
       callBack()

+    log "decodeContext 3"
     if bitmapsTag
       @decodeBitmapsTag bitmapsTag, postDecodeBitmaps
     else
       postDecodeBitmaps null

   decodeTopTag: (topTag, callBack) ->
+    log "decodeTopTag 1"
     @decodeContext topTag, =>
+      log "decodeTopTag 2"
       topElement = @createElementFromTag topTag
       callBack topElement


Remove extra char

Remove extra char

--- demo_server/src/server/writequery.coffee
+++ demo_server/src/server/writequery.coffee
@@ -11,7 +11,7 @@
                 return mutate_query.mutate server
             when 4
                 insert_query = new WriteQueryInsert @data.getInsert()
-                return insert_query.insert servera
+                return insert_query.insert server
             #when 6 # For each
             when 7
                 point_update_query = new WriteQueryPointUpdate @data.getPointUpdate()


rename stable: true to avoidOverflow: false should come into effect with 1.14

--- lib/editor/result.coffee
+++ lib/editor/result.coffee
@@ -94,7 +94,7 @@
   initMarker: ([start, end]) ->
     @marker = @editor.markBufferRange @lineRange(start, end)
     @marker.result = @
-    mark = item: @view, stable: true
+    mark = item: @view, avoidOverflow: false
     switch @type
       when 'inline' then mark.type = 'overlay'; mark.class = 'ink-overlay'
       when 'block' then mark.type = 'block'; mark.position = 'after'


helpscout: added "tags"

helpscout: added "tags"

So that we can easily sort free from paying within HelpScout

--- servers/lib/server/helpscout.coffee
+++ servers/lib/server/helpscout.coffee
@@ -51,6 +51,8 @@
             id        : 19295
             name      : "Support"
           ,
+          tags		  : ["Plan->#{plan}"]
+		  ,
           threads     : [
             type      : "customer"
             createdBy :


Best finish fixed

Best finish fixed

--- models/game.coffee
+++ models/game.coffee
@@ -46,7 +46,7 @@
       return b.time - a.time
     return a.name.localeCompare b.name

-  for i, ranking of @rankings
+  for ranking, i in @rankings
     ranking.score = i
     ranking.rank = i + 1


add two more teams

add two more teams

--- models/team.coffee
+++ models/team.coffee
@@ -41,7 +41,7 @@
 TeamSchema.static 'canRegister', (next) ->
   Team.count {}, (err, count) ->
     return next err if err
-    max = 325 + 1 # +1 because team fortnight labs doesn't count
+    max = 327 + 1 # +1 because team fortnight labs doesn't count
     next null, count < max, max - count

 TeamSchema.static 'uniqueName', (name, next) ->


Antennapod works now too

Antennapod works now too

--- src/coffee/clients.coffee
+++ src/coffee/clients.coffee
@@ -42,12 +42,12 @@
   ]

   android: [
-    #{
-      #title: 'AntennaPod'
-      #scheme: 'antennapod-subscribe://'
-      #icon: 'android/antennapod@2x.png'
-      #install: 'https://play.google.com/store/apps/details?id=de.danoeh.antennapod'
-    #},
+    {
+      title: 'AntennaPod'
+      scheme: 'antennapod-subscribe://'
+      icon: 'android/antennapod@2x.png'
+      install: 'https://play.google.com/store/apps/details?id=de.danoeh.antennapod'
+    },
     #{
       #title: 'BeyondPod'
       #scheme: 'pcast://'


revert(list-selection): Using clientIds had unintended consequences

--- src/components/list-selection.coffee
+++ src/components/list-selection.coffee
@@ -45,7 +45,7 @@
     return unless item
     throw new Error("toggle must be called with a Model") unless item instanceof Model

-    without = _.reject @_items, (t) -> t.clientId is item.clientId
+    without = _.reject @_items, (t) -> t.id is item.id
     if without.length < @_items.length
       @_items = without
     else
@@ -56,7 +56,7 @@
     return unless item
     throw new Error("add must be called with a Model") unless item instanceof Model

-    updated = _.reject @_items, (t) -> t.clientId is item.clientId
+    updated = _.reject @_items, (t) -> t.id is item.id
     updated.push(item)
     if updated.length isnt @_items.length
       @_items = updated
@@ -73,7 +73,7 @@

     itemIds = _.pluck(items, 'id')

-    without = _.reject @_items, (t) -> t.clientId in itemIds
+    without = _.reject @_items, (t) -> t.id in itemIds
     if without.length < @_items.length
       @_items = without
       @trigger(@)
@@ -97,12 +97,12 @@
       # items are in the _items array in the order they were selected.
       # (important for walking)
       relativeTo = @_items[@_items.length - 1]
-      startIdx = @_view.indexOfId(relativeTo.clientId)
-      endIdx = @_view.indexOfId(item.clientId)
+      startIdx = @_view.indexOfId(relativeTo.id)
+      endIdx = @_view.indexOfId(item.id)
       return if startIdx is -1 or endIdx is -1
       for idx in [startIdx..endIdx]
         item = @_view.get(idx)
-        @_items = _.reject @_items, (t) -> t.clientId is item.clientId
+        @_items = _.reject @_items, (t) -> t.id is item.id
         @_items.push(item)
     @trigger()

@@ -116,7 +116,7 @@

     ids = @ids()
     noSelection = @_items.length is 0
-    neitherSelected = (not current or ids.indexOf(current.clientId) is -1) and (not next or ids.indexOf(next.clientId) is -1)
+    neitherSelected = (not current or ids.indexOf(current.id) is -1) and (not next or ids.indexOf(next.id) is -1)

     if noSelection or neitherSelected
       @_items.push(current) if current
@@ -124,15 +124,15 @@
     else
       selectionPostPopHeadId = null
       if @_items.length > 1
-        selectionPostPopHeadId = @_items[@_items.length - 2].clientId
+        selectionPostPopHeadId = @_items[@_items.length - 2].id

-      if next.clientId is selectionPostPopHeadId
+      if next.id is selectionPostPopHeadId
         @_items.pop()
       else
         # Important: As you walk over this item, remove it and re-push it on the selected
         # array even if it's already there. That way, the items in _items are always
         # in the order you walked over them, and you can walk back to deselect them.
-        @_items = _.reject @_items, (t) -> t.clientId is next.clientId
+        @_items = _.reject @_items, (t) -> t.id is next.id
         @_items.push(next)

     @trigger()
@@ -147,7 +147,7 @@
       touched = 0
       for newer in change.objects
         for existing, idx in @_items
-          if existing.clientId is newer.clientId
+          if existing.id is newer.id
             @_items[idx] = newer
             touched += 1
             break


Simplify syntax

Simplify syntax

--- lib/linter-csound.coffee
+++ lib/linter-csound.coffee
@@ -17,7 +17,7 @@
       items:
         type: 'string'

-  provideLinter: () ->
+  provideLinter: ->
     return {
       name: 'Csound'
       grammarScopes: ['source.csound', 'source.csound-document']


hash device after save, unify save and update

--- lib/models/device.coffee
+++ lib/models/device.coffee
@@ -63,7 +63,7 @@
   verifyDeprecatedToken: (token, callback=_.noop) =>
     @fetch (error, attributes) =>
       return callback error if error?
-
+
       hashedTokens = _.pluck(attributes.tokens, 'hash') ? []
       hashedTokens.push attributes.token if attributes.token?

@@ -111,10 +111,7 @@
     ], (error) =>
       return callback error if error?
       debug 'save', @attributes
-      @devices.update {uuid: @uuid}, {$set: @attributes}, (error, data) =>
-        @clearCache @uuid
-        @fetch?.cache = null
-        callback error
+      @update $set: @attributes, callback

   set: (attributes)=>
     @attributes ?= {}
@@ -131,8 +128,7 @@

   update: (params, callback=->) =>
     params = _.cloneDeep params
-
-    keys = _.keys(params)
+    keys   = _.keys(params)

     if _.all(keys, (key) -> _.startsWith key, '$')
       params['$set'] ?= {}
@@ -146,7 +142,19 @@
       @clearCache @uuid
       @fetch?.cache = null
       return callback @sanitizeError(error) if error?
-      callback()
+      @_hashDevice (error) =>
+        return callback @sanitizeError(error) if error?
+        callback()
+
+  _hashDevice: (callback=->) =>
+    debug '_hashDevice', @uuid
+    @devices.findOne uuid: @uuid, (error, data) =>
+      return callback error if error?
+      delete data.meshblu.hash if data?.meshblu?.hash
+      params = $set :
+        'meshblu.hash': @_hashToken JSON.stringify(data)
+      debug 'updating hash', @uuid, params
+      @devices.update uuid: @uuid, params, callback

   addGeo: (callback=->) =>
     return _.defer callback unless @attributes.ipAddress?


:lipstick:

:lipstick:

--- lib/tag-generator.coffee
+++ lib/tag-generator.coffee
@@ -18,7 +18,7 @@
   generate: ->
     deferred = $.Deferred()
     tags = []
-    command = "#{require.resolve('ctags')}"
+    command = require.resolve('ctags')
     args = ['--fields=+KS', '-nf', '-', @path]
     stdout = (lines) =>
       for line in lines.split('\n')


We don't need this.

We don't need this.

Simplification. unsetting @theme not that importatn

--- lib/theme-watcher.coffee
+++ lib/theme-watcher.coffee
@@ -9,10 +9,6 @@
     super()
     @theme.on 'deactivated', @destroy
     @watch()
-
-  destroy: =>
-    super()
-    @theme = null

   watch: ->
     unless @theme.isFile()


Removed wait for DOM

Removed wait for DOM

--- assets/js/src/__init.coffee
+++ assets/js/src/__init.coffee
@@ -1,42 +1,40 @@
 'use strict'

-$ ->
+window.Uno = Uno =
+  version: '2.6.5'

-  window.Uno = Uno =
-    version: '2.6.4'
+  search:
+    container: -> $('#results')
+    form: (action) -> $('#search-container')[action]()

-    search:
-      container: -> $('#results')
-      form: (action) -> $('#search-container')[action]()
+  loadingBar: (action) -> $('.pace')[action]()

-    loadingBar: (action) -> $('.pace')[action]()
+  context: ->
+    # get the context from the first class name of body
+    # https://github.com/TryGhost/Ghost/wiki/Context-aware-Filters-and-Helpers
+    className = document.body.className.split(' ')[0].split('-')[0]
+    if className is '' then 'error' else className

-    context: ->
-      # get the context from the first class name of body
-      # https://github.com/TryGhost/Ghost/wiki/Context-aware-Filters-and-Helpers
-      className = document.body.className.split(' ')[0].split('-')[0]
-      if className is '' then 'error' else className
+  app: do -> document.body

-    app: do -> document.body
+  is: (property, value) -> this.app.dataset[property] is value

-    is: (property, value) -> this.app.dataset[property] is value
+  timeAgo: (selector) ->
+    $(selector).each ->
+      postDate = $(this).html()
+      postDateInDays = Math.floor((Date.now() - new Date(postDate)) / 86400000)

-    timeAgo: (selector) ->
-      $(selector).each ->
-        postDate = $(this).html()
-        postDateInDays = Math.floor((Date.now() - new Date(postDate)) / 86400000)
+      if postDateInDays is 0 then postDateInDays = 'today'
+      else if postDateInDays is 1 then postDateInDays = 'yesterday'
+      else postDateInDays = "#{postDateInDays} days ago"

-        if postDateInDays is 0 then postDateInDays = 'today'
-        else if postDateInDays is 1 then postDateInDays = 'yesterday'
-        else postDateInDays = "#{postDateInDays} days ago"
+      $(this).html(postDateInDays)
+      $(this).mouseover -> $(this).html postDate
+      $(this).mouseout -> $(this).html postDateInDays

-        $(this).html(postDateInDays)
-        $(this).mouseover -> $(this).html postDate
-        $(this).mouseout -> $(this).html postDateInDays
-
-    device: ->
-      w = window.innerWidth
-      h = window.innerHeight
-      return 'mobile' if (w <= 480)
-      return 'tablet' if (w <= 1024)
-      'desktop'
+  device: ->
+    w = window.innerWidth
+    h = window.innerHeight
+    return 'mobile' if (w <= 480)
+    return 'tablet' if (w <= 1024)
+    'desktop'


:new: Add second parameter to Message View initialize

--- lib/views/message.coffee
+++ lib/views/message.coffee
@@ -1,5 +1,7 @@
+# This file is imported in views/panel
+
 class Message extends HTMLElement
-  initialize: (message)->
+  initialize: (message, addPath)->
     @message = message

     # The ribbon


nevermind, _dont_ apply the encoder when decoding hasMany relations

--- src/model/associations/has_many_association.coffee
+++ src/model/associations/has_many_association.coffee
@@ -47,13 +47,9 @@
       recordsToMap = []
       recordsToAdd = []

-      primaryKeyAttribute = relatedModel.primaryKey
-      primaryKeyDecoder = relatedModel.prototype._batman.get("encoders").get(primaryKeyAttribute).decode
-
       for jsonObject in data
-        id = jsonObject[primaryKeyAttribute]
-        decodedId = primaryKeyDecoder(id)
-        record = relatedModel._loadIdentity(decodedId)
+        id = jsonObject[relatedModel.primaryKey]
+        record = relatedModel._loadIdentity(id)

         if record?
           recordsToAdd.push(record)


Fix freezing enemies upon death

Fix freezing enemies upon death

--- src/lib/script_modules/entity.coffee
+++ src/lib/script_modules/entity.coffee
@@ -519,7 +519,6 @@
         })
       else
         { x, y } = @location()()
-        #@decoy.removeComponent('ViewportFixed')
         @decoy.attr(
           x: x
           y: y
@@ -527,8 +526,10 @@
           health: 1
           defaultSpeed: @entity.defaultSpeed
         )
-      @decoy.removeComponent('BurstShot')
-      @decoy.removeComponent('Hostile')
+
+      @decoy.removeComponent('BurstShot') if @decoy.has('BurstShot')
+      @decoy.removeComponent('Hostile') if @decoy.has('Hostile')
+
       @decoy.updatedHealth()
       if @entity.xFlipped
         @decoy.flipX()


fix color comparisson

fix color comparisson

--- source/javascripts/sql_joins.coffee
+++ source/javascripts/sql_joins.coffee
@@ -112,7 +112,7 @@
         if @_isSelectedCircle(obj) then '1' else '0'
     @_selectJoinInfo(sqlState.join('.'))

-  _isSelectedCircle: (selectObj) => Snap.getRGB(selectObj.attr('fill')).toString() is Snap.getRGB('rgb(194, 88, 39)').toString()
+  _isSelectedCircle: (selectObj) => Snap.getRGB(selectObj.attr('fill')).hex is Snap.getRGB('rgb(194, 88, 39)').hex

   _selectJoinInfo: (state) =>
     sqlJoinInfo = @_sqlJoinsData[state]


Add more test

Add more test

--- spec/CommentCoreLibrary_spec.coffee
+++ spec/CommentCoreLibrary_spec.coffee
@@ -1,12 +1,84 @@
 'use strict'
 describe 'CommentManager', ->
-  manager = null
+  manager = stage = cmt = c1 = c2 = c3 = c4 = c5 = null

   describe 'instance API', ->
     beforeEach ->
-      manager = new CommentManager(window)
+      c1 = stime: 1
+      c2 = stime: 2, date: '2014-07-12T04:35:55.624Z'
+      c3 =
+        stime: 2
+        date: '2014-07-12T04:35:55.626Z'
+        dbid: '53c0bb2b6465625061b40698'
+      c4 =
+        stime: 2
+        date: '2014-07-12T04:35:55.626Z'
+        dbid: '53c0bb2b6465625061b40700'
+      c5 =
+        stime: 2
+        date: '2014-07-12T04:35:55.626Z'
+        dbid: '53c0bb2b6465625061b40700'
+      cmt =
+        stime: 124900
+        color: '#fff'
+        mode: 1
+        size: 25
+        hash: '53c0bb2b6465625061b40700'
+        date: '2014-07-12T04:35:55.624Z'
+        position: 13600
+      stage = document.createElement 'DIV'
+      manager = new CommentManager(stage)
+      manager.init()

-    'load start stop insert send clear time'.split(' ').forEach (method)->
+    'addEventListener clear dispatchEvent finish init
+    insert load onTimerEvent rescale seek send sendComment
+    setBounds start stop time validate'.split(/\s/).forEach (method)->
+
       it "has method: '#{method}'", ->
         expect(typeof manager[method]).toBe 'function'

+    it 'sets the stage', ->
+      expect(manager.stage).toBe stage
+
+    describe '.load', ->
+      it 'loads specific comment' , ->
+        expect(manager.timeline).toEqual []
+        manager.load [cmt]
+        expect(manager.timeline).toEqual [cmt]
+
+      it 'sorts the comments', ->
+        manager.load [ c5, c2, c4, c1, c3 ]
+        expect(manager.timeline).toEqual [c1, c2, c3, c4, c5]
+
+    describe '.send', ->
+      it 'sends to runline' , ->
+        expect(manager.runline.length).toBe 0
+        manager.send cmt
+        expect(manager.runline.length).toBe 1
+
+    describe '.start', ->
+      it 'starts the timer', ->
+        manager.start()
+        manager.start()
+        # TODO: figure out how to test the timer
+        # maybe just add spy on window.setInterval
+
+    describe '.stop', ->
+      it 'stops the timer', ->
+        manager.stop()
+        # TODO: figure out how to test the timer
+        # maybe just add spy on window.clearInterval
+
+    describe '.clear', ->
+      it 'clears', ->
+        manager.send cmt
+        expect(manager.runline.length).toBe 1
+        manager.clear()
+        expect(manager.runline.length).toBe 0
+
+    describe '.insert', ->
+      it 'inserts to right position', ->
+        manager.load [c3, c5]
+        expect(manager.timeline).toEqual [c3, c5]
+        manager.insert c4
+        expect(manager.timeline).toEqual [c3, c4 , c5]


Need to wait for new api

Need to wait for new api

--- spec/highlight-selected-spec.coffee
+++ spec/highlight-selected-spec.coffee
@@ -35,14 +35,14 @@
           .then ({mainModule}) ->
             highlightSelected = mainModule

-      if hasMinimap
-        waitsForPromise ->
-          atom.packages.activatePackage('minimap').then ({mainModule}) ->
-            minimapModule = mainModule
-        waitsForPromise ->
-          atom.packages.activatePackage('minimap-highlight-selected')
-            .then ({mainModule}) ->
-              minimapHS = mainModule
+      # if hasMinimap
+      #   waitsForPromise ->
+      #     atom.packages.activatePackage('minimap').then ({mainModule}) ->
+      #       minimapModule = mainModule
+      #   waitsForPromise ->
+      #     atom.packages.activatePackage('minimap-highlight-selected')
+      #       .then ({mainModule}) ->
+      #         minimapHS = mainModule

       waitsForPromise ->
         atom.workspace.open('sample.coffee').then(
@@ -205,19 +205,19 @@
           expect(editorElement.querySelectorAll('.highlight-selected.light-theme
             .region')).toHaveLength(4)

-    if hasMinimap
-      describe "minimap highlight selected still works", ->
-        beforeEach ->
-          editor = atom.workspace.getActiveTextEditor()
-          minimap = minimapModule.minimapForEditor(editor)
-
-          spyOn(minimap, 'decorateMarker').andCallThrough()
-          range = new Range(new Point(8, 2), new Point(8, 8))
-          editor.setSelectedBufferRange(range)
-          advanceClock(20000)
-
-        it 'adds a decoration for the selection in the minimap', ->
-          expect(minimap.decorateMarker).toHaveBeenCalled()
+    # if hasMinimap
+    #   describe "minimap highlight selected still works", ->
+    #     beforeEach ->
+    #       editor = atom.workspace.getActiveTextEditor()
+    #       minimap = minimapModule.minimapForEditor(editor)
+    #
+    #       spyOn(minimap, 'decorateMarker').andCallThrough()
+    #       range = new Range(new Point(8, 2), new Point(8, 8))
+    #       editor.setSelectedBufferRange(range)
+    #       advanceClock(20000)
+    #
+    #     it 'adds a decoration for the selection in the minimap', ->
+    #       expect(minimap.decorateMarker).toHaveBeenCalled()

   describe "when opening a php file", ->
     beforeEach ->


Added admin management page to the navbar.

--- web/coffee/navbar.coffee
+++ web/coffee/navbar.coffee
@@ -39,7 +39,7 @@
   Team: "/team"
   Chat: "/chat"
   Scoreboard: "/scoreboard"
-  About:
+  About:
     About: "/about"
     News: "/news"
   Account:
@@ -52,6 +52,9 @@
   News: "/news"
   Scoreboard: "/scoreboard"
   Login: "/login"
+
+adminLoggedIn =
+  Management: "/management"

 loadNavbar = (renderNavbarLinks, renderNestedNavbarLinks) ->

@@ -77,6 +80,10 @@
             navbarLayout.links = userLoggedIn
          else
             navbarLayout.links = userLoggedInNoCompetition
+
+        if data.data["admin"]
+           $.extend navbarLayout.links, adminLoggedIn
+
     $("#navbar-links").html renderNavbarLinks(navbarLayout)
     $("#navbar-item-logout").on("click", logout)


bugfix path.resolve in linda-server command  #2

--- bin/linda-server/app.coffee
+++ bin/linda-server/app.coffee
@@ -24,7 +24,7 @@

 http = require('http').Server(app)
 io = require('socket.io')(http)
-linda = require(path.resolve()).Server.listen(io: io, server: http)
+linda = require(path.resolve __dirname, '../../').Server.listen(io: io, server: http)
 app.set 'socket.io', io
 app.set 'config', config
 app.set 'package', package_json


add mark-button to point-tool

add mark-button to point-tool

--- app/assets/javascripts/components/mark/tools/point-tool/index.cjsx
+++ app/assets/javascripts/components/mark/tools/point-tool/index.cjsx
@@ -2,6 +2,7 @@
 DrawingToolRoot = require './root'
 Draggable       = require 'lib/draggable'
 DeleteButton    = require './delete-button'
+MarkButtonMixin = require 'lib/mark-button-mixin'

 RADIUS = 10
 SELECTED_RADIUS = 20
@@ -15,6 +16,8 @@
 module.exports = React.createClass
   displayName: 'SuperAwesomePointTool'

+  mixins: [MarkButtonMixin]
+
   statics:
     defaultValues: ({x, y}) ->
       {x, y}
@@ -26,6 +29,10 @@
     theta = (DELETE_BUTTON_ANGLE) * (Math.PI / 180)
     x: (SELECTED_RADIUS / @props.xScale) * Math.cos theta
     y: -1 * (SELECTED_RADIUS / @props.yScale) * Math.sin theta
+
+  getMarkButtonPosition: ->
+    x: SELECTED_RADIUS/@props.xScale
+    y: SELECTED_RADIUS/@props.yScale

   render: ->
     averageScale = (@props.xScale + @props.yScale) / 2
@@ -64,6 +71,8 @@
           <DeleteButton tool={this} getDeleteButtonPosition={@getDeleteButtonPosition} />
         }

+        { if @props.selected then @renderMarkButton() }
+
       </g>
     </g>


#162331383 added else for checkboxes set lookup values to false

--- app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
+++ app/assets/javascripts/hanuman/hanuman-conditional-logic.js.coffee
@@ -186,6 +186,9 @@
         $ruleElement.find('input[type="checkbox"]').each ->
           if selectedOptions.indexOf($(this).attr('value')) != -1
             $(this).prop("checked", true).trigger('change')
+          else
+            $(this).prop("checked", false).trigger('change')
+

       when 'chosenmultiselect'
         selectedOptions = value.split(",")


[skip] Limited the Planning Poker queue to the tickets that don't have estimates (2m)

--- app/assets/javascripts/houston-scheduler/views/project_view.coffee
+++ app/assets/javascripts/houston-scheduler/views/project_view.coffee
@@ -32,7 +32,7 @@

   ticketsWaitingForMyEffortEstimate: ->
     myEstimateKey = "estimatedEffort[#{window.user.id}]"
-    @tickets.unresolved().select (ticket)-> !ticket.get(myEstimateKey)
+    _.select @ticketsWaitingForEffortEstimate(), (ticket)-> !ticket.get(myEstimateKey)

   showTab: (view)->


A bit of padding in the navbar

A bit of padding in the navbar

--- app/assets/javascripts/rglossa/components/top/navbar.js.jsx.coffee
+++ app/assets/javascripts/rglossa/components/top/navbar.js.jsx.coffee
@@ -3,7 +3,7 @@
 window.Navbar = React.createClass
   render: ->
     `

-

+

           Glossa


Added an open option to register

Added an open option to register

--- command-register.coffee
+++ command-register.coffee
@@ -12,9 +12,11 @@
       .option '-s, --server <host[:port]>', 'Meshblu host'
       .option '-t, --type <device:type>', 'Device type'
       .option '-d, --data <\'{"name":"Some Device"}\'>', 'Device Data [JSON]'
+      .option '-o, --open', "Make the device open to everyone"
       .parse process.argv

       @data = JSON.parse(commander.data) if commander.data?
+      @isOpen = commander.open?

   parseConfig: =>
     {server, port} = @parseServer()
@@ -44,8 +46,22 @@
     @conn.on 'notReady', @onReady

   onReady: (credentials) =>
-    deviceParams = discoverWhitelist: [], configureWhitelist: [], receiveWhitelist: [], type: @config.type
-    _.extend(deviceParams, @data) if @data?
+    lockedDownParams =
+      discoverWhitelist: [],
+      configureWhitelist: [],
+      receiveWhitelist: []
+
+    openParams =
+      discoverWhitelist: ['*']
+      configureWhitelist: ['*']
+      receiveWhitelist: ['*']
+
+    deviceParams =
+      type: @config.type
+
+    _.extend deviceParams, lockedDownParams unless @isOpen
+    _.extend deviceParams, openParams if @isOpen
+    _.extend deviceParams, @data if @data?

     @conn.register deviceParams, (credentials) =>
       @config.uuid = credentials.uuid


adding newlines after error stacktrace in REPL.

--- repl.coffee
+++ repl.coffee
@@ -12,6 +12,10 @@
 # Start by opening up **stdio**.
 stdio = process.openStdin()

+# Log an error.
+error = (err) ->
+  stdio.write (err.stack or err.toString()) + '\n\n'
+
 # Quick alias for quitting the REPL.
 helpers.extend global, quit: -> process.exit(0)

@@ -23,12 +27,11 @@
     val = CoffeeScript.eval buffer.toString(), bare: on, globals: on, fileName: 'repl'
     console.log val if val isnt undefined
   catch err
-    stdio.write err.stack or err.toString()
+    error err
   repl.prompt()

 # Make sure that uncaught exceptions don't kill the REPL.
-process.on 'uncaughtException', (err) ->
-  stdio.write err.stack or err.toString()
+process.on 'uncaughtException', error

 # Create the REPL by listening to **stdin**.
 repl = readline.createInterface stdio


cleanup

cleanup

--- client/apps/edit/components/content2/section_controls/index.coffee
+++ client/apps/edit/components/content2/section_controls/index.coffee
@@ -27,7 +27,7 @@
     # used for classic layout only
     sectionType = @props.section.get('type')
     sectionLayout = @props.section.get('layout')
-    if @props.isHero or (sectionType is 'embed' and sectionLayout is 'overflow')
+    if @props.isHero
       width = 1100
     else if sectionLayout?.includes('overflow') or sectionType is 'image_set'
       width = 940


comments

comments

--- client/landing/app/CommonViews/opinions/opinionlistitemview.coffee
+++ client/landing/app/CommonViews/opinions/opinionlistitemview.coffee
@@ -14,7 +14,7 @@

     # FIXME
     # this is really lazy loading. opinionsByRange should yield
-    # the comments by default
+    # the comments by default. fetchOpinion is not capable of doing that.

     if data.repliesCount and not data.replies? # comments are not in data
       data.commentsByRange                   # so we fetch them manually
@@ -30,6 +30,7 @@
           for comment in comments       # and add them to the commentBox
             @commentBox.commentList.addItem comment

+    # bounce the RefreshTeaser event
     @commentBox.on "RefreshTeaser",=>
       @parent.emit "RefreshTeaser"


added callback to terminal.runCommand

added callback to terminal.runCommand

--- client/landing/app/CommonViews/workspace/panes/terminalpane.coffee
+++ client/landing/app/CommonViews/workspace/panes/terminalpane.coffee
@@ -19,9 +19,13 @@
     {command} = @getOptions()
     @runCommand command if command

-  runCommand: (command) ->
+  runCommand: (command, callback) ->
     return unless command
-    return @remote.input "#{command}\n"  if @remote
+    if @remote
+      if callback
+        @webterm.once "WebTermEvent", callback
+        command += ";echo $?|kdevent"
+      return @remote.input "#{command}\n"

     if not @remote and not @triedAgain
       @utils.wait 2000, =>


Fix lambda error.

Fix lambda error.

--- models/repository.coffee
+++ models/repository.coffee
@@ -24,7 +24,7 @@

 exports.Repository = mongoose.model 'Repository', exports.RepositorySchema

-exports.Repository.prototype.toJSON = toJSON () ->
+exports.Repository.prototype.toJSON = ->
   obj = this.toObject
   obj.builds = obj.builds.reverse()
   obj


removed pointless jquery selector caching

--- oridomi.coffee
+++ oridomi.coffee
@@ -572,7 +572,6 @@
     @el.innerHTML   = ''
     @el.appendChild @_cloneEl
     @el.appendChild @_stageHolder
-    @$el = $ @el if $
     # An effect method is called since touch events rely on using the last
     # method called.
     @accordion 0


Store menu template even if window isn't focused

update may be called before the window gains focus to store its
template so it is updated correcltly once the window gains focus.

--- src/browser/application-menu.coffee
+++ src/browser/application-menu.coffee
@@ -22,20 +22,18 @@
   # keystrokesByCommand - An Object where the keys are commands and the values
   #                       are Arrays containing the keystroke.
   update: (window, template, keystrokesByCommand) ->
-    return unless window is @lastFocusedWindow
-
     @translateTemplate(template, keystrokesByCommand)
     @substituteVersion(template)
     @windowTemplates.set(window, template)
-    @setActiveTemplate(template)
-
-    @showUpdateMenuItem(global.atomApplication.autoUpdateManager.getState())
+    @setActiveTemplate(template) if window is @lastFocusedWindow

   setActiveTemplate: (template) ->
     unless _.isEqual(template, @activeTemplate)
       @activeTemplate = template
       @menu = Menu.buildFromTemplate(_.deepClone(template))
       Menu.setApplicationMenu(@menu)
+
+    @showUpdateMenuItem(global.atomApplication.autoUpdateManager.getState())

   # Register a BrowserWindow with this application menu.
   addWindow: (window) ->


[options] clean-up faulty manifests before displaying

--- src/coffee/options/manifests.coffee
+++ src/coffee/options/manifests.coffee
@@ -90,6 +90,12 @@

                 value.sources.each (source) ->
                     module.log.log '-- Source key %s', source.key
+
+                    # clean-up info to show, in case the manifest is faulty
+                    source.faction = 'unknown' unless source.faction?
+                    source.players = 0 unless Object.isNumber source.players
+                    source.tag = source.key if Object.has(source, 'key') and not Object.has(source, 'tag')
+                    source.version = 0 unless source.version?

                     sourceList.push($ '<li>'
                         .addClass 'list-group-item source faction-' + source.faction


Corrige buyButton com redirect=false sem Sku selecionado

--- src/coffee/portal-buy-button.coffee
+++ src/coffee/portal-buy-button.coffee
@@ -126,8 +126,10 @@

 		return url

+	valid: => !!(@sku or @options.multipleProductIds)
+
 	update: =>
-		url = if @sku or @options.multipleProductIds then @getURL() else "javascript:alert('#{@options.errorMessage}');"
+		url = if @valid() then @getURL() else "javascript:alert('#{@options.errorMessage}');"
 		@element.attr('href', url)
 		@element.show()

@@ -137,7 +139,7 @@
 			@element.hide()

 	buyButtonHandler: (evt) =>
-		return true if @options.redirect
+		return true if @options.redirect or not @valid()

 		$(window).trigger 'vtex.modal.hide'
 		$.get(@getURL())


Fix url to solve vector conflicts

Fix url to solve vector conflicts

--- admin/static/coffee/resolve_issues.coffee
+++ admin/static/coffee/resolve_issues.coffee
@@ -160,7 +160,7 @@
         on_submit: ->
             super
             $.ajax
-                url: "/ajax/" + @resolution_url
+                url: "/ajax/semilattice/" + @resolution_url
                 type: 'POST'
                 contentType: 'application/json'
                 data: JSON.stringify(@final_value)
@@ -349,7 +349,7 @@

             # grab possible conflicting values
             $.ajax
-                url: '/ajax/' + get_resolution_url()
+                url: '/ajax/semilattice/' + get_resolution_url()
                 type: 'GET'
                 contentType: 'application/json'
                 async: false


Add axes to inspector

Add axes to inspector

--- src/public/scripts/app.inspector.coffee
+++ src/public/scripts/app.inspector.coffee
@@ -82,6 +82,7 @@
 			# Create scene, camera and renderer.
 			@scene = new Three.Scene()
 			@camera = new Three.PerspectiveCamera(viewAngle, aspectRatio, nearClip, farClip)
+			@camera.position = new Three.Vector3()
 			@renderer = new Three.WebGLRenderer()

 			@renderer.setSize(width, height)
@@ -109,6 +110,35 @@
 			@stats.domElement.style.top = '0px'
 			@stats.domElement.style.left = '0px'
 			container.appendChild(@stats.domElement)
+
+			# Add axes
+			xStart = new Three.Vector3(5000, 0, 0)
+			xEnd = new Three.Vector3(-5000, 0, 0)
+			yStart = new Three.Vector3(0, 5000, 0)
+			yEnd = new Three.Vector3(0, -5000, 0)
+			zStart = new Three.Vector3(0, 0, 5000)
+			zEnd = new Three.Vector3(0, 0, -5000)
+
+			xGeometry = new Three.Geometry()
+			xGeometry.vertices.push(xStart)
+			xGeometry.vertices.push(xEnd)
+			xMaterial = new Three.LineBasicMaterial(color: 0xff0000)
+			xLine = new Three.Line(xGeometry, xMaterial)
+			@scene.add(xLine)
+
+			yGeometry = new Three.Geometry()
+			yGeometry.vertices.push(yStart)
+			yGeometry.vertices.push(yEnd)
+			yMaterial = new Three.LineBasicMaterial(color: 0x00ff00)
+			yLine = new Three.Line(yGeometry, yMaterial)
+			@scene.add(yLine)
+
+			zGeometry = new Three.Geometry()
+			zGeometry.vertices.push(zStart)
+			zGeometry.vertices.push(zEnd)
+			zMaterial = new Three.LineBasicMaterial(color: 0x0000ff)
+			zLine = new Three.Line(zGeometry, zMaterial)
+			@scene.add(zLine)

 			# Various callbacks and the like.
 			window.requestAnimationFrame(@update)


log: test without case in regex

log: test without case in regex

--- client/Terminal/sessionstackview.coffee
+++ client/Terminal/sessionstackview.coffee
@@ -32,7 +32,7 @@
       @hide()
       @loader.hide()

-      unless (/No sessions available/.test(err.message))
+      unless (/no sessions available/i.test(err.message))
         KD.utils.warnAndLog "terminal: webtermGetSessions error",
           {reason:err?.message, hostnameAlias:@getOptions().alias}


some unnecessary code removed

some unnecessary code removed

--- client/app/MainApp/book/bookview.coffee
+++ client/app/MainApp/book/bookview.coffee
@@ -159,10 +159,9 @@

   fillPrevPage:->
     if BookView.navigateNewPages
-      @getNewPages (pages)=>
+      @getNewPages =>
         prev = @prevUnreadPage()
         @fillPage prev if prev?
-        @checkBoundaries pages
       return

     return if @currentIndex - 1 < 0
@@ -170,10 +169,9 @@

   fillNextPage:->
     if BookView.navigateNewPages
-      @getNewPages (pages)=>
+      @getNewPages =>
         next = @nextUnreadPage()
         @fillPage next if next?
-        @checkBoundaries pages
       return

     return if __bookPages.length is @currentIndex + 1


Klient's new storage api helpers for client side

Allows to set JSON objects as value

--- client/app/lib/kite/kites/klient.coffee
+++ client/app/lib/kite/kites/klient.coffee
@@ -137,6 +137,34 @@
       @syncSessionsWithLocalStorage()

+  storageSet: (key, value) ->
+
+    if not key or not value
+      return  Promise.reject 'key and value required'
+
+    value = (JSON.stringify value) or ''
+    @tell 'storage.set', {key, value}
+
+
+  storageGet: (key) ->
+
+    return  Promise.reject 'key required'  unless key
+
+    @tell 'storage.get', {key}
+
+    .then (value)->
+      try value = JSON.parse value
+      return value
+    .catch (err)->
+      return null
+
+
+  storageDelete: (key)->
+
+    return  Promise.reject 'key required'  unless key
+
+    @tell 'storage.delete', {key}
+

   getLocalStorage = ->


Adding video link to home

Adding video link to home

--- client/app/views/pages/home.tmpl.coffee
+++ client/app/views/pages/home.tmpl.coffee
@@ -29,6 +29,14 @@
                 a({href: '/sign_up'}, icon('sign-up'), ' Sign Up')
             ) unless data.currentUserID
             p(
+                'What is Sagefy? '
+                a(
+                    {href: 'https://www.youtube.com/watch?v=LKUMexJXGDQ'}
+                    'Watch this 3 minute YouTube video'
+                )
+                '.'
+            )
+            p(
                 {style: {
                     background: 'rgb(255, 236, 239)'
                     color: 'rgb(197, 124, 139)'


Editor: Use AceApplicationTabView. It handles closing of unsaved files.

--- client/ide/views/tabview/ideview.coffee
+++ client/ide/views/tabview/ideview.coffee
@@ -1,6 +1,8 @@
 class IDE.IDEView extends IDE.WorkspaceTabView

   constructor: (options = {}, data) ->
+
+    options.tabViewClass = AceApplicationTabView

     super options, data

@@ -57,6 +59,7 @@
     paneOptions =
       name      : file.name
       editor    : editorPane
+      aceView   : editorPane.aceView # this is required for ace app. see AceApplicationTabView:6

     editorPane.once 'EditorIsReady', ->
       editorPane.aceView.ace.on 'ace.change.cursor', (cursor) ->


Test Leave Team Modal

Test Leave Team Modal

--- client/test/lib/dashboard/myteam.coffee
+++ client/test/lib/dashboard/myteam.coffee
@@ -61,6 +61,24 @@
         .waitForElementVisible  '.kdnotification', 5000
         .assert.containsText    '.kdnotification.main', 'Check your email'
         .pause 5000
+
+        .click leaveTeamButton
+        .waitForElementVisible '.kdmodal.kddraggable', 5000
+        .pause 2000
+        .clearValue passwordSelector
+        .setValue passwordSelector, '1234'
+        .click confirmButton
+        .waitForElementVisible  '.kdnotification', 20000
+        .assert.containsText    '.kdnotification.main', 'Current password cannot be confirmed'
+        .pause 5000
+
+        .click leaveTeamButton
+        .waitForElementVisible '.kdmodal.kddraggable', 5000
+        .pause 2000
+        .clearValue passwordSelector
+        .setValue passwordSelector, targetUser1.password
+        .click confirmButton
+        .assert.urlContains helpers.getUrl(yes)

       # .click saveChangesButton
       # .waitForElementNotPresent '.kdnotification', 5000