statuses saved

statuses saved

--- _temp/saveStatus.coffee
+++ _temp/saveStatus.coffee
@@ -1,75 +1,61 @@
-#db.run "DROP TABLE #{config.database.statuses_table}"
-# db.run "CREATE TABLE #{config.database.statuses_table} (status TEXT, date TEXT)"
-#
-# stmt = db.prepare "INSERT INTO #{config.database.statuses_table} VALUES (?, ?)"
-# stmt.run "Этого числа, в 1995, появились Герои Меча и Магии", "31.08"
-# stmt.run "В этот день, в 1998, вышла Half Life", "8.11"
-# stmt.run "В этот день, 1997 года, вышел Fallout", "30.9"
-# stmt.run "В этот день, 2007 года, Portal", "10.10"
-# stmt.run "В этот день, в 1996, появилась Neverhood", "19.9"
-# stmt.run "В этот день, в 1993, вышел DOOM", "10.12"
-# stmt.run "В этот день, в 1991, вышла Civilization", "15.10"
-# stmt.run "В этот день, в 1998, вышел Star Craft", "31.3"
-# stmt.run "В этот день, в 2002, вышли Космические рейнджеры", "23.12"
-# stmt.run "В этот день, в 1994, вышел Warcraft", "15.1"
-# stmt.run "В этот день, в 1996, вышла Diablo", "30.11"
-# stmt.run "В этот день, в 1996, вышел Duke Nukem 3D", "29.1"
-# stmt.run "В этот день, в 2002, вышел Morrowind", "1.5"
-# stmt.run "В этот день, в 1993, вышла X-COM UFO Defense", "31.12"
-# stmt.run "В этот день, в 2000, вышел Counter Strike", "8.11"
-# stmt.run "В этот день, в 1997, вышел Carmageddon", "30.6"
-# stmt.run "В этот день, в 1997, вышел Full Throttle", "30.6"
-# stmt.run "В этот день, в 1997, вышла Age of Empires", "26.10"
-# stmt.run "В этот день, в 1996, вышел Red Alert", "22.11"
-# stmt.run "В этот день, в 2001, вышел Max Payne", "24.7"
-# stmt.run "В этот день, в 2001, вышли Казаки", "12.4"
-# stmt.run "В этот день, в 1984, появился Тетрис", "6.6"
-# stmt.run "В этот день, в 2002, вышла Mafia", "28.8"
-# stmt.run "В этот день, в 1996, вышел Quake", "22.6"
-# stmt.run "В этот день, в 1994, вышел Need for Speed", "10.9"
-# stmt.run "В этот день, в 2014, вышел Dungeon keeper", "29.1"
-# stmt.run "В этот день, в 1999, вышел Unreal Tournament", "30.11"
-# stmt.run "В этот день, в 2001, вышел Return to Castle Wolfenstein", "20.11"
-# stmt.run "В этот день, в 2000, вышел Deus Ex", "22.6"
-# stmt.run "В этот день, в 1989, вышла Simcity", "1.1"
-# stmt.run "В этот день, в 2001, вышла Black & White", "25.3"
-# stmt.run "В этот день, в 2001, вышла Arcanum", "21.8"
-# stmt.run "В этот день, в 1996, вышла Settlers II" -  "31.8"
-# stmt.run "В этот день, в 2007, вышел S.T.A.L.K.E.R.", "20.3"
-# stmt.run "В этот день, в 2001, вышел Serious Sam", "20.3"
-# stmt.run "В этот день, в 2000, вышел Hitman", "19.11"
-# stmt.run "В этот день, в 2011, вышел Minecraft", "18.11"
-# stmt.run "В этот день, в 2002, вышла Syberia", "9.1"
-# stmt.run "В этот день, в 1995, вышла Descent", "28.2"
-# stmt.run "В этот день, в 2001, вышла Stronghold", "21.10"
-# stmt.run "В этот день, в 2008, вышел Braid", "6.8"
-# stmt.run "В этот день, в 1997, вышла Grand Theft Auto", "8.11"
-# stmt.run "В этот день, в 1999, вышли Аллоды II: Повелитель душ", "вышла 31.7"
-# stmt.run "В этот день, в 2001, вышла Gothic", "15.3"
-# stmt.run "В этот день, в 1996, вышла Blood", "14.2"
-# stmt.run "В этот день, в 1999, вышла Planescape: Torment "- "12.12"
-# stmt.run "В этот день, в 2005, вышла Fahrenheit", "16.9"
-# stmt.run "В этот день, в 1983, вышел Bomber Man", "28.4"
-# stmt.run "В этот день, в 2007, вышел Mass effect", "20.11"
-# stmt.run "В этот день, в 2002, вышел Neverwinter nights", "18.6"
-# stmt.run "В этот день, в 1991, вышел Sonic the Hedgehog", "23.6"
-# stmt.run "В этот день, в 2009, вышла Plants vs Zombies", "5.5"
-# stmt.run "В этот день, в 1993, вышла Myst", "24.9"
-# stmt.run "В этот день, в 1994, вышла Earthworm Jim", "12.10"
-# stmt.run "В этот день, в 2009, вышла Машинариум", "16.10"
-# stmt.run "В этот день, в 1999, вышла Disciples", "27.9"
-# stmt.run "В этот день, в 1999, вышла American McGee’s Alice", "13.8"
-# stmt.run "В этот день, в 1998, вышел Grim Fandango", "30.10"
-# stmt.run "В этот день, в 1995, вышел Terminal Velocity", "1.5"
-# stmt.run "В этот день, в 2001, вышел Oni", "29.1"
-# stmt.run "В этот день, в 2000, вышла Total War", "14.6"
-# stmt.run "В этот день, в 1998, вышла Knights and Merchants", "1.10"
-# stmt.run "В этот день, в 1997, вышла Total Annihilation", "25.9"
-# stmt.run "В этот день, в 2008, вышла Mirror's Edge", "12.11"
-# stmt.run "В этот день, в 1996, вышла Tomb Raider", "15.11"
-# stmt.run "В этот день, в 2003, вышла Command & Conquer: Generals", "14.2"
-# stmt.run "В этот день, в 1998, вышли Вангеры", "19.6"
-# stmt.run "В этот день, в 2000, вышла No One Lives Forever", "9.11"
-# stmt.run "В этот день, в 1999, вышел Silent Hill", "31.1"
-#
-# do stmt.finalize
+###
+01.01.1989 вышла Simcity	                1.1
+09.01.2002 вышла Syberia	                9.1
+15.01.1994 вышел Warcraft	                15.1
+29.01.1996 вышел Duke Nukem 3D	            29.1
+
+14.02 - день рождения YouTube	            14.2
+28.02.1995 вышла Descent	                28.2
+
+15.03.2001 вышла Gothic	                    15.3
+20.03.2007 вышел S.T.A.L.K.E.R.	            20.3
+25.03.2001 вышла Black & White	            25.3
+31.03.1998 вышел Star Craft	                31.3
+
+01.04.1976 была основана Apple              1.4
+04.04.1975 была основана Microsoft          4.4
+12.04 День космонавтики                     12.4
+28.04.1983 вышел Bomber Man	                28.4
+
+01.05.2002 вышел Morrowind	                1.5
+05.05.2009 вышла Plants vs Zombies	        5.5
+
+06.06.1984 появился Тетрис	                6.6
+18.06.2002 вышел Neverwinter nights         8.6
+22.06.1996 вышел Quake	                    22.6
+23.06.1991 вышел Sonic the Hedgehog         23.6
+30.06.1997 вышел Full Throttle	            30.6
+
+24.07.2001 вышел Max Payne	                24.7
+31.07.1999 вышли Аллоды II: Повелитель душ	31.7
+
+06.08.2008 вышел Braid	                    6.8
+21.08.2001 вышел Arcanum	                21.8
+24.08.1996 была основана Valve              24.8
+28.08.2002 вышла Mafia	                    28.8
+
+04.09.1998 был основан Google               4.9
+10.09.1994 вышел Need for Speed	            10.9
+12.09.2003 появился Steam                   12.9
+16.09.2005 вышла Fahrenheit	                16.9
+19.09.1996 появилась Neverhood	            19.9
+30.09.1997 вышел Fallout	                30.9
+
+10.10.2007 вышел Portal	                    10.10
+15.10.1991 вышла Civilization	            15.10
+21.10.2001 вышла Stronghold	                21.10
+26.10.1997 вышла Age of Empires	            26.10
+28.10 - День рождения Билла Гейтса          28.10
+
+03.11 - день рождения Гейба Ньюэлла         3.11
+08.11.1998 вышла Half Life	                8.11
+18.11.2011 вышел Minecraft	                18.11
+19.11.2000 вышел Hitman	                    19.11
+20.11.2007 вышел Mass effect	            20.11
+22.11.1996 вышел Red Alert	                22.11
+30.11.1996 вышла Diablo	                    30.11
+
+10.12.1993 вышел DOOM	                    10.12
+23.12.2002 вышли Космические рейнджеры	    23.12
+31.12.1993 вышла X-COM UFO Defense	        31.12
+###


Updating langauge.

Updating langauge.


Allow TODO-like keywords to match inside comments

--- grammars/viml.cson
+++ grammars/viml.cson
@@ -35,8 +35,10 @@
 	comments:
 		patterns: [{
 			name: "comment.line.quotes.viml"
-			match: '^\\s*(").*$'
-			captures:
+			begin: '^\\s*(")'
+			end:   '$'
+			patterns: [{include: "#todo"}]
+			beginCaptures:
 				1: name: "punctuation.definition.comment.vim"
 		},{
 			name: "comment.inline.quotes.viml"


minor removing commented test that indeed doesn't constitute a problem anymore


Cant change props

Cant change props

--- client/app/components/compose.coffee
+++ client/app/components/compose.coffee
@@ -441,15 +441,16 @@
         getGroupedError error, @state, _.isEmpty

     sendActionMessage: (success) ->
-        return if @props.isSaving
+        return if @state.isSaving
         if (validate = @validateMessage())
             LayoutActionCreator.alertError t 'compose error no ' + validate[1]
             success(null, @state) if _.isFunction success
             return

-        @props.isSaving = true
-        MessageActionCreator.send _.clone(@state), (error, message) =>
-            @props.isSaving = false
+        _message = _.clone @state
+        @state.isSaving = true
+        MessageActionCreator.send _message, (error, message) =>
+            delete @state.isSaving
             if error? or not message?
                 if @state.isDraft
                     msgKo = t "message action draft ko"


See #317. Use Warning notification, improve message for unsupported lang

--- src/beautifiers/index.coffee
+++ src/beautifiers/index.coffee
@@ -217,6 +217,13 @@
         return flatOptions

     ###
+    From https://github.com/atom/notifications/blob/01779ade79e7196f1603b8c1fa31716aa4a33911/lib/notification-issue.coffee#L130
+    ###
+    encodeURI: (str) ->
+        str = encodeURI(str)
+        str.replace(/#/g, '%23').replace(/;/g, '%3B')
+
+    ###

     ###
     getBeautifiers: (language, options) ->
@@ -226,6 +233,9 @@
             _.contains(beautifier.languages, language)
         )

+    ###
+
+    ###
     beautify: (text, allOptions, grammar, filePath) ->
         return new Promise((resolve, reject) =>
             logger.info('beautify', text, allOptions, grammar, filePath)
@@ -348,8 +358,32 @@
               if atom.config.get("atom-beautify.muteUnsupportedLanguageErrors")
                 return resolve(null)
               else
-                reject(new Error("Unsupported language for grammar '#{grammar}' with extension '#{fileExtension}'."))
-
+                repoBugsUrl = pkg.bugs.url
+                # issueTitle = "Add support for language with grammar '#{grammar}' and extension '#{fileExtension}'"
+                # issueBody = """
+                # ### About My Installation
+                # **Atom Version**: #{atom.getVersion()}
+                # **Atom Beautify Version**: #{pkg.version}
+                # **Platform**: #{process.platform}
+                #
+                # ### Example input file:
+                # ```#{fileExtension}
+                # #{text}
+                # ```
+                #
+                # """
+                # requestLanguageUrl = "#{repoBugsUrl}/new?title=#{@encodeURI(issueTitle)}&body=#{@encodeURI(issueBody)}"
+                # detail = "If you would like to request this language be supported please create an issue by clicking request new language support."
+                title = "Atom Beautify could not find a supported beautifier for this file"
+                detail = """
+                Atom Beautify could not determine a supported beautifier to handle this file with grammar \"#{grammar}\" and extension \"#{fileExtension}\". \
+                If you would like to request support for this file and it's language, please create an issue for Atom Beautify at #{repoBugsUrl}
+                """
+                atom?.notifications.addWarning(title, {
+                    detail
+                    dismissable: true
+                })
+                return resolve(null)
         )

     findFileResults: {}


remove cruft test code

remove cruft test code

--- test/bitbucket-pr_test.coffee
+++ test/bitbucket-pr_test.coffee
@@ -133,13 +133,3 @@
       expect( action.color ).to.eql pre.RED
       expect( action.fields[0].title ).to.eql pre.title
       expect( action.fields[1].value ).to.eql '<https://api.bitbucket.org/pullrequest_id|View on Bitbucket>'
-
-
-describe 'bitbucket-pr', ->
-  room = null
-
-  beforeEach ->
-    room = helper.createRoom()
-
-  afterEach ->
-    room.destroy()


syntax tweaks

syntax tweaks

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -483,18 +483,37 @@
     @accordion angle / 10, options

+  _curlDefaults:
+    anchor: 'left'
+    twist: false
+
+
   curl: (angle, options = {}) ->
+    options = extendObj options, @_curlDefaults
     {anchor} = options
     angle = @_normalizeAngle(angle) /  @_getPanelType anchor

+    if anchor isnt @lastAnchor
+      return @reset =>
         @_showStage anchor
+        setTimeout =>
+          @curl angle, options
+        , 0
+
+    @lastAngle = angle = @_normalizeAngle angle
+
+    if anchor is 'left' or anchor is 'right'
+      rotation = [0, 1, 0, angle]
+    else
+      rotation = [1, 0, 0, -angle]
+
     for panel, i in @panels[anchor]
       panel.style[transformProp] = @_transform @_getXy(i, anchor), rotation

     @_callback options

-  setAngles: (angles, axis, options = {}) ->
+  setAngles: (angles, options = {}) ->
     if !Array.isArray angles
       return !silent and console?.warn 'oriDomi: Argument must be an array of angles'


use strict

use strict

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -8,6 +8,7 @@
 * Copyright 2012
 ###

+'use strict'

 root = window
 $ = root.$ or false


removed do

removed do

--- oridomi.coffee
+++ oridomi.coffee
@@ -778,7 +778,7 @@
       hideEl @_stages[@_lastOp.anchor]
       @_lastOp.anchor = anchor
       @_lastOp.reset  = true
-      @_stages[anchor].style[css.transform] = 'translate3d(' + do =>
+      @_stages[anchor].style[css.transform] = 'translate3d(' +
         switch anchor
           when 'left'
             '0, 0, 0)'


add reset flag to lastOp after stageReset

--- oridomi.coffee
+++ oridomi.coffee
@@ -514,9 +514,10 @@
   # wouldn't be called due to no animation taking place. This method reasons if
   # movement has taken place, preventing this pitfall of transition listeners.
   _isIdenticalOperation: (op) ->
-    return false if @lastOp.angle isnt op.angle
-    for k, v of op.options
-      return false if op.options[k] isnt @lastOp.options[k] and k isnt 'callback'
+    return true  unless @lastOp.fn
+    return false if @lastOp.reset
+    return false if @lastOp[key] isnt op[key] for key in ['angle', 'anchor', 'fn']
+    return false if v isnt @lastOp.options[k] and k isnt 'callback' for k, v of op.options
     true

@@ -529,7 +530,7 @@
     else
       @panels[@lastOp.anchor][0].addEventListener css.transitionEnd, @_onTransitionEnd, false

-    @lastOp = operation
+    (@lastOp = operation).reset = false

   # Handler called when a CSS transition ends.
@@ -643,6 +644,7 @@
       @stages[anchor].style.display = 'block'
       @stages[@lastOp.anchor].style.display = 'none'
       @lastOp.anchor = anchor
+      @lastOp.reset  = true

   _stageReset: (anchor, cb) =>


detect browser implementation of grab cursor

--- oridomi.coffee
+++ oridomi.coffee
@@ -89,6 +89,19 @@

 # The default cursor style is set to `grab` to prompt the user to interact with the element.
 [css.grab, css.grabbing] = do ->
+  for prefix in prefixList
+    plainGrab = 'grab'
+    testEl.style.cursor = (grabValue = "-#{ prefix.toLowerCase() }-#{ plainGrab }")
+    # If the cursor was set correctly, return the prefixed pair.
+    return [grabValue, "-#{ prefix.toLowerCase() }-grabbing"] if testEl.style.cursor is grabValue
+  # Otherwise try the unprefixed version.
+  testEl.style.cursor = plainGrab
+  if testEl.style.cursor is plainGrab
+    [plainGrab, 'grabbing']
+  else
+    # Fallback to `move`.
+    ['move', 'move']
+
 # Invoke a functional scope to set a hyphenated version of the transform property.
 css.transformProp = do ->
   # Use a regex to pluck the prefix `testProp` found.


simpler shader style syntax

simpler shader style syntax

--- oridomi.coffee
+++ oridomi.coffee
@@ -278,11 +278,8 @@
       shader.style[css.transitionDuration] = @settings.speed + 'ms'
       shader.style[css.transitionEasing] = @settings.easingMethod
       shader.style.position = 'absolute'
-      shader.style.width = '100%'
-      shader.style.height = '100%'
-      shader.style.opacity = '0'
-      shader.style.top = '0'
-      shader.style.left = '0'
+      shader.style.width = shader.style.height = '100%'
+      shader.style.opacity = shader.style.top = shader.style.left = '0'
       shader.style.pointerEvents = 'none'

     # The content holder is a clone of the target element.


Refactoring: Clarify test suite by using CSS selectors instead of XPath

--- test/src/promises-test.coffee
+++ test/src/promises-test.coffee
@@ -12,6 +12,13 @@
 errorDelay = 1000

 baseUrl = 'http://localhost:9001'
+pageTitle = 'Pääkaupunkiseudun palvelukartta'
+serviceTreeItemSelector = '#service-tree-container > ul > li'
+browseButtonSelector = '#browse-region'
+searchResultPath = '#navigation-contents li'
+searchButton =  '#search-region > div > form > span.action-button.search-button > span'
+searchFieldPath = '#search-region > div > form > span:nth-of-type(1) > input'
+typeaheadResultPath = '#search-region span.twitter-typeahead span.tt-suggestions'

 describe 'Browser test', ->
   before ->
@@ -21,110 +28,81 @@
     asserters = wd.asserters

   describe 'Test navigation widget', ->
-
     it 'Title should become "Pääkaupunkiseudun palvelukartta"', (done) ->
       browser
         .get(baseUrl)
-        .title().should.become('Pääkaupunkiseudun palvelukartta')
+        .title().should.become(pageTitle)
         .should.notify(done)

     it 'Should contain button "Selaa palveluita"', (done) ->
-      browseButtonSelector = '//*[@id="browse-region"]'
       browser
-        .waitForElementByXPath(browseButtonSelector, delay)
+        .waitForElementByCss(browseButtonSelector, delay)
         .click().should.be.fulfilled
         .should.notify(done)

-
     it 'Should contain list item "Terveys"', (done) ->
-      serviceTreeItemSelector = '//*[@id="service-tree-container"]/ul/li//' +
-                                'span[text() = "Terveys"]'
       browser
-        .waitForElementByXPath(serviceTreeItemSelector, delay,
-          asserters.isDisplayed)
+        .waitForElementByCss(serviceTreeItemSelector,
+          asserters.textInclude('Terveys'), delay)
         .should.be.fulfilled
         .should.notify(done)

     # Sanity
     it 'Should not contain list item "Sairaus"', (done) ->
-      serviceTreeItemSelector = '//*[@id="service-tree-container"]/ul/li//' +
-                                'span[text() = "Sairaus"]'
       browser
-        .waitForElementByXPath(serviceTreeItemSelector, errorDelay,
-          asserters.isDisplayed)
+        .waitForElementByCss(serviceTreeItemSelector,
+          asserters.textInclude('Sairaus'), errorDelay)
         .should.be.rejected
         .should.notify(done)

   describe 'Test look ahead', ->
-
     it 'Title should become "Pääkaupunkiseudun palvelukartta"', (done) ->
       browser
-        #.init(browserName: 'chrome')
         .get(baseUrl)
-        .title().should.become('Pääkaupunkiseudun palvelukartta')
+        .title().should.become(pageTitle)
         .should.notify(done)

     it 'Should find item "Kallion kirjasto"', (done) ->
-
-      searchFieldPath = '//*[@id="search-region"]/div/form/span[1]/input'
-      typeaheadResultPath = '//*[@id="search-region"]//span[@class="twitter-' +
-                            'typeahead"]//span[@class="tt-suggestions"]' +
-                            '//div[text() = "Kallion kirjasto"]'
       searchText = 'kallion kirjasto'
-
       browser
-        .waitForElementByXPath(searchFieldPath, delay)
+        .waitForElementByCss(searchFieldPath, delay)
+        .click()
         .type(searchText)
-        .waitForElementByXPath(typeaheadResultPath, delay)
+        .waitForElementByCss(typeaheadResultPath, asserters.textInclude("Kallion kirjasto"), delay)
         .should.be.fulfilled
         .should.notify(done)

   describe 'Test search', ->
-
     it 'Title should become "Pääkaupunkiseudun palvelukartta"', (done) ->
       browser
-        #.init(browserName: 'chrome')
         .get(baseUrl)
-        .title().should.become('Pääkaupunkiseudun palvelukartta')
-        .should.notify(done)
-
-    it 'Should manage to click search text field', (done) ->
-      searchFieldPath = '//*[@id="search-region"]/div/form/span[1]/input'
-      browser
-        .waitForElementByXPath(searchFieldPath, delay, asserters.isDisplayed)
-        .click().should.be.fulfilled
+        .title().should.become(pageTitle)
         .should.notify(done)

     it 'Should manage to input search text', (done) ->
-      searchFieldPath = '//*[@id="search-region"]/div/form/span[1]/input'
       searchText = 'kallion kirjasto'
       browser
-        .elementByXPath(searchFieldPath)
-        .type(searchText).should.be.fulfilled
+        .waitForElementByCss(searchFieldPath, delay)
+        .click()
+        .type(searchText)
+        .should.be.fulfilled
         .should.notify(done)

     it 'Should manage to click search button', (done) ->
-      searchButton =  '#search-region > div > form > span.action-button.' +
-                      'search-button > span'
       browser
-        .waitForElementByCss(searchButton, delay, asserters.isDisplayed)
+        .waitForElementByCss(searchButton, delay)
         .click().should.be.fulfilled
         .should.notify(done)

     it 'Should find item "Kallion kirjasto"', (done) ->
-      searchResultPath =  '//*[@id="navigation-contents"]//li//' +
-                          '*[contains(.,"Kallion kirjasto")]'
       browser
-        .waitForElementByXPath(searchResultPath, delay, asserters.isDisplayed)
+        .waitForElementByCss(searchResultPath, asserters.textInclude("Kallion kirjasto"), delay)
         .should.be.fulfilled
         .should.notify(done)

     it 'Should not find item "Kallio2n kirjasto"', (done) ->
-      searchResultPath =  '//*[@id="navigation-contents"]//li//*[contains' +
-                          '(.,"Kallio2n kirjasto")]'
       browser
-        .waitForElementByXPath(searchResultPath, errorDelay,
-          asserters.isDisplayed)
+        .waitForElementByCss(searchResultPath, asserters.textInclude("Kallio2n kirjasto"), errorDelay)
         .should.be.rejected
         .should.notify(done)


Enabling and disabling emulatedTouchEvents as part of enabling and disabling the emulator

--- framer/Extras/TouchEmulator.coffee
+++ framer/Extras/TouchEmulator.coffee
@@ -224,8 +224,10 @@
 exports.enable = ->
 	return if Utils.isTouch()
 	touchEmulator ?= new TouchEmulator()
+	Events.enableEmulatedTouchEvents(true)

 exports.disable = ->
 	return unless touchEmulator
 	touchEmulator.destroy()
 	touchEmulator = null
+	Events.enableEmulatedTouchEvents(false)


Change the Title Check - should be yes or no

The title option was set before to be null, but I believe it's better having a switch (yes or no aka true or false). This also allow to keep the readme as it is.

--- app/assets/javascripts/growlyflash/alert.coffee
+++ app/assets/javascripts/growlyflash/alert.coffee
@@ -56,7 +56,7 @@
     """×"""

   _title: ->
-    return "" unless @title?
+    return ""  if @title is no
     """#{@type.charAt(0).toUpperCase()}#{@type.substring(1)}!"""

   calc_top_offset: ->


Added rotation to the labels to make it more legible when large numbers on screen

--- app/assets/javascripts/provider_chart.js.coffee
+++ app/assets/javascripts/provider_chart.js.coffee
@@ -98,7 +98,7 @@

         nodeUpdate.select("text")
           .text((d) -> if d.active then "#{d.cda_identifiers?[0].root || ""} #{d.cda_identifiers?[0].extension || ""} #{d.given_name}" else "#{d.cda_identifiers?[0].root || ""} #{d.cda_identifiers?[0].extension || ""}")
-          .attr("transform", (d) -> if d.active then "translate(25) rotate(0)" else "translate(15)")
+          .attr("transform", (d) -> if d.active then "translate(25) rotate(0)" else "translate(15) rotate(30)")

         nodeExit = node.exit()


Add 'options.eslint.configFile' field'

Add 'options.eslint.configFile' field'

--- gulp/config.coffee
+++ gulp/config.coffee
@@ -25,6 +25,10 @@
   lib   :
     js : "lib.js"

+  options :
+    eslint :
+      configFile : ".eslintrc.yml"
+
   plugins : require("gulp-load-plugins")({
     rename :
       "gulp-ruby-sass" : "sass"


ENHANCE: Allow tasks to be loaded in inbox list from def

--- src/app/tasks/task-inbox-list/task-inbox-list.coffee
+++ src/app/tasks/task-inbox-list/task-inbox-list.coffee
@@ -61,13 +61,17 @@
     listeners.push $scope.$watch 'unit.id', (newUnitId, oldUnitId) ->
       return if !newUnitId? || (newUnitId == oldUnitId && $scope.tasks?)
       # Tasks for feedback or tasks for task inbox, depending on the data source
-      $scope.taskData.source.query { id: newUnitId },
+      $scope.taskData.source.query { id: newUnitId, task_def_id: $scope.filters.taskDefinitionIdSelected },
         (response) ->
           $scope.tasks = $scope.unit.incorporateTasks(response)
           # Load initial set task, either the first in the list of tasks or if
           # provided (URL) selected task id then load actual task in now
           task = findTaskForId($scope.taskData.temporaryTaskId) || _.first($scope.tasks)
           $scope.setSelectedTask(task)
+          # If loading via task definitions, fill
+          if $scope.taskData == Unit.tasksForDefinition
+            unstartedTasks = $scope.unit.fillWithUnStartedTasks($scope.tasks, $scope.selectedDefinition)
+            _.extend($scope.tasks, unstartedTasks)
           # For when URL has been manually changed, set the selected task
           # using new array of tasks loaded from the new temporaryTaskId
           listeners.push $scope.$watch 'taskData.temporaryTaskId', (newId, oldId) ->


Fix for 404 statuses from client_side_validations; small usage fix

--- app/assets/javascripts/ultimate/flash.js.coffee
+++ app/assets/javascripts/ultimate/flash.js.coffee
@@ -27,7 +27,7 @@
  *
  * * * USE INSTEAD
  * @usage
- *   window.flash = new Ultimate.Plugin.Flash[(Object options = {})]
+ *   window.flash = new Ultimate.Plugins.Flash[(Object options = {})]
  *   flash.notice String text
 ###

@@ -253,7 +253,8 @@
           # catch 'error' object and call alert() method
           return @alert(parsedJSON['error'])  if parsedJSON['error']
           # may be parsedJSON is form errors
-          if @detectFormErrors is true
+          # about 404: https://github.com/bcardarella/client_side_validations/issues/297
+          if @detectFormErrors is true and jqXHR.status isnt 404
             # show message about form with errors
             return @alert(@t('formFieldsError'))
           else if _.isFunction(@detectFormErrors)


[Backport] Fix drag&drop stories from backlog to spritn

--- app/coffee/modules/resources/userstories.coffee
+++ app/coffee/modules/resources/userstories.coffee
@@ -112,17 +112,6 @@
         params = {project_id: projectId, bulk_stories: data}
         return $http.post(url, params)

-    service.bulkUpdateMilestone = (projectId, milestoneId, data) ->
-        url = $urls.resolve("bulk-update-us-milestone")
-        data = _.map data, (us) ->
-            return {
-                us_id: us.id
-                order: us.order
-            }
-
-        params = {project_id: projectId, milestone_id: milestoneId, bulk_stories: data}
-        return $http.post(url, params)
-
     service.listValues = (projectId, type) ->
         params = {"project": projectId}
         service.storeQueryParams(projectId, params)


Small code layout improvemetns.

Small code layout improvemetns.

--- app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee
+++ app/assets/javascripts/app/controllers/_application_controller_generic.js.coffee
@@ -10,7 +10,6 @@
     @render()

   render: ->
-    @log 'ren new', @el
     @html App.view('generic/admin/new')(
       form: @formGen( model: @genericObject ),
       head: 'New ' + @pageData.object
@@ -90,6 +89,7 @@
         @modalHide()
       error: =>
         @log 'errors'
+
         @modalHide()
     )

@@ -148,15 +148,15 @@
       )

     @html App.view('generic/admin/index')(
-      head: @pageData.objects,
-      notes: @pageData.notes,
+      head:    @pageData.objects,
+      notes:   @pageData.notes,
       buttons: @pageData.buttons,
-      menus: @pageData.menus,
+      menus:   @pageData.menus,
     )

     # append content table
     table = @table(
-      model: @genericObject,
+      model:   @genericObject,
       objects: objects,
     )
     @el.find('.table-overview').append(table)
@@ -189,7 +189,7 @@
     super

   render: ->
-    @log 'ttt', @target, @
+
     # set title
     @title @page.title
     @navupdate @page.nav
@@ -200,21 +200,20 @@
       type:     @type,
       target:   @target,
     )
+
+    if !@target
+      @target = @menu[0]['target']
+
     for menu in @menu
-      @el.find('.nav-tab-content').append('
' + menu.name + '
')
-      if menu.controller
+      @el.find('.nav-tab-content').append('

')
+      if menu.controller && ( @toggleable is true || ( @toggleable is false && menu.target is @target ) )
         params    = menu.params || {}
         params.el = @el.find( '#' + menu.target )
         new menu.controller( params )

     @el.find('.tabbable').addClass('hide')
-    if @target
-      @el.find( '#' + @target ).removeClass('hide')
-    else
-      @el.find('.tabbable:first').removeClass('hide')
-
-    @el.find('[data-toggle="tabnav"]:first').addClass('active')
-
+    @el.find( '#' + @target ).removeClass('hide')
+    @el.find('[data-toggle="tabnav"][href*="/' + @target + '"]').parent().addClass('active')

   toggle: (e) ->
     return true if @toggleable is false
@@ -237,7 +236,7 @@
     @el.find('.nav-tabs li:first').addClass('active')

     for tab in @tabs
-      @el.find('.tab-content').append('
' + tab.target + '
')
+      @el.find('.tab-content').append('

')
       if tab.controller
         params = tab.params || {}
         params.el = @el.find( '#' + tab.target )


HComboBox has an unofficial _comboNumber property to check number validation against, but this may still change.

--- js/menus/combobox/combobox.coffee
+++ js/menus/combobox/combobox.coffee
@@ -51,5 +51,5 @@
       @unitSuffix.drawRect()
     @setStyleOfPart('label','right',this._extraLabelRight+'px')
     @menu.bringToFront()
-HComboBox = HTextControl.extend(HComboBoxInterface)
-HNumericComboBox = HNumericTextControl.extend(HComboBoxInterface)
+HComboBox = HTextControl.extend(HComboBoxInterface).extend({_comboNumber:false})
+HNumericComboBox = HNumericTextControl.extend(HComboBoxInterface).extend({_comboNumber:true})


tiny refactor

tiny refactor

--- apps/show/components/related_shows/index.coffee
+++ apps/show/components/related_shows/index.coffee
@@ -71,6 +71,6 @@
       DateHelpers: DateHelpers
       ViewHelpers: ViewHelpers
       fromShowGuide: location.search.match 'from-show-guide'
-      linkToFair: show.fair && show.fair.published && show.fair.profile && show.fair.profile.is_published
+      linkToFair: show.fair?.published && show.fair.profile?.is_published

   .catch console.error.bind(console)


accidentally left a script test

accidentally left a script test

--- components/layout/header/view.coffee
+++ components/layout/header/view.coffee
@@ -18,7 +18,7 @@
     'tap .header--icon'                   : 'setActive'
     'tap .btn-login'                      : 'login'
     'tap .btn-signup'                     : 'signup'
-    'touchstart .dropdown--menu__trigger'      : 'toggleDropdown'
+    'tap .dropdown--menu__trigger'        : 'toggleDropdown'

   initialize: (options) ->


Update scratch

Update scratch

--- scratch.coffee
+++ scratch.coffee
@@ -10,8 +10,9 @@
 # Libraries
 global.React = require 'react'
 global.Promise = require 'bluebird'
-Arda = require './src'
+global.Arda = Arda = require './src'

+# Application
 class HelloComponent extends Arda.Component
   render: ->
     React.createElement 'h1', {}, 'Hello Arda'
@@ -19,7 +20,6 @@
 class HelloContext extends Arda.Context
   @component: HelloComponent

-# window.addEventListener 'DOMContentLoaded', ->
 router = new Arda.Router(Arda.DefaultLayout, document.body)
 router.pushContext(HelloContext, {})
 .then =>


KDModalView: Fixed overlay not removed problem.

--- components/modals/KDModalView.coffee
+++ components/modals/KDModalView.coffee
@@ -202,6 +202,7 @@
       @getDomElement().hide()
       uber()

+    @overlay.destroy()
     @emit 'KDModalViewDestroyed', @

   ### STACK HELPERS ###


KDTabview: save scroll pos

KDTabview: save scroll pos

--- components/tabs/KDTabPaneView.coffee
+++ components/tabs/KDTabPaneView.coffee
@@ -10,6 +10,11 @@
     super options, data

     @name = options.name
+    @lastScrollTops =
+      window : 0
+      parent : 0
+      self   : 0
+

     @on "KDTabPaneActive",        @bound "setMainView"
     @on "KDTabPaneLazyViewAdded", @bound "fireLazyCallback"
@@ -22,9 +27,19 @@
     @parent.getElement().appendChild @getElement()
     @active = yes
     @emit "KDTabPaneActive"
+    KD.utils.defer =>
+      document.documentElement.scrollTop = @lastScrollTops.window
+      @getElement().scrollTop            = @lastScrollTops.self
+      @parent.getElement().scrollTop     = @lastScrollTops.parent

   hide:->
+
+    return  unless @active
+
+    @lastScrollTops.window = document.documentElement.scrollTop
+    @lastScrollTops.parent = @parent.getElement().scrollTop
+    @lastScrollTops.self   = @getElement().scrollTop

     @setClass "kdhiddentab"
     @unsetClass "active"


OX-252 Fix too big zoom step

OX-252 Fix too big zoom step

--- app/assets/javascripts/oxalis/model.coffee
+++ app/assets/javascripts/oxalis/model.coffee
@@ -40,7 +40,7 @@

               @scaleInfo = new ScaleInfo(tracing.tracing.scale)
               @binary = new Binary(@flycam, tracing.dataSet, TEXTURE_SIZE_P)
-              @flycam = new Flycam(VIEWPORT_SIZE, @scaleInfo, @binary.cube.ZOOM_STEP_COUNT)
+              @flycam = new Flycam(VIEWPORT_SIZE, @scaleInfo, @binary.cube.ZOOM_STEP_COUNT - 1)
               @route = new Route(tracing.tracing, tracing.dataSet, @scaleInfo, @flycam)
               @user = new User(user)


tuning

tuning

--- app/assets/javascripts/workflows.js.coffee
+++ app/assets/javascripts/workflows.js.coffee
@@ -44,9 +44,7 @@
     if logged and $("#menus .fb_logged").attr('data-display-invite-popup') == 'true'
       window.colorbox_invite_friends()
   else
-    random2 = Math.floor((Math.random()*3)+1)
-    if random2 == 1
-      window.colorbox_random_level()
+    window.colorbox_random_level()

 $ ->
   # Click on 'next' on "welcome"
@@ -98,7 +96,7 @@
     # change the url and save related state (pack and level)
     window.push_this_state()

-    setTimeout(random_social_popup, 1500)
+    setTimeout(random_social_popup, 1000)
     false
   )

@@ -110,7 +108,7 @@

     window.change_level()

-    setTimeout(random_social_popup, 1500)
+    setTimeout(random_social_popup, 1000)
     false
   )


[backport] Minor improvement for make analyics more safe.

--- app/coffee/modules/common/analytics.coffee
+++ app/coffee/modules/common/analytics.coffee
@@ -67,6 +67,7 @@

     trackPage: (url, title) ->
         return if not @.initialized
+        return if not @win.ga

         title = title or @doc[0].title
         @win.ga("send", "pageview", {
@@ -76,6 +77,8 @@

     trackEvent: (category, action, label, value) ->
         return if not @.initialized
+        return if not @win.ga
+
         @win.ga("send", "event", category, action, label, value)


FullCalendar timeFormat use H:mm

FullCalendar timeFormat use H:mm

24-hour clock

--- app/coffeescripts/calendar/Calendar.coffee
+++ app/coffeescripts/calendar/Calendar.coffee
@@ -56,6 +56,7 @@
       """

       fullCalendarParams = _.defaults(
+        timeFormat: 'H:mm'
         header:
           left:   'prev,today,next,title'
           center: ''


specs to test list initialization

specs to test list initialization

--- test/spec/controllers/choropleth_form_controller_spec.coffee
+++ test/spec/controllers/choropleth_form_controller_spec.coffee
@@ -6,10 +6,10 @@
       id: 'testChoropleth'
       uiTemplateInstance: @choroplethMap
       storedData:
-        map: 'aMap'
+        map: sampleMap
         projection: 'aProjection'
         mapName: 'aGreatName'
-        data: 'someData'
+        data: sample1DData
         mappingPropertyOnMap: 'someProp'
         mappingPropertyOnData: 'someProp'
         valueProperty: 'someVal'
@@ -86,19 +86,44 @@
           @choroplethController = instantiateController('ChoroplethFormController',
             $scope: @scope, $http: {}, ngProgress: @ngProgress, dataService: {})

-        it 'should initialize available projections'
+        it 'should initialize available projections', ->
+          expect(@scope.projections).to.eql(choroplethMapConfig.availableProjections)

-        it 'should initialize available mapping properties on map'
+        it 'should initialize available mapping properties on map', ->
+          expect(@scope.availableMapProperties).to.eql([
+            label: 'id (e.g. 1)'
+            value: 'id'
+          ,
+            label: 'name (e.g. Alabama)'
+            value: 'name'
+          ,
+            label: 'reverseMapping (e.g. String2)'
+            value: 'reverseMapping'
+          ])

       describe 'for data selections', ->

-        it 'should initialize available mapping properties on data'
+        beforeEach ->
+          @choroplethController = instantiateController('ChoroplethFormController',
+            $scope: @scope, $http: {}, ngProgress: @ngProgress, dataService: {})

-        it 'should initialize available value properties on data'
-
+        it 'should initialize available data properties', ->
+          expect(@scope.availableDataProperties).to.eql([
+            label: 'id (e.g. 2)'
+            key: 'id'
+          ,
+            label: 'reverseId (e.g. String2)'
+            key: 'reverseId'
+          ,
+            label: 'value (e.g. 7)'
+            key: 'value'
+          ,
+            label: 'alternativeValue (e.g. 5)'
+            key: 'alternativeValue'
+          ])

   # TODO: there seems to be some timing issue when changing user input...
@@ -112,7 +137,6 @@
   #   describe 'changes projection', ->

   #     it 'should change the projection on input', ->
-  #       console.log "HERE"
   #       @scope.projection = 'fancyNewProjection'
   #       @scope.$digest()
   #       expect(@scope.snippet.model.data('projection')).to.eql('fancyNewProjection')


Fix composed tweet when there's no twitter handle

--- framer/Components/ShareComponent.coffee
+++ framer/Components/ShareComponent.coffee
@@ -486,7 +486,7 @@
 			if @shareInfo.twitter
 				tweet += "A prototype by @#{@shareInfo.twitter}. Design without limitations in @framerjs — "
 			else if @shareInfo.author
-				tweet += "A prototype by @#{@shareInfo.author}. Design without limitations in @framerjs — "
+				tweet += "A prototype by #{@shareInfo.author}. Design without limitations in @framerjs — "
 			else
 				tweet += "A @framerjs prototype by @#{@shareInfo.author}. Design without limitations — "


Don’t open a new window/tab when clicking ‘Open in Framer’

Fixes motif/company#2240

--- framer/Components/ShareComponent.coffee
+++ framer/Components/ShareComponent.coffee
@@ -1,3 +1,5 @@
+{_} = require "../Underscore"
+
 # Insert Roboto font
 css = """
 	@font-face {
@@ -40,6 +42,9 @@
 	constructor: (options) ->
 		super options

+		options = _.defaults options,
+			newWindow: true
+
 		defaultProps =
 			height: 33
 			ignoreEvents: false
@@ -65,7 +70,11 @@
 			@opacity = 1
 			@states.switch('default')

-		@onClick -> window.open(options.url, "_blank")
+		@onClick ->
+			if options.newWindow
+				window.open(options.url)
+			else
+				window.location = options.url

 # Share component
 class ShareComponent
@@ -390,8 +399,9 @@
 			parent: @info
 			y: verticalPosition + 16

-		@buttonDownload = new Button
+		@buttonOpen = new Button
 			url: @shareInfo.openInFramerURL
+			newWindow: false
 			html: "Open in Framer"
 			color: "#FFF"
 			parent: @buttons
@@ -405,7 +415,7 @@
 			borderWidth: 1
 			borderColor: "#D5D5D5"
 			width: 33
-			x: @buttonDownload.maxX + 6
+			x: @buttonOpen.maxX + 6
 			style:
 				borderRadius: "3px 0 0 3px"


Don't fail if we don't have paginationlinks

--- src/client/datasource.coffee
+++ src/client/datasource.coffee
@@ -120,13 +120,13 @@
     #
     # @returns {Boolean}
     isFirst: ->
-      !@paginationLinks.first
+      !@paginationLinks?.first

     # Is datasource on the last page?
     #
     # @returns {Boolean}
     isLast: ->
-      !@paginationLinks.last
+      !@paginationLinks?.last

     # Go to previous page.
     #


Add Roxy Lead to Enums

Add Roxy Lead to Enums

--- src/coffee/game/enums.coffee
+++ src/coffee/game/enums.coffee
@@ -4,9 +4,11 @@
       illusionist: 'an illusionist'
       hallucinist: 'a hallucinist'
       hypnotist: 'a hypnotist'
+
     leads:
       none: undefined
       jackie: 'Jackie'
       employer: 'KB&S'
       cop: 'Officer Dentley'
       student: 'Ms. Denotto'
+      roxy: 'Roxy'


Output component only disconnects when out is attached

--- src/components/Output.coffee
+++ src/components/Output.coffee
@@ -29,7 +29,7 @@
       @outPorts.out.send data if @outPorts.out.isAttached()

     @inPorts.in.on "disconnect", =>
-      @outPorts.out.disconnect()
+      @outPorts.out.disconnect() if @outPorts.out.isAttached()

     @inPorts.options.on "data", (data) =>
       @setOptions data


fix redisstore

fix redisstore

--- config/initializers/socket.io.coffee
+++ config/initializers/socket.io.coffee
@@ -10,6 +10,7 @@
     io.set("polling duration", 10)

   io.store = new RedisStore(
+    redis: require('redback/node_modules/redis')
     redisPub: Caboose.app.redis.pub
     redisSub: Caboose.app.redis.sub
     redisClient: Caboose.app.redis.default


move View configure from `initialize` to `constructor`

--- src/chaplin/views/view.coffee
+++ src/chaplin/views/view.coffee
@@ -43,7 +43,7 @@
     subviews: null
     subviewsByName: null

-    constructor: ->
+    constructor: (options) ->
       # Wrap `initialize` so `afterInitialize` is called afterwards
       # Only wrap if there is an overriding method, otherwise we
       # can call the `after-` method directly
@@ -57,15 +57,15 @@
         # Otherwise just bind the `render` method
         @render = _(@render).bind this

-      # Call Backbone’s constructor
-      super
-
-    initialize: (options) ->
-      # No super call here, Backbone’s `initialize` is a no-op
-
       # Copy some options to instance properties
       if options
         _(this).extend _.pick options, ['autoRender', 'container', 'containerMethod']
+
+      # Call Backbone’s constructor
+      super
+
+    initialize: (options) ->
+      # No super call here, Backbone’s `initialize` is a no-op

       # Initialize subviews
       @subviews = []


remove debug

remove debug

--- src/marbles/http/middleware/serialize_json.js.coffee
+++ src/marbles/http/middleware/serialize_json.js.coffee
@@ -4,7 +4,6 @@
     return unless (content_type = http.headers['Content-Type']) && content_type.match(/\bjson/i)
     body = if http.body then JSON.stringify(http.body) else null
     body = null if body == "{}" or body == "[]"
-    console.log('processRequest', typeof body)
     http.body = body

   processResponse: (http, xhr) ->


:lipstick:

:lipstick:

--- src/packages/fuzzy-finder/lib/load-paths-task.coffee
+++ src/packages/fuzzy-finder/lib/load-paths-task.coffee
@@ -18,7 +18,7 @@
     args = ['-l', rootPath]
     args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores')
     args.unshift("-d", "#{ignoredNames.join(',')}") if ignoredNames.length > 0
-
+
     paths = []
     deferred = $.Deferred()
     exit = (code) =>
@@ -35,4 +35,3 @@

   abort: ->
     @aborted = true
-


buttonbar: experimental idea for showing the formatting bar as a dropdown (only needs some fixes to handle nested dropdowns)

--- salvus/page/buttonbar.coffee
+++ salvus/page/buttonbar.coffee
@@ -1081,11 +1081,21 @@

     # TODO merge this with the usual text formatting toolbar, such that its list of actions is inserted here
     # IDEA: maybe, clicking on the "Format" dropdown shows the cloned formatting toolbar?
-    text = ["Format", "Text formatting",
-            [
-             ["Bold", "#bold"]
-            ]]
-    add_menu(latexbar, text)
+    #text = ["Format", "Text formatting",[]]
+    #add_menu(latexbar, text)
+    formatting = $("")
+    formatting.append($("""
+
+     Format
+
+    """))
+    format_buttons = $(".salvus-editor-codemirror-worksheet-editable-buttons").clone()
+    format_buttons.addClass("dropdown-menu")
+    format_buttons.removeClass("hide")
+    format_buttons.css("min-width", 300);
+    formatting.append(format_buttons)
+    latexbar.append(formatting)
+    # end format button idea

     formulas = ["Formula", "These are some standard formuas",
                 [


Fixed: clear timeout to prevent multiple automatic refresh from starting.

--- server/models/account.coffee
+++ server/models/account.coffee
@@ -45,6 +45,7 @@
 CONSTANTS = require '../utils/constants'
 require('../utils/socket_handler').wrapModel Account, 'account'

+refreshTimeout = null

 Account::doASAP = (operation, callback) ->
     ImapPool.get(@id).doASAP operation, callback
@@ -102,7 +103,8 @@
             cb null
     , (err) ->
         if periodic?
-            setTimeout ->
+            clearTimeout refreshTimeout
+            refreshTimeout = setTimeout ->
                 log.debug "doing periodic refresh"
                 # periodic refresh should only check new messages on favorites mailboxes
                 options.onlyFavorites = true


test: cleanup

test: cleanup

--- test/functional/index.coffee
+++ test/functional/index.coffee
@@ -71,10 +71,6 @@

   after ->
     client
-      .then ->
-        new Promise (resolve) ->
-          revision.short (str) ->
-            resolve build = str
       .sauceJobStatus
         passed: _.every this.test.parent.tests, {state: 'passed'}
         public: 'public'


closed #18 client authentication : test comment updates

--- test/lib/test-api-key.coffee
+++ test/lib/test-api-key.coffee
@@ -59,13 +59,13 @@
       delete process.env.API_KEYS_ENABLED
       delete process.env.API_KEYS

-    it "should return 405 if the API key is missing", ->
+    it "should return 401 if the API key is missing", ->
       r = request(server)
         .get('/v1/routes')

       helpers.assert401WithMissingApiKeyHeader r

-    it "should return 405 if the API key is invalid", ->
+    it "should return 401 if the API key is invalid", ->
       r = request(server)
         .get('/v1/routes')
         .headers('api-key': 'bar-token')
@@ -95,4 +95,4 @@

           route = body[1]
           route.should.have.property 'id', '456'
-          route.should.have.property 'description', 'Route 456'+          route.should.have.property 'description', 'Route 456'


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/controllable.coffee
+++ src/controllable.coffee
@@ -22,7 +22,8 @@
   # => 13

   # We keep track of the direction the object is
-  # facing in case you need that (efor attack direction)
+  # facing in case you need that (eg. for attack direction)
+
 </pre></code>

 @name Controllable


fix for arbitrary ordering of cookies from http

--- test/get.coffee
+++ test/get.coffee
@@ -188,10 +188,15 @@
             assert.equal resp?.statusCode, 200, "Status code should be 200, is #{resp?.statusCode}"
             cookies = j.get uri
             assert.equal cookies.length, 2
-            assert.equal cookies[0]?.name, 'my_param'
-            assert.equal cookies[0]?.value, 'trolling'
-            assert.equal cookies[1]?.name, 'my_param2'
-            assert.equal cookies[1]?.value, 'trolling2'
+            my_param = 0
+            my_param2 = 1
+            if cookies[0]?.name is 'my_param2'
+              my_param = 1
+              my_param2 = 0
+            assert.equal cookies[my_param]?.name, 'my_param'
+            assert.equal cookies[my_param]?.value, 'trolling'
+            assert.equal cookies[my_param2]?.name, 'my_param2'
+            assert.equal cookies[my_param2]?.value, 'trolling2'

             options =
               uri: "#{protocol}://httpbin.org/cookies"


return false if courseTimezone is blank

return false if courseTimezone is blank

--- tutor/src/helpers/time.coffee
+++ tutor/src/helpers/time.coffee
@@ -132,7 +132,7 @@
     timezone in _.values(TimeHelper.getTimezones())

   isCourseTimezone: (courseTimezone) ->
-    return false unless courseTimezone?
+    return false if _.isEmpty(courseTimezone)

     {offsets} = moment()._z or moment.tz(TimeHelper.getLocalTimezone())._z
     courseTimezoneOffsets = moment.tz(courseTimezone)._z.offsets


Biquad filter visualization fix.

Biquad filter visualization fix.

--- packages/landsofillusions-assets/audioeditor/node/nodes/biquadfilter/biquadfilter.coffee
+++ packages/landsofillusions-assets/audioeditor/node/nodes/biquadfilter/biquadfilter.coffee
@@ -8,12 +8,12 @@

   @_frequenciesBase = 1.07

-  @frequencies = for index in [0..99]
-    24000 / Math.pow @_frequenciesBase, 99 - index
+  @frequencies = for index in [0..100]
+    24000 / Math.pow @_frequenciesBase, 101 - index

   @_frequencies = new Float32Array @frequencies
-  @_magnitudeResponse = new Float32Array 100
-  @_phaseResponse = new Float32Array 100
+  @_magnitudeResponse = new Float32Array 101
+  @_phaseResponse = new Float32Array 101

   constructor: (@node) ->
     super arguments...
@@ -53,20 +53,18 @@
         for value, index in @constructor._phaseResponse
           context.lineTo index, 25.5 + value * 5

-      context.lineTo 100, 25.5
       context.stroke()

       # Draw magnitude response.
       context.strokeStyle = "#7c8ce0"
       context.beginPath()

-      context.moveTo 0, 25.5
+      context.moveTo 0, 50.5

       if biquadFilterNode
         for value, index in @constructor._magnitudeResponse
           context.lineTo index, (1 - value * 0.5) * 50.5

-      context.lineTo 100, 25.5
       context.stroke()

       if audioNode
@@ -75,7 +73,7 @@
         detune = audioNode.readParameter 'detune'

         effectiveFrequency = frequency * Math.pow 2, detune / 1200
-        x = 99.5 - Math.floor Math.log(24000 / effectiveFrequency) / Math.log @constructor._frequenciesBase
+        x = 100.5 - Math.floor Math.log(24000 / effectiveFrequency) / Math.log @constructor._frequenciesBase

         context.strokeStyle = "#8c58b8"
         context.beginPath()


Harness Test

Harness Test

--- test/2.test.coffee
+++ test/2.test.coffee
@@ -63,11 +63,15 @@
         setTimeout reschedule, 100

       do killone = ->
-        victim_index = parseInt Math.random() * (child_processes.length - 1)
-        allowed_signals = ['SIGINT', 'SIGHUP', 'SIGUSR2']
-        random_signal = -> allowed_signals[parseInt Math.random() * allowed_signals.length]
-        child_processes[victim_index].kill random_signal()
-        setTimeout killone, 100
+        queue.workers (err, workers) ->
+
+          return setTimeout killone, 100 unless workers.length
+          victim_index = parseInt Math.random() * workers.length
+          allowed_signals = ['SIGINT', 'SIGHUP', 'SIGUSR2']
+          random_signal = -> allowed_signals[parseInt Math.random() * allowed_signals.length]
+          #console.log workers, victim_index
+          process.kill workers[victim_index].pid, random_signal()
+          setTimeout killone, 100

       do stats = ->
         queue.statistics (err, statistics) ->
@@ -93,7 +97,7 @@
           setTimeout ->
             queue.statistics (err, statistics) ->
               done() if statistics.workers is 0
-          , 10
+          , 20

   it "Should Dump Incremental Numbers", (done) ->
     for group in [0 .. total_groups - 1]


set the listeners to begin with doi!

set the listeners to begin with doi!

--- app/assets/javascripts/posts.js.coffee
+++ app/assets/javascripts/posts.js.coffee
@@ -78,7 +78,6 @@
   # Set listener on abstract link
   setAbstractListeners = ->
     $('.abstract-link').on 'click', (e) ->
-      console.log 'hey boi'
       targetID = $(e.target).data('target')
       $target = $('#' + targetID)
       # show abstract lightbox on click
@@ -88,3 +87,5 @@
         $target.removeClass('shown').addClass('visibly-hidden')
       $target.on 'click', ->
         $target.removeClass('shown').addClass('visibly-hidden')
+
+  do setAbstractListeners


Added back the map zoom controls

Added back the map zoom controls

--- app/assets/javascripts/power.js.coffee
+++ app/assets/javascripts/power.js.coffee
@@ -90,6 +90,7 @@
       zoom: 11
       mapTypeId: google.maps.MapTypeId.ROADMAP
       disableDefaultUI: true
+      zoomControl: true
       scrollwheel: false
       styles: [
         {


debug

debug

--- app/assets/javascripts/profiles.coffee
+++ app/assets/javascripts/profiles.coffee
@@ -1,8 +1,8 @@
 # Place all the behaviors and hooks related to the matching controller here.
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://coffeescript.org/
-bla
-$->
+
+$ ->
   alert "bla"
   $('#myModule').click ->
     if $('#check_modul').prop('checked')


Use new non-intermediate representation

Use new non-intermediate representation

--- app/js/jail_iframe/initializers/xdm.coffee
+++ app/js/jail_iframe/initializers/xdm.coffee
@@ -3,7 +3,7 @@
 frame_container.appendChild(iframe)
 FactlinkJailRoot.createReceiverEnvoy FactlinkJailRoot.annotatedSiteReceiver
 iframe.id = "factlink-modal-frame"
-iframe.src = "#{FactlinkConfig.api}/factlink/intermediate"
+iframe.src = "#{FactlinkConfig.api}/client/blank"
 FactlinkJailRoot.factlinkCoreEnvoy = FactlinkJailRoot.createSenderEnvoy iframe.contentWindow, ['showFactlink', 'prepareNewFactlink' ]

 FactlinkJailRoot.openFactlinkModal = FactlinkJailRoot.factlinkCoreEnvoy.showFactlink


Don't show groups menu if you're not in any groups nor admin

--- app/backbone/views/react_topbar.coffee
+++ app/backbone/views/react_topbar.coffee
@@ -37,13 +37,15 @@
                _i ['icon-bookmark']
                " On your site"
           ]
-        else
+        else if currentSession.user().get('admin') || currentSession.user().get('groups').length
           [
             _li ['dropdown-menu-item'],
               _a [href: "/user/#{username}/groups"],
                 _i ['icon-users']
                 " Groups"
           ]
+        else
+          []
         )...
         _li ['dropdown-menu-item'],
          _a [href: "/user/#{username}/edit", rel: 'backbone'],


Remove dead code.

Remove dead code.

--- app/scripts/lib/paper/path_reshaper.coffee
+++ app/scripts/lib/paper/path_reshaper.coffee
@@ -16,5 +16,4 @@
     finalise: =>
       @path.removeSegments(1, @path.segments.size - 2)
       @path.simplify(100)
-      # @path.remove()
       @path.segments


Call next autofill iteration before it starts loading again

--- app/assets/javascripts/devtools.coffee
+++ app/assets/javascripts/devtools.coffee
@@ -3,6 +3,7 @@

 window.autofill = ->
   delay 20, ->
+    autofill() unless getResponse().done
     unless getResponse().loading
       lastQuestion = getResponse().questions[getResponse().questions.length - 1]

@@ -11,7 +12,6 @@
       option = options[Math.floor(Math.random() * options.length)]

       Screensmart.store.dispatch(Screensmart.Actions.setAnswer(lastQuestion.id, option.id))
-    autofill() unless getResponse().finished

 document.addEventListener 'keyup', (event) ->
   if event.ctrlKey && event.keyCode == 220 # CTRL + \


- Stop spamming google.

- Stop spamming google.

--- app/core/Tracker.coffee
+++ app/core/Tracker.coffee
@@ -131,17 +131,17 @@
     @trackSnowplow action, _.cloneDeep properties

-
-    # Google Analytics
-    # https://developers.google.com/analytics/devguides/collection/analyticsjs/events
-    gaFieldObject =
-      hitType: 'event'
-      eventCategory: properties.category ? 'All'
-      eventAction: action
-    gaFieldObject.eventLabel = properties.label if properties.label?
-    gaFieldObject.eventValue = properties.value if properties.value?
-    ga? 'send', gaFieldObject
-    ga? 'codeplay.send', gaFieldObject if features.codePlay
+    unless event in ['View Load', 'Script Started', 'Script Ended', 'Heard Sprite']
+      # Google Analytics
+      # https://developers.google.com/analytics/devguides/collection/analyticsjs/events
+      gaFieldObject =
+        hitType: 'event'
+        eventCategory: properties.category ? 'All'
+        eventAction: action
+      gaFieldObject.eventLabel = properties.label if properties.label?
+      gaFieldObject.eventValue = properties.value if properties.value?
+      ga? 'send', gaFieldObject
+      ga? 'codeplay.send', gaFieldObject if features.codePlay

     # Inspectlet
     # http://www.inspectlet.com/docs#tagging


Add confirmation when canceling creating/editing with changes

--- app/assets/javascripts/notes.js.coffee
+++ app/assets/javascripts/notes.js.coffee
@@ -104,19 +104,31 @@
     return if isMetaKey e

     $textarea = $(e.target)
+
+    # Edit previous note when UP arrow is hit
     if $textarea.val() is '' and e.which is 38
       myLastNote = $("li.note[data-author-id='#{gon.current_user_id}'][data-editable]:last")
       if myLastNote.length
         myLastNoteEditBtn = myLastNote.find('.js-note-edit')
         myLastNoteEditBtn.trigger('click', [true, myLastNote])
+
+    # Cancel creating diff note or editing any note when ESCAPE is hit
     if e.which is 27
       discussionNoteForm = $textarea.closest(".js-discussion-note-form")
       if discussionNoteForm.length
+        if $textarea.val() isnt ''
+          return unless confirm('Are you sure you want to cancel creating this comment?')
+
         @removeDiscussionNoteForm(discussionNoteForm)
         return

       editNote = $textarea.closest(".note")
       if editNote.length
+        originalText = $textarea.closest('form').data('original-note')
+        newText = $textarea.val()
+        if originalText isnt newText
+          return unless confirm('Are you sure you want to cancel editing this comment?')
+
         @removeNoteEditForm(editNote)


Initialized the angular app

Initialized the angular app

--- app/assets/javascripts/pages.js.coffee
+++ app/assets/javascripts/pages.js.coffee
@@ -1,3 +1,14 @@
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://coffeescript.org/
+#= require_self
+#= require_tree ./controllers/homepage
+#= require_tree ./directives
+#= require_tree ./services
+#= require_tree ./templates
+
+@app = angular.module('infoeducatie', [ 'ngRoute', 'ngResource', 'ngAnimate' ])
+
+@app.config(['$routeProvider', '$locationProvider', (routeProvider, locationProvider) ->
+  routeProvider.when('/', {
+    templateUrl: '/assets/templates/homepage/index.html',
+    controller: 'HomePageCtrl'
+  }).otherwise({ redirectTo: '/' })
+])


sks-98 remove fixtures

sks-98 remove fixtures

--- app/assets/javascripts/store.js.coffee
+++ app/assets/javascripts/store.js.coffee
@@ -4,8 +4,8 @@

 #Sks.Store.registerAdapter 'Sks.User', DS.FixtureAdapter
 #Sks.Store.registerAdapter 'Sks.CurrentUser', DS.FixtureAdapter
-Sks.Store.registerAdapter 'Sks.Hamster', DS.FixtureAdapter
-Sks.Store.registerAdapter 'Sks.Top', DS.FixtureAdapter
-Sks.Store.registerAdapter 'Sks.KudoReceived', DS.FixtureAdapter
-Sks.Store.registerAdapter 'Sks.KudoLastWeek', DS.FixtureAdapter
-Sks.Store.registerAdapter 'Sks.Comment', DS.FixtureAdapter+#Sks.Store.registerAdapter 'Sks.Hamster', DS.FixtureAdapter
+#Sks.Store.registerAdapter 'Sks.Top', DS.FixtureAdapter
+#Sks.Store.registerAdapter 'Sks.KudoReceived', DS.FixtureAdapter
+#Sks.Store.registerAdapter 'Sks.KudoLastWeek', DS.FixtureAdapter
+#Sks.Store.registerAdapter 'Sks.Comment', DS.FixtureAdapter


Custom and Stub are removed

Custom and Stub are removed

--- grammars/sifu.cson
+++ grammars/sifu.cson
@@ -83,9 +83,6 @@
             'include': '#dto'
           }
           {
-            'include': '#customEndpoint'
-          }
-          {
             'include': '#readEndpoint'
           }
           {
@@ -796,9 +793,6 @@
             'include': '#modelSetting'
           }
           {
-            'include': '#stub'
-          }
-          {
             'include': '#queryInlineCount'
           }
           {
@@ -870,9 +864,6 @@
             'include': '#modelSetting'
           }
           {
-            'include': '#stub'
-          }
-          {
             'include': '#requestInlineDto'
           }
           {
@@ -1026,71 +1017,6 @@
         'name': 'markup.inserted'
     'name': 'currencyTypeElement'
     'patterns':[
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
-  'customEndpoint':
-    'begin': '([ \\t]*[a-zA-Z][_a-zA-Z0-9]*)([ \\t]+custom)'
-    'beginCaptures':
-      '1':
-        'name': 'punctuation.definition.identity'
-      '2':
-        'name': 'keyword'
-    'name': 'customEndpoint'
-    'patterns':[
-      {
-        'begin': '\\['
-        'patterns': [
-          {
-            'include': '#comments'
-          }
-          {
-            'include': '#modelSetting'
-          }
-          {
-            'include': '#paged'
-          }
-          {
-            'include': '#stub'
-          }
-          {
-            'include': '#requestInlineDto'
-          }
-          {
-            'include': '#requestDto'
-          }
-          {
-            'include': '#responseInlineDto'
-          }
-          {
-            'include': '#responseDto'
-          }
-          {
-            'include': '#secured'
-          }
-          {
-            'include': '#public'
-          }
-          {
-            'include': '#endpointErrors'
-          }
-          {
-            'include': '#rest'
-          }
-          {
-            'include': '#version'
-          }
-          {
-            'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-            'name': 'invalid.illegal'
-          }
-        ]
-        'end': '\\]'
-      }
       {
         'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
         'name': 'invalid.illegal'
@@ -1290,9 +1216,6 @@
           }
           {
             'include': '#modelSetting'
-          }
-          {
-            'include': '#stub'
           }
           {
             'include': '#endpointQueryInlineSelect'
@@ -7948,9 +7871,6 @@
             'include': '#paged'
           }
           {
-            'include': '#stub'
-          }
-          {
             'include': '#endpointQueryInlineSelect'
           }
           {
@@ -8312,28 +8232,6 @@
     ]
     'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'

-  'rest':
-    'begin': '(?:([ \\t]*get)|([ \\t]*post)|([ \\t]*put)|([ \\t]*delete))(?:([ \\t]+[^(\\s\\{\\}\\[\\]\\(\\)#,)]+))?'
-    'beginCaptures':
-      '1':
-        'name': 'markup.inserted'
-      '2':
-        'name': 'markup.inserted'
-      '3':
-        'name': 'markup.inserted'
-      '4':
-        'name': 'markup.inserted'
-      '5':
-        'name': 'constant'
-    'name': 'rest'
-    'patterns':[
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
   'restSimple':
     'begin': '([ \\t]*rest)(?:([ \\t]+[^(\\s\\{\\}\\[\\]\\(\\)#,)]+))?'
     'beginCaptures':
@@ -9084,20 +8982,6 @@
         ]
         'end': '\\)'
       }
-      {
-        'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
-        'name': 'invalid.illegal'
-      }
-    ]
-    'end': '(?=[ \\t]*(,|#|\\]|\\)|\\}|\\n))'
-
-  'stub':
-    'begin': '([ \\t]*stub)'
-    'beginCaptures':
-      '1':
-        'name': 'keyword'
-    'name': 'stub'
-    'patterns':[
       {
         'match': '[^(\\s\\{\\}\\[\\]\\(\\)#,)]+'
         'name': 'invalid.illegal'
@@ -10651,9 +10535,6 @@
             'include': '#modelSetting'
           }
           {
-            'include': '#stub'
-          }
-          {
             'include': '#requestInlineDto'
           }
           {


OX-55 Also notify when saving insuccessful

--- app/assets/javascripts/view/gui.coffee
+++ app/assets/javascripts/view/gui.coffee
@@ -141,7 +141,9 @@
     fNodes.open()

   saveNow : =>
-    @model.Route.pushImpl().done( -> alert("Successfully saved!"))
+    @model.Route.pushImpl()
+      .fail( -> alert("Something went wrong with saving, please try again."))
+      .done( -> alert("Successfully saved!"))

   setPosFromString : (posString) =>
     stringArray = posString.split(",")


Update pt-PT.coffee

Update pt-PT.coffee

--- app/locale/pt-PT.coffee
+++ app/locale/pt-PT.coffee
@@ -159,10 +159,10 @@
     date: "Data"
     body: "Corpo"
     version: "Versão"
-#    pending: "Pending"
-#    accepted: "Accepted"
-#    rejected: "Rejected"
-#    withdrawn: "Withdrawn"
+    pending: "Pendentes"
+    accepted: "Aceitadas"
+    rejected: "Rejeitadas"
+    withdrawn: "Canceladas"
     submitter: "Submissor"
     submitted: "Submeteu"
     commit_msg: "Mensagem da Submissão"
@@ -197,9 +197,9 @@
     hard: "Difícil"
     player: "Jogador"
     player_level: "Nível" # Like player level 5, not like level: Dungeons of Kithgard
-#    warrior: "Warrior"
-#    ranger: "Ranger"
-#    wizard: "Wizard"
+    warrior: "Guerreiro"
+    ranger: "Arqueiro"
+    wizard: "Feiticeiro"

   units:
     second: "segundo"


Added custom-plugin support, autoloading plugins, core-addon container

--- src/API.coffee
+++ src/API.coffee
@@ -1,24 +1,51 @@
 ##################################
-#   SYS-API (c) 2015 - Burnett
+#   SYS-API (c) 2016- Burnett
 ##################################

 restify = require 'restify'
 bcrypt  = require 'bcrypt';

-AddonHelper = require './AddonHelper'
+ClassHelper = require './ClassHelper'

-Fs = require './addons/Fs/Fs'
-Os  = require './addons/Os/Os'
-Net = require './addons/Net/Net'
+# Define Core-Addons
+Addons = [
+    "./addons/Fs",
+    "./addons/Os",
+    "./addons/Net"
+]
+
+class API extends ClassHelper
+
+    # Include and expose Core-Addons
+    for addon, index in Addons
+        @extend(require(addon))
+        @include(require(addon))

-class API extends AddonHelper
+
+    # Plugin-Handler
+    plugins =
+        registerAll: (root) ->
+            console.log "Loading plugins.."
+
+            API.fs.readDir(root, true, (err, files) ->
+                if err then return console.log(err)
+                for file, index in files
+                    API.include(require(file))
+            )

-    @include Fs
-    @include Os
-    @include Net

     constructor: (options) ->
-        @server = new restify.createServer(options);
+        @options = options
+
+        if(typeof @options['restify'] == undefined)
+            @options.restify = {}
+
+        @server = new restify.createServer(@options.restify);
+
+        if('plugins.root' of @options)
+            if('plugins.autoload' of @options && @options['plugins.autoload'] == true)
+                plugins.registerAll(@options['plugins.root'])
+

     connect: (port) ->
         @server.listen port, () ->


Update pt-PT.coffee

Update pt-PT.coffee

--- app/locale/pt-PT.coffee
+++ app/locale/pt-PT.coffee
@@ -596,8 +596,8 @@
     intro_2: "Não é necessário ter experiência!"
     free_title: "Quanto custa?"
 #    cost_china: "CodeCombat in China is free for the first five levels, after which it costs $9.99 USD per month for access to our other 140+ levels on our exclusive China servers."
-#    free_1: "There are 80+ FREE levels which cover every concept."
-#    free_2: "A monthly subscription provides access to video tutorials and extra practice levels."
+    free_1: "Há 80+ níveis GRATUITOS que abordam cada conceito."
+    free_2: "Uma subscrição mensal garante acesso a tutoriais em vídeo e a níveis extra para praticar."
     teacher_subs_title: "Os professores recebem uma subscrição gratuita!"
     teacher_subs_1: "Por favor, preenche o nosso"
     teacher_subs_2: "Inquérito para Professores"
@@ -616,12 +616,12 @@
 #    monitor_progress_3: "To add a student, send them the invite link for your Clan, which is on the"
 #    monitor_progress_4: "page."
 #    monitor_progress_5: "After they join, you will see a summary of the student's progress on your Clan's page."
-#    private_clans_1: "Private Clans provide increased privacy and detailed progress information for each student."
-#    private_clans_2: "To create a private Clan, check the 'Make clan private' checkbox when creating a"
-#    private_clans_3: "."
+    private_clans_1: "Os Clãs Privados garantem privacidade e informações sobre o progresso de cada estudante superiores."
+    private_clans_2: "Para criares um Clã privado, marca a caixa 'Tornar o clã privado' aquando da criação de um"
+    private_clans_3: "."
     who_for_title: "Para quem é o CodeCombat?"
-#    who_for_1: "We recommend CodeCombat for students aged 9 and up. No prior programming experience is needed."
-#    who_for_2: "We've designed CodeCombat to appeal to both boys and girls."
+    who_for_1: "Recomendamos o CodeCombat para estudantes com idade superior a 9. Não é necessária nenhuma experiência de programação prévia."
+    who_for_2: "O CodeCombat foi pensado de forma a ser apelativo tanto para rapazes como para raparigas."
     material_title: "Quanto material há?"
 #    material_china: "Approximately 30 hours of gameplay spread over 140+ subscriber-only levels so far, with new levels every week."
 #    material_1: "Approximately 10 hours of free content and an additional 20 hours of subscriber content, with new levels every week."
@@ -656,7 +656,7 @@
     contact_2: "se tiveres mais questões."
     description_1: "Oferecemos subscrições gratuitas a professores para efeitos de avaliação. Na nossa página para"
     description_2: "professores"
-    description_3: ", podes encontar muitas mais informações."
+    description_3: "podes encontar muitas mais informações."
     description_4: "Por favor, preenche este pequeno inquérito e nós enviar-te-emos, por e-mail, as instruções de configuração."
     email: "Endereço de E-mail"
     school_city: "Nome da Escola, Cidade"


make lint happy

make lint happy

--- src/CLI.coffee
+++ src/CLI.coffee
@@ -112,8 +112,8 @@
     data = env.loadData
     # TODO allow loading json from stdin
     parser.parse data
-  else # fetch + process
+  else # fetch + process
     printDefaultInfo env.config
     processOutput = (data, config) ->
-        parser.parse data
+      parser.parse data
     extractor.extract env.config, processOutput


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/number_extensions.coffee
+++ src/number_extensions.coffee
@@ -73,7 +73,8 @@
 Number::round = ->
   Math.round(this)

-##
+###*
+
 Number::circularPoints = (n, block) ->
   n.times (i) ->
     block(Point.fromAngle((i/n).turns))


Light clean up

Light clean up

--- lib/analytics.coffee
+++ lib/analytics.coffee
@@ -1,26 +1,27 @@
-_ = require 'underscore'
-_s = require 'underscore.string'
-sd = require('sharify').data
-qs = require('querystring')
+{ extend, reduce } = require 'underscore'
+{ capitalize } = require 'underscore.string'
+{ NODE_ENV, CURRENT_USER, GOOGLE_ANALYTICS_ID } = require('sharify').data

 module.exports = (options) =>
   return if module.exports.getUserAgent()?.indexOf?('PhantomJS') > -1

   { @ga, @location } = options
+
   @location ?= window?.location
-  if sd.GOOGLE_ANALYTICS_ID
+
+  if GOOGLE_ANALYTICS_ID
     googleAnalyticsParams = cookieDomain: 'are.na'

-    if sd.CURRENT_USER?.id
-      googleAnalyticsParams.userId = sd.CURRENT_USER?.id
+    if CURRENT_USER?.id
+      googleAnalyticsParams.userId = CURRENT_USER?.id

-    @ga? 'create', sd.GOOGLE_ANALYTICS_ID, googleAnalyticsParams
+    @ga? 'create', GOOGLE_ANALYTICS_ID, googleAnalyticsParams

 module.exports.getUserAgent = ->
   window?.navigator?.userAgent

 module.exports.trackPageview = (args = {}) =>
-  opts = _.extend { hitType: 'pageview' }, args
+  opts = extend { hitType: 'pageview' }, args
   ga? 'send', opts

 module.exports.trackOutboundLink = (url, cb = $.noop) =>
@@ -29,13 +30,14 @@
     'hitCallback': cb

 module.exports.registerCurrentUser = ->
-  userType = if sd.CURRENT_USER then "Logged In" else "Logged Out"
+  userType = if CURRENT_USER then "Logged In" else "Logged Out"
   ga?('set', 'dimension1', userType)
-  ga?('set', 'dimension2', sd.CURRENT_USER?.registered) if sd.CURRENT_USER
+  ga?('set', 'dimension2', CURRENT_USER?.registered) if CURRENT_USER

 module.exports.modelNameAndIdToLabel = (modelName, id) ->
   throw new Error('Requires modelName and id') unless modelName? and id?
-  "#{_s.capitalize(modelName)}:#{id}"
+
+  "#{capitalize modelName}:#{id}"

 categories =
   impression: 'Impressions'
@@ -50,7 +52,7 @@
   other: 'Other Events'

 module.exports.track = track =
-  _.reduce(Object.keys(categories), (memo, kind) ->
+  reduce(Object.keys(categories), (memo, kind) ->
     memo[kind] = (description, options = {}) ->
       # Send google analytics event
       ga? 'send', {


Change DomUtils.makeXPath to loop as an array rather than an object

This fixes the tests, which were broken by makeXPath trying to recurse
over Arrays with an augmented prototype.

--- lib/dom_utils.coffee
+++ lib/dom_utils.coffee
@@ -32,8 +32,8 @@
   #
   makeXPath: (elementArray) ->
     xpath = []
-    for i of elementArray
-      xpath.push("//" + elementArray[i], "//xhtml:" + elementArray[i])
+    for element in elementArray
+      xpath.push("//" + element, "//xhtml:" + element)
     xpath.join(" | ")

   evaluateXPath: (xpath, resultType) ->


Rename isReadme to isReadmePath

Rename isReadme to isReadmePath

--- lib/file-view.coffee
+++ lib/file-view.coffee
@@ -17,7 +17,7 @@
     @subscribe $(window), 'focus', => @updateStatus()

     extension = fs.extension(@getPath())
-    if fs.isReadme(@getPath())
+    if fs.isReadmePath(@getPath())
       @fileName.addClass('readme-icon')
     else if fs.isCompressedExtension(extension)
       @fileName.addClass('compressed-icon')


Use binary icon for .woff and .DS_Store extensions

--- lib/file-view.coffee
+++ lib/file-view.coffee
@@ -25,6 +25,8 @@
       @fileName.addClass('image-icon')
     else if fs.isPdfExtension(extension)
       @fileName.addClass('pdf-icon')
+    else if fs.isBinaryExtension(extension)
+      @fileName.addClass('binary-icon')
     else
       @fileName.addClass('text-icon')


Fix format command call

Fix format command call

--- lib/go-format.coffee
+++ lib/go-format.coffee
@@ -15,7 +15,7 @@
     atom.workspaceView.command 'go-format:format', =>
       editor = atom.workspace.getActiveEditor()
       if editor
-        @view.format(editor)
+        @format(editor)

   deactivate: ->
     @view.destroy()


"Coming soon" warning for Delete and View Subscribers buttons

--- client/landing/app/Applications/Groups.kdapplication/Views/productsettingsview.coffee
+++ client/landing/app/Applications/Groups.kdapplication/Views/productsettingsview.coffee
@@ -125,10 +125,15 @@

     @clientsButton = new KDButtonView
       title    : "View Buyers"
-      callback : =>
+      callback : ->
+        new KDNotificationView
+          title: "Coming soon!"

     @deleteButton = new KDButtonView
-      title: "-"
+      title    : "-"
+      callback : ->
+        new KDNotificationView
+          title: "Coming soon!"

   viewAppended: JView::viewAppended


updating api to post json for now to match backend

--- src/api.coffee
+++ src/api.coffee
@@ -42,6 +42,8 @@
       if payload?
         opts.data = JSON.stringify(payload)
         opts.processData = false
+        # For now, the backend is expecting JSON and cannot accept url-encoded forms
+        opts.contentType = 'application/json'

       url = "#{url}.json" if IS_LOCAL


Hotfix: fix wrong srid in high contrast map bbox query.

--- src/app.coffee
+++ src/app.coffee
@@ -225,7 +225,7 @@
                 unitList.pageSize = PAGE_SIZE
                 unitList.setFilter 'bbox', bboxString
                 layer = p13n.get 'map_background_layer'
-                unitList.setFilter 'bbox_srid', if layer == 'servicemap' then 3067 else 3879
+                unitList.setFilter 'bbox_srid', if layer in ['servicemap', 'accessible_map'] then 3067 else 3879
                 unitList.setFilter 'only', 'name,location,root_services'
                 # Default exclude filter: statues, wlan hot spots
                 unitList.setFilter 'exclude_services', '25658,25538'


escape clears the selection cursor too

escape clears the selection cursor too

--- src/app.coffee
+++ src/app.coffee
@@ -17,9 +17,13 @@
     this.ids.album = {}
     this.ids.track = {}
     this.ids.playlist = {}
+  fullClear: ->
+    this.clear()
+    this.type = null
+    this.cursor = null
   selectOnly: (sel_name, key) ->
+    this.clear()
     this.type = sel_name
-    this.clear()
     this.ids[sel_name][key] = true
     this.cursor = key

@@ -421,8 +425,7 @@
         if $("#menu").get().length > 0
           removeContextMenu()
           return
-        # clear selection
-        selection.clear()
+        selection.fullClear()
         refreshSelection()
     32: # space
       ctrl:    no


Add multi room support to talker, using multiple sockets as a room context.

--- src/hubot/talker.coffee
+++ src/hubot/talker.coffee
@@ -7,7 +7,7 @@
 class Talker extends Robot
   send: (user, strings...) ->
     strings.forEach (str) =>
-      @bot.write {"type": "message", "content": str}
+      @bot.write user.room, {"type": "message", "content": str}

   reply: (user, strings...) ->
     strings.forEach (str) =>
@@ -15,49 +15,50 @@

   run: ->
     self = @
-    options =
-      token:   process.env.HUBOT_TALKER_TOKEN
-      rooms:   process.env.HUBOT_TALKER_ROOMS
+    token = process.env.HUBOT_TALKER_TOKEN
+    rooms = process.env.HUBOT_TALKER_ROOMS.split(',')

-    console.log options
-    bot = new TalkerClient(options)
+    bot = new TalkerClient()
     console.log bot

-    bot.connect ->
-      options.rooms.split(',').forEach (room) ->
-        console.log "Entering room: " + room
-        bot.write {"room": room, "token": options.token, "type": "connect"}
+    ping = (room)->
+      setInterval ->
+        bot.write room, {type: "ping"}
+      , 25000

-      setInterval ->
-        bot.write {type: "ping"}
-      , 25000
+    bot.on "Ready", (room)->
+      message = {"room": room, "token": token, "type": "connect"}
+      bot.write room, message
+      ping room

     bot.on "Users", (message)->
       for user in message.users
         self.userForId(user.id, user)

-    bot.on "TextMessage", (message)->
-      console.log message
-
-      author = self.userForId(message.user.id, message.user)
+    bot.on "TextMessage", (room, message)->
+      content = message.content

       # Replace "@mention" with "mention: ", case-insensitively
       regexp = new RegExp("\\b@#{self.quoteRegex(self.name)}\\b", 'i')
       content = message.content.replace(regexp, "#{self.name}: ")

-      self.receive new Robot.TextMessage(author, content)
+      self.receive new Robot.TextMessage self.userForMessage(room, message), content

-    bot.on "EnterMessage", (message) ->
-      console.log message
-      author = self.userForId(message.user.id, message.user)
-      self.receive new Robot.EnterMessage(author)
+    bot.on "EnterMessage", (room, message) ->
+      self.receive new Robot.EnterMessage self.userForMessage(room, message)

-    bot.on "LeaveMessage", (message) ->
-      console.log message
-      author = self.userForId(message.user.id, message.user)
-      self.receive new Robot.LeaveMessage(author)
+    bot.on "LeaveMessage", (room, message) ->
+      self.receive new Robot.LeaveMessage self.userForMessage(room, message)
+
+    for room in rooms
+      bot.sockets[room] = bot.createSocket(room)

     @bot = bot
+
+  userForMessage: (room, message)->
+    author = @userForId(message.user.id, message.user)
+    author.room = room
+    author

   quoteRegex: (string) ->
     string.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
@@ -65,66 +66,61 @@
 module.exports = Talker

 class TalkerClient extends EventEmitter
-  constructor: (options) ->
-    @token         = options.token
-    @rooms         = options.rooms.split(",")
+  constructor: ->
     @domain        = 'talkerapp.com'
     @encoding      = 'utf8'
     @port          = 8500
+    @sockets       = {}

-  connect: (callback) ->
+  createSocket: (room) ->
     self = @

-    @socket = tls.connect @port, @domain, ->
-      # callback called only after successful socket socket
-      console.log "Connected to " + self.domain
-      self.socket.setEncoding @encoding
-      callback()
+    socket = tls.connect @port, @domain, ->
+      console.log("Connected to room #{room}.")
+      self.emit "Ready", room

     #callback
-    @socket.addListener 'data', (data) ->
+    socket.on 'data', (data) ->
       for line in data.split '\n'
-        console.log line
-
-        message = unless line is ''
-          message = JSON.parse(line)
-        else
-          message = null
+        message = if line is '' then null else JSON.parse(line)

         if message
-          if message.type == "connected"
-            self.emit "Connected"
+          console.log "From room #{room}: #{line}"
           if message.type == "users"
             self.emit "Users", message
           if message.type == "message"
-            self.emit "TextMessage", message
+            self.emit "TextMessage", room, message
           if message.type == "join"
-            self.emit "EnterMessage", message
+            self.emit "EnterMessage", room, message
           if message.type == "leave"
-            self.emit "LeaveMessage", message
+            self.emit "LeaveMessage", room, message
           if message.type == "error"
-            self.disconnect message.message
+            self.disconnect room, message.message

-
-    @socket.addListener "eof", ->
+    socket.addListener "eof", ->
       console.log "eof"
-    @socket.addListener "timeout", ->
+    socket.addListener "timeout", ->
       console.log "timeout"
-    @socket.addListener "end", ->
+    socket.addListener "end", ->
       console.log "end"

-  write: (arguments) ->
+    socket.setEncoding @encoding
+
+    socket
+
+  write: (room, arguments) ->
     self = @
+    @sockets[room]

-    if @socket.readyState != 'open'
-      return self.disconnect 'cannot send with readyState: ' + @socket.readyState
+    if @sockets[room].readyState != 'open'
+      return @disconnect 'cannot send with readyState: ' + @sockets[room].readyState

     message = JSON.stringify(arguments)
-    console.log message
+    console.log "To room #{room}: #{message}"

-    @socket.write message, @encoding
+    @sockets[room].write message, @encoding

-  disconnect: (why) ->
-    if @socket.readyState != 'closed'
-      @socket.close
+  disconnect: (room, why) ->
+    if @sockets[room] != 'closed'
+      @sockets[room]
       console.log 'disconnected (reason: ' + why + ')'


use heroku port env var

use heroku port env var

--- src/hubot/twilio.coffee
+++ src/hubot/twilio.coffee
@@ -37,7 +37,7 @@
       response.writeHead 200, 'Content-Type': 'text/plain'
       response.end()

-    server.listen (parseInt(process.env.HUBOT_SMS_PORT) || 8080), "0.0.0.0"
+    server.listen (parseInt(process.env.PORT) || 8080), "0.0.0.0"

   handle: (body, from) ->
     return if body.length == 0


XHR factory

XHR factory

--- src/loader/index.coffee
+++ src/loader/index.coffee
@@ -12,6 +12,19 @@
     constructor: (@self_name, @props) ->
         @name = @constructor.name
         @message = "During `#{@self_name}` loading window object was polluted with: #{props}"
+
+XHR = ->
+    for factgory in [
+                    -> new XMLHttpRequest()
+                    -> new ActiveXObject("Msxml2.XMLHTTP")
+                    -> new ActiveXObject("Msxml3.XMLHTTP")
+                    -> new ActiveXObject("Microsoft.XMLHTTP")
+                    ]
+        try
+            return factory()
+        catch
+            continue
+    return

 class BasicLoader
     constructor: (options) ->


:racehorse: Cache ranges in MarkerIndex

:racehorse: Cache ranges in MarkerIndex

--- src/marker-index.coffee
+++ src/marker-index.coffee
@@ -2,6 +2,7 @@
 Range = require "./range"
 {addSet, subtractSet, intersectSet, setEqual} = require "./set-helpers"

+Zero = Point.zero()
 BRANCHING_THRESHOLD = 3

 class Node
@@ -248,10 +249,8 @@
   dump: (offset, snapshot) ->
     end = offset.traverse(@extent)
     @ids.forEach (id) ->
-      if snapshot[id]?
-        snapshot[id].end = end
-      else
-        snapshot[id] = Range(offset, end)
+      snapshot[id].start ?= offset
+      snapshot[id].end = end
     end

   findContaining: (point, set) ->
@@ -292,15 +291,18 @@

   insert: (id, start, end) ->
     assertValidId(id)
+    @rangeCache[id] = Range(start, end)
     if splitNodes = @rootNode.insert(new Set().add(id + ""), start, end)
       @rootNode = new Node(splitNodes)

   delete: (id) ->
     assertValidId(id)
+    delete @rangeCache[id]
     @rootNode.delete(id)
     @condenseIfNeeded()

   splice: (position, oldExtent, newExtent) ->
+    @clearRangeCache()
     if splitNodes = @rootNode.splice(position, oldExtent, newExtent, @exclusiveIds, new Set)
       @rootNode = new Node(splitNodes)
     @condenseIfNeeded()
@@ -320,10 +322,12 @@
       Range(start, @getEnd(id))

   getStart: (id) ->
-    @rootNode.getStart(id)
+    if entry = @rangeCache[id]
+      entry.start ?= @rootNode.getStart(id)

   getEnd: (id) ->
-    @rootNode.getEnd(id)
+    if entry = @rangeCache[id]
+      entry.end ?= @rootNode.getEnd(id)

   findContaining: (start, end) ->
     containing = new Set
@@ -360,17 +364,24 @@
     result

   clear: ->
+    @rootNode = new Leaf(Point.infinity(), new Set)
     @exclusiveIds = new Set
-    @rootNode = new Leaf(Point.infinity(), new Set)
+    @clearRangeCache()

   dump: ->
-    snapshot = {}
-    @rootNode.dump(Point.zero(), snapshot)
-    snapshot
+    unless @rangeCacheFresh
+      @rootNode.dump(Point.zero(), @rangeCache)
+      @rangeCacheFresh = true
+    @rangeCache

   ###
   Section: Private
   ###
+
+  clearRangeCache: ->
+    @rangeCache = {}
+    @rootNode.ids.forEach (id) => @rangeCache[id] = templateRange()
+    @rangeCacheFresh = false

   condenseIfNeeded: ->
     while @rootNode.children?.length is 1
@@ -380,3 +391,8 @@
 assertValidId = (id) ->
   unless typeof id is 'string'
     throw new TypeError("Marker ID must be a string")
+
+templateRange = ->
+  range = new Range(Zero, Zero)
+  range.start = range.end = null
+  range


Use v1 UUIDs so we can check the time of generation

--- src/microservice.coffee
+++ src/microservice.coffee
@@ -338,7 +338,7 @@
       callback err

   requestLogger: (req, res, next) ->
-    req.id = uuid.v4()
+    req.id = uuid.v1()
     weblog = req.app.log.child
       req_id: req.id
       url: req.originalUrl


OHM-65: Updated Schema naming

OHM-65: Updated Schema naming

--- src/model/audits.coffee
+++ src/model/audits.coffee
@@ -7,7 +7,7 @@
   "codeSystemName": { type: String, required: false }

-activeParticipantSchema = new Schema
+ActiveParticipantSchema = new Schema
   "userID": { type: String, required: false }
   "alternativeUserID": { type: String, required: false }
   "userIsRequestor": { type: String, required: false }
@@ -27,7 +27,7 @@
     "value": { type: String, required: false }

-auditRecordSchema = new Schema
+AuditRecordSchema = new Schema
   "rawMessage":  { type: String, required: false }
   "eventIdentification":
     "eventDateTime": { type: Date, required: true, default: Date.now }
@@ -35,9 +35,9 @@
     "eventActionCode": { type: String, required: false }
     "eventID": codeTypeSchema
     "eventTypeCode": codeTypeSchema
-  "activeParticipant": [ activeParticipantSchema ]
+  "activeParticipant": [ ActiveParticipantSchema ]
   "auditSourceIdentification":
     "auditSourceID": { type: String, required: false }
   "participantObjectIdentification": [ ParticipantObjectIdentificationSchema ]

-exports.Audit = mongoose.model 'Audit', auditRecordSchema+exports.Audit = mongoose.model 'Audit', AuditRecordSchema


fix longstanding TODO in getCallerClass

fix longstanding TODO in getCallerClass

--- src/natives/main.coffee
+++ src/natives/main.coffee
@@ -1417,8 +1417,11 @@
       ]
       Reflection: [
         o 'getCallerClass(I)Ljava/lang/Class;', (rs, frames_to_skip) ->
-            #TODO: disregard frames assoc. with java.lang.reflect.Method.invoke() and its implementation
             caller = rs.meta_stack().get_caller(frames_to_skip)
+            # Note: disregard frames associated with
+            #   java.lang.reflect.Method.invoke() and its implementation.
+            if caller.name.indexOf('Ljava/lang/reflect/Method;::invoke') is 0
+              caller = rs.meta_stack().get_caller(frames_to_skip + 1)
             cls = caller.method.cls
             return cls.get_class_object(rs)
         o 'getClassAccessFlags(Ljava/lang/Class;)I', (rs, class_obj) ->


there is no cb

there is no cb

--- src/pages/download.iced
+++ src/pages/download.iced
@@ -35,6 +35,4 @@
       await fs.writeFile(key, page.body_html, defer(err))
       console.log colors.green("Downloaded #{key}")

-  return cb(null)
-
   done()


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -32,6 +32,7 @@

   rightEnemy = GameObject
     x: 100
-    y
+    y: 50
+    height

 module()


Follow mixin

Follow mixin

--- test/follow.coffee
+++ test/follow.coffee
@@ -21,4 +21,5 @@
   fastEnemy = GameObject
     x: 50

+
 module()


Classroom: Showing a loader view until class manifest fetched and parsed.

--- client/landing/app/Applications/Classroom.kdapplication/Views/classroomclassesview.coffee
+++ client/landing/app/Applications/Classroom.kdapplication/Views/classroomclassesview.coffee
@@ -51,6 +51,10 @@
     @noRelatedClass.show()   unless @getData().related
     @noEnrolledClass.show()  unless @getData().enrolled

+  viewAppended: ->
+    super
+    thumbView.loader.show() for thumbView in @thumbViews
+
   pistachio: ->
     """
       {{> @enrolledContainer}}


Section: Add unit tests.

Section: Add unit tests.

--- test/prompt.coffee
+++ test/prompt.coffee
@@ -25,3 +25,24 @@
         exists.should.equal 0
         done()

+
+describe 'Section', ->
+  section = new Impromptu.Section 'id1'
+
+  ['content', 'background', 'foreground'].forEach (property) ->
+    it "#{property} should be clear", (done) ->
+      section[property] 'section', (err, result) ->
+        should.not.exist result
+        done()
+
+    it "#{property} should set data", (done) ->
+      section[property] 'section', "#{property}-value", (err) ->
+        section[property] 'section', (err, result) ->
+          result.should.equal "#{property}-value"
+          done()
+
+  it "should remove data", (done) ->
+    section.del 'section', (err) ->
+      section.content 'section', (err, result) ->
+        should.not.exist result
+        done()


account: deletion: survey link updated

account: deletion: survey link updated

--- client/account/lib/deletemodalview.coffee
+++ client/account/lib/deletemodalview.coffee
@@ -75,7 +75,7 @@
       JUser.unregister username.getValue(), (err) =>
         if err then new KDNotificationView title : 'There was a problem, please try again!'
         else
-          surveyLink = 'https://docs.google.com/forms/d/1fiC6wSThfXxtLpdRlQ7qnNvJrClqdUrmOT_L-_cu1tw/viewform'
+          surveyLink = 'https://docs.google.com/forms/d/1pNRfkqRJSYh8k7Z5JnZH06P1QXW5q8hfr6l8kLV_iOU/viewform'
           @setTitle 'Account successfully deleted'
           @setContent """
             <div class='modalformline'>


hiding loginScreen should set -winHeight, not -winWidth

--- client/app/MainApp/login/loginview.coffee
+++ client/app/MainApp/login/loginview.coffee
@@ -279,7 +279,7 @@

   hide:(callback)->

-    @setY -@getSingleton('windowController').winWidth
+    @setY -@getSingleton('windowController').winHeight

     cb = =>
       @emit "LoginViewHidden"


Add link logic for close conversation button

--- client/app/components/conversation.coffee
+++ client/app/components/conversation.coffee
@@ -123,8 +123,9 @@
                     'data-message-id': @props.message.get 'id'
                     @props.message.get 'subject'
                 @renderToolbar()
-                button
+                a
                     className: 'clickable btn btn-default fa fa-close'
+                    href: @buildClosePanelUrl 'second'

             for glob, index in messages
                 if _.isArray glob


Remove deprecated integrations helper

Remove deprecated integrations helper

--- client/app/lib/helpers/integration.coffee
+++ client/app/lib/helpers/integration.coffee
@@ -1,234 +0,0 @@
-kd           = require 'kd'
-remote       = require 'app/remote'
-globals      = require 'globals'
-doXhrRequest = require 'app/util/doXhrRequest'
-whoami       = require 'app/util/whoami'
-
-
-list = (callback) ->
-
-  doXhrRequest
-    type     : 'GET'
-    endPoint : '/api/integration/'
-  , (err, response) ->
-
-    return callback err  if err
-
-    return callback null, response.data
-
-find = (query, callback) ->
-
-  list (err, items) ->
-
-    return callback err  if err
-
-    query = decodeURIComponent query
-
-    for item in items when item.name is query or item.title is query
-      integration = item
-
-    return callback { message: 'Not found' }  unless integration
-
-    fetchChannels (err, channels) ->
-      return callback err  if err
-
-      integration.channels = channels
-
-      callback null, integration
-
-
-fetchChannels = (callback) ->
-
-  kd.singletons.socialapi.account.fetchChannels (err, channels) ->
-
-    return callback err  if err
-
-    decoratedChannels = []
-
-    for channel in channels
-      { id, typeConstant, name, purpose, participantsPreview } = channel
-
-      # TODO after refactoring the private channels, we also need to add them here
-      if typeConstant is 'topic' or typeConstant is 'group'
-        decoratedChannels.push { name:"##{name}", id }
-
-    callback null, decoratedChannels
-
-
-fetch = (name, callback) ->
-
-  doXhrRequest
-    type     : 'GET'
-    endPoint : "/api/integration/#{name}"
-  , (err, response) ->
-
-    return callback err  if err
-
-    return callback null, response.data
-
-
-fetchChannelIntegration = (options, callback) ->
-  { id } = options
-
-  doXhrRequest
-    type     : 'GET'
-    endPoint : "/api/integration/channelintegration/#{id}"
-  , (err, response) ->
-
-    return callback err  if err
-
-    return callback null, response.data
-
-
-create = (options, callback) ->
-
-  doXhrRequest
-    endPoint : '/api/integration/channelintegration'
-    type     : 'POST'
-    data     : options
-  , (err, response) ->
-
-    return callback err  if err
-
-    return callback null, response.data
-
-
-update = (options, callback) ->
-
-  { id } = options
-  doXhrRequest
-    endPoint : "/api/integration/channelintegration/#{id}"
-    type     : 'POST'
-    data     : options
-  , callback
-
-
-remove = (id, callback) ->
-
-  doXhrRequest
-    endPoint : "/api/integration/channelintegration/#{id}"
-    type     : 'DELETE'
-  , callback
-
-
-listChannelIntegrations = (callback) ->
-
-  doXhrRequest
-    endPoint : '/api/integration/channelintegration'
-    type     : 'GET'
-  , (err, response) ->
-    return callback err  if err
-
-    return callback null, response.data
-
-
-regenerateToken = (options, callback) ->
-
-  doXhrRequest
-    endPoint : '/api/integration/channelintegration/token'
-    type     : 'POST'
-    data     : options
-  , (err, response) ->
-    return callback err  if err
-
-    return callback null, response.data
-
-
-fetchAllGithubRepos = (callback) ->
-
-  page = 1
-  result = []
-
-  fetch = ->
-    _options =
-      method     : 'repos.getAll'
-      pluck      : ['full_name', 'permissions.admin']
-      options    :
-        per_page : 100
-        page     : page
-
-    remote.api.Github.api _options, (err, response) ->
-
-      return callback err  if err
-
-      result = result.concat response
-
-      return callback null, result if response.length < 100
-
-      page++
-
-      fetch()
-
-  fetch()
-
-
-fetchConfigureData = (options, callback) ->
-
-  fetchChannels (err, channels) ->
-    return callback err  if err
-
-    fetchChannelIntegration options, (err, response) ->
-      return callback err  if err
-
-      { integration, channelIntegration } = response
-
-      { id, token, createdAt, updatedAt, description,
-        integrationId, channelId, isDisabled, settings } = channelIntegration
-
-      description     = description or integration.summary
-      webhookUrl      = "#{globals.config.webhookMiddleware.url}/#{integration.name}/#{token}"
-      selectedEvents  = []
-      name            = settings?.customName or integration.title
-      selectedChannel = channelId
-      data            = { channels, id, integration, token, createdAt, name, selectedChannel,
-                          updatedAt, description, integrationId, webhookUrl, isDisabled }
-
-
-      if channelIntegration.settings
-        data.selectedEvents = try JSON.parse channelIntegration.settings.events catch e then []
-
-      if integration.settings?.events
-        events = try JSON.parse integration.settings.events catch e then null
-        data.settings = { events }
-
-      data.authorizable = integration.settings?.authorizable is 'true'
-
-      return callback null, data  unless data.authorizable
-
-      whoami().isAuthorized integration.name, (err, isAuthorized) ->
-
-        return callback err  if err
-
-        return callback null, data  unless isAuthorized
-
-        data.isAuthorized = isAuthorized
-
-        if integration.name is 'github'
-          fetchAllGithubRepos (err, repositories) ->
-            if err
-              if err.code is 401
-                data.isAuthorized = no
-                return callback null, data
-              else
-                return callback err
-            data.repositories = repositories
-            data.selectedRepository = channelIntegration.settings?.repository
-            callback null, data
-        else
-          callback null, data
-
-
-module.exports = {
-  list
-  find
-  fetch
-  create
-  update
-  remove
-  fetchChannels
-  fetchConfigureData
-  fetchChannelIntegration
-  listChannelIntegrations
-  regenerateToken
-  fetchAllGithubRepos
-}


remove unuser label

remove unuser label

--- lib/installed-package-view.coffee
+++ lib/installed-package-view.coffee
@@ -65,7 +65,6 @@
       @packageRepo.text(repoName.substring(1)).show()
     else
       @packageRepo.hide()
-      @isCorePackageLabel.hide()

     authorUsername = @getAuthorUserName()
     authorName = @pack.metadata?.author?.name or @pack.metadata?.author or authorUsername