lay foundations for jumpin form

lay foundations for jumpin form

--- src/frontend/home.coffee
+++ src/frontend/home.coffee
@@ -23,6 +23,28 @@
         marginTop   : '+=20'
     }, 600

+class JumpInStep
+    constructor : (@father, @name) ->
+        @_jqBtn     = PrivateValue.GetOnly ($ '#' + @name + 'Btn')
+        @_jqDiv     = PrivateValue.GetOnly ($ 'div#' + @name)
+        @_jqCancel  = PrivateValue.GetOnly ((do @_jqDiv.get).find '#' + @name + 'Cancel')
+        (do @_jqBtn.get).click @display
+        (do @_jqCancel.get).click @hide
+
+    display : (event) =>
+        do @father.hide
+        (do @_jqDiv.get).fadeTo 0.01
+        (do @_jqDiv.get).animate {
+            left    : '-=290'
+        }, 600
+
+    hide    : (event) =>
+        do @father.show
+        (do @_jqDiv.get).fadeTo 0.99
+        (do @_jqDiv.get).animate {
+            left    : '+=290'
+        }, 600
+
 class ChoiceForm
     constructor : (@name) ->
         @_jqElem    = PrivateValue.GetOnly ($ '#' + @name)
@@ -41,6 +63,27 @@
         (do @_jqElem.get).fadeIn 600

     onSubmit    : (event) =>
+
+class JumpInForm extends ChoiceForm
+    constructor : (@name) ->
+        super @name
+        @_jqFirstStep   = PrivateValue.GetOnly (do @_jqElem.get).find '#stepOne'
+        @steps  = [
+            new JumpInStep this, 'newRoom'
+            new JumpInStep this, 'joinRoom'
+        ]
+
+    hide : () =>
+        (do @_jqFirstStep.get).fadeTo 0.99
+        (do @_jqFirstStep.get).animate {
+            left    : '-=290'
+        }, 600
+
+    show : () =>
+        (do @_jqFirstStep.get).fadeTo 0.01
+        (do @_jqFirstStep.get).animate {
+            left    : '+=290'
+        }, 600

 class SignUpForm extends ChoiceForm
     onSubmit    : (event) =>
@@ -75,7 +118,7 @@
     do ($ 'span#choicesContainer > div div').show
     do FadeIn
     choices =
-        '#jumpIn'   : new Choice 'jumpIn'
+        '#jumpIn'   : new Choice 'jumpIn', JumpInForm
         '#logIn'    : new Choice 'logIn'
         '#signUp'   : new Choice 'signUp', SignUpForm


Fix HTTP client JSON parse error when receiving multiple events.

--- lib/assets/javascripts/websocket_rails/http_connection.js.coffee
+++ lib/assets/javascripts/websocket_rails/http_connection.js.coffee
@@ -32,6 +32,7 @@
     if @_conn.readyState == 3
       data         = @_conn.responseText.substring @last_pos
       @last_pos    = @_conn.responseText.length
+      data = data.replace "]][[", "],["
       console.log data
       decoded_data = JSON.parse data
       @dispatcher.new_message decoded_data


Test kernel handling

Test kernel handling

--- spec/kernel-manager-spec.coffee
+++ spec/kernel-manager-spec.coffee
@@ -2,6 +2,7 @@

 path = require 'path'
 fs = require 'fs'
+_ = require 'lodash'

 describe 'Kernel manager', ->
     firstKernelSpecString = '''{
@@ -48,11 +49,64 @@
     kernelSpecs.kernelspecs.python2 = secondKernelSpec.kernelspecs.python2
     kernelSpecsString = JSON.stringify kernelSpecs

+    mockGrammar =
+        name: 'grammarLanguage'
+
+    mockKernel =
+        kernelSpec:
+            language: 'kernelLanguage'
+        destroy: ->
+
     kernelManager = null

     beforeEach ->
         kernelManager = new KernelManager()
         atom.config.set 'Hydrogen.kernelspec', ''
+
+    describe 'constructor', ->
+        it 'should initialize @_runningKernels', ->
+            expect(kernelManager._runningKernels).toEqual({})
+        it 'should call @getKernelSpecsFromSettings', ->
+            spyOn(kernelManager, 'getKernelSpecsFromSettings')
+            kernelManager.constructor()
+            expect(kernelManager.getKernelSpecsFromSettings).toHaveBeenCalled()
+
+    describe 'destroy', ->
+        it 'should destroy all running kernels', ->
+            mockKernels =
+                kernel1: _.clone mockKernel
+                kernel2: _.clone mockKernel
+            spyOn(mockKernels.kernel1, 'destroy')
+            spyOn(mockKernels.kernel2, 'destroy')
+            kernelManager._runningKernels = mockKernels
+            kernelManager.destroy()
+            expect(mockKernels.kernel1.destroy).toHaveBeenCalled()
+            expect(mockKernels.kernel2.destroy).toHaveBeenCalled()
+            expect(kernelManager._runningKernels).toEqual({})
+
+    describe 'setRunningKernelFor', ->
+        it 'should set the running kernel for a grammar', ->
+            kernelManager.setRunningKernelFor mockGrammar, mockKernel
+            expect(kernelManager._runningKernels.grammarlanguage)
+                .not.toBeUndefined()
+            expect(kernelManager._runningKernels.grammarlanguage
+                .kernelSpec.language).toEqual('grammarlanguage')
+
+    describe 'destroyRunningKernelFor', ->
+        it 'should destroy a running kernel for a grammar', ->
+            mockKernels =
+                grammarlanguage: _.clone mockKernel
+                kernel2: _.clone mockKernel
+
+            spyOn(mockKernels.grammarlanguage, 'destroy')
+            spyOn(mockKernels.kernel2, 'destroy')
+            kernelManager._runningKernels = _.clone mockKernels
+            kernelManager.destroyRunningKernelFor mockGrammar
+
+            expect(mockKernels.grammarlanguage.destroy).toHaveBeenCalled()
+            expect(mockKernels.kernel2.destroy).not.toHaveBeenCalled()
+            expect(kernelManager._runningKernels.kernel2).not.toBeUndefined()
+            expect(kernelManager._runningKernels.grammarlanguage).toBeUndefined()

     describe 'getKernelSpecsFromSettings', ->
         it 'should parse kernelspecs from settings', ->
@@ -127,8 +181,8 @@
                     resolve()

     it 'should read lower case name from grammar', ->
-        grammar = atom.grammars.getGrammars()[0]
-        expect(kernelManager.getLanguageFor grammar).toEqual('null grammar')
+        expect(kernelManager.getLanguageFor mockGrammar)
+            .toEqual('grammarlanguage')

     it 'should update kernelspecs', ->
         waitsForPromise -> new Promise (resolve, reject) ->


Unfocus

Unfocus

--- spec/keymap-manager-spec.coffee
+++ spec/keymap-manager-spec.coffee
@@ -881,7 +881,7 @@
       expect(partiallyMatchedBindings.map ({command}) -> command).toEqual ['command-1', 'command-2']
       expect(keyboardEventTarget).toBe document.body

-    fit "emits `matched-partially` when a key binding partially matches an event for key bindings that have keyup events", ->
+    it "emits `matched-partially` when a key binding partially matches an event for key bindings that have keyup events", ->
       handler = jasmine.createSpy('matched-partially handler')
       keymapManager.onDidPartiallyMatchBindings handler
       keymapManager.add "test",


hide another popups

hide another popups

--- vendor/assets/javascripts/jquery.drappers.popup.js.coffee
+++ vendor/assets/javascripts/jquery.drappers.popup.js.coffee
@@ -8,10 +8,10 @@
   throw "$.drapper plugin hasn't been required This plugin depends on 'jquery.drapper' plugin. See https://github.com/aratak/jquery_drapper/ for details." if $.fn.drapper is undefined

   class Popup
-    constructor: (@button, @element, @cover)->
+    constructor: (@button_selector, @element_selector, @cover)->
       @cover = $(@cover)
-      @button = $(@cover).find @button
-      @element = $(@cover).find @element
+      @button = $(@cover).find @button_selector
+      @element = $(@cover).find @element_selector
       @hide()
       @bindEvents()

@@ -22,12 +22,15 @@
         false

     show: ->
+      @hideAnotherPopups()
       @element.show()
       $('body').click => @hide()

+    hideAnotherPopups: ->
+      $(@button_selector).hide()
+
     hide: ->
       @element.hide()
-      ;

   $.drappers['popup'] = ->


fix(travis): remove forced failling tests

--- specs/units/promise.spec.coffee
+++ specs/units/promise.spec.coffee
@@ -1,4 +1,4 @@
-describe spectacular.Promises, ->
+describe spectacular.Promise, ->

   it -> should exist


empty messages should not be dispatched

empty messages should not be dispatched

--- src/ui/dispatcher.coffee
+++ src/ui/dispatcher.coffee
@@ -99,7 +99,8 @@
     viewstate.selectNextConv offset
     ipc.send 'setfocus', viewstate.selectedConv

-handle 'sendmessage', (txt) ->
+handle 'sendmessage', (txt = '') ->
+    if !txt.trim() then return
     msg = userinput.buildChatMessage txt
     ipc.send 'sendchatmessage', msg
     conv.addChatMessagePlaceholder entity.self.id, msg


changed message on setpresence to be more verbose

--- src/ui/dispatcher.coffee
+++ src/ui/dispatcher.coffee
@@ -9,7 +9,7 @@
 clipboard = require('electron').clipboard

 {entity, conv, viewstate, userinput, connection, convsettings, notify} = require './models'
-{insertTextAtCursor, throttle, later, isImg} = require './util'
+{insertTextAtCursor, throttle, later, isImg, nameof} = require './util'

 'connecting connected connect_failed'.split(' ').forEach (n) ->
     handle n, -> connection.setState n
@@ -68,8 +68,9 @@

 handle 'setpresence', (r) ->
     if not r?.presence?.available?
-        console.log "setpresence event with unexpected value", r
-    entity.setPresence r.user_id.chat_id, r?.presence?.available
+        console.log "setpresence: User '#{nameof entity[r?.user_id?.chat_id]}' does not show his/hers/it status", r
+    else
+        entity.setPresence r.user_id.chat_id, r?.presence?.available

 handle 'update:unreadcount', ->
     console.log 'update'


Fix es-raf import.

Fix es-raf import.

--- src/utils/patches.coffee
+++ src/utils/patches.coffee
@@ -1,4 +1,4 @@
-import raf from 'es-raf'
+import {raf} from 'es-raf'

 # Shims/Polyfills
 window.Promise               ?= require 'broken'


load the yale header and footer in the global React app

--- app/assets/javascripts/components/app.cjsx
+++ app/assets/javascripts/components/app.cjsx
@@ -1,6 +1,6 @@
 React = require("react")
-MainHeader                    = require '../partials/main-header'
-Footer                        = require '../partials/footer'
+MainHeader                    = require '../partials/yale-header'
+Footer                        = require '../partials/yale-footer'
 API                           = require '../lib/api'
 Project                       = require 'models/project.coffee'


replace spaces with + in query parameters. fixes #44

--- app/assets/transit/lib/views/splash.coffee
+++ app/assets/transit/lib/views/splash.coffee
@@ -15,8 +15,8 @@

   go_to_plan: (event) =>
     event.preventDefault()
-    from = @$('#from_query').val()
-    to = @$('#to_query').val()
+    from = @$('#from_query').val().replace(/\s/g, '+')
+    to = @$('#to_query').val().replace(/\s/g, '+')
     if (to == null || to.length <= 3)
         @$('#to-location').addClass('btn-danger')
     else


Use new store.add method.

Use new store.add method.

--- app/client/js/songs/edit/react/page.coffee
+++ app/client/js/songs/edit/react/page.coffee
@@ -8,9 +8,10 @@

   ###*
     @param {app.Routes} routes
+    @param {app.songs.Store} store
     @constructor
   ###
-  constructor: (routes) ->
+  constructor: (routes, store) ->

     @create = React.createClass

@@ -52,7 +53,7 @@
         form = @refs['form'].getDOMNode()
         data = este.dom.serializeForm form
         song = new app.songs.Song data.name, data.chordpro
-        errors = song.validate()
+        errors = store.add song
         if errors.length
           field = form.elements[errors[0].prop]
           field.focus()


adding alternate keyboard shortcuts for indent/de-indent for inkdrop.

--- inkdrop_keymap.cson
+++ inkdrop_keymap.cson
@@ -5,4 +5,7 @@
 '.CodeMirror.vim-mode.replace-mode textarea':
   'ctrl-[': 'vim:exit-insert-mode'
   'j k': 'vim:exit-insert-mode'
-  'k j': 'vim:exit-insert-mode'+  'k j': 'vim:exit-insert-mode'
+'.CodeMirror textarea':
+  'alt-]': 'editor:indent-more'
+  'alt-[': 'editor:indent-less'


Adds keymap for insert mode CTRL-U

Adds keymap for insert mode CTRL-U

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -12,6 +12,7 @@

 'atom-text-editor.vim-mode.insert-mode':
   'ctrl-w': 'editor:delete-to-beginning-of-word'
+  'ctrl-u': 'editor:delete-to-beginning-of-line'

 'atom-text-editor.vim-mode:not(.insert-mode)':
   'h': 'vim-mode:move-left'


put the ctrl-c keybinding in the right place

Oh yeah, this is for insert mode to active command mode. Now it works.

--- keymaps/vim-mode.cson
+++ keymaps/vim-mode.cson
@@ -3,6 +3,7 @@

 '.vim-mode.insert-mode:not(.mini)':
   'escape': 'vim-mode:activate-command-mode'
+  'ctrl-c': 'vim-mode:activate-command-mode'

 '.vim-mode.command-mode:not(.mini)':
   '" a': 'vim-mode:register-prefix'


Don't need to pass size if buffer is provided.

--- nointro.coffee
+++ nointro.coffee
@@ -24,7 +24,7 @@
         entry
         .pipe writableStream
         .on 'close', ->
-          resolve writableStream.getContents(), entry.uncompressedSize
+          resolve writableStream.getContents()
       else
         entry.autodrain()
     .on 'close', reject


Remove old source fie

Remove old source fie

--- src/js/app/editor.coffee
+++ src/js/app/editor.coffee
@@ -1,556 +0,0 @@
-$ = require 'ejquery'
-ace = require 'ace/ace'
-Prelude = require 'vendor/prelude/prelude-browser-min'
-TimeLine = require 'app/UniqueTimeLine'
-Commands = require 'app/Commands'
-History = require 'app/History'
-CommandMode = require 'app/CommandMode'
-jsDump = require 'vendor/jsDump'
-
-console.log "Loaded sourceArea"
-Prelude.installPrelude window
-sourceFragment = "try:"
-compiledJS = ""
-compiler = null
-compilerOptions = null
-sourceCompiled = false
-autoCompile = true
-lastHit = 0
-lastErrorType = ""
-currentMode = ""
-AUTOSAVE_DELAY = 6000
-LAST_CODE = "lastEditedSourceCodeCOOKIE"
-UNNAMED_CODE = "@unnamed"
-TIMELINE_COOKIE = "timelineCOOKIE"
-sourceChanged = false
-saveName = UNNAMED_CODE
-cookieFilePrefix = "TeaTableFile_"
-timeline = new TimeLine
-
-addMessage = (text, id) ->
-  tag = if id?
-    " data-id=#{id}"
-  else
-    ""
-  newMessage = $("<pre#{tag}>#{text}</pre>")
-  $("#output").prepend newMessage
-  setMaxPreWidth newMessage
-
-eraseMessages = (except...) ->
-  excepts = join ", ", except
-  $("#output").children().not ->
-    $(this).find(excepts).size() > 0
-  .remove()
-
-getMessage = (n) ->
-  $("#output pre").eq n
-
-getCurrentMessage = ->
-  getMessage 0
-
-setCurrentMessage = (text, id) ->
-  getCurrentMessage().text(text).data "id", id
-
-isCurrentMessage = (id) ->
-  getCurrentMessage().data("id") is id
-
-log = (input...) ->
-  input = for i in input
-    jsDump.parse i ? "Nothing"
-  message = input.join ", "
-  if message.length > 0
-    addMessage lastMessage = message
-
-showImportantMessage = (type, message) ->
-  $("#messages").attr "class", type
-  $("#messages pre").text message
-  $("#messages").stop(true, true).fadeIn 200
-
-showErrorMessage = (type, message) ->
-  lastErrorType = type
-  showImportantMessage "errorMessage", message
-
-showFileMessage = (message) ->
-  showImportantMessage "fileMessage", message
-
-currentMessage = ->
-  $("#messages pre").text()
-
-hideError = (types...) ->
-  if lastErrorType in types
-    $("#messages").fadeOut 700
-
-# TODO: get rid of the duplication between dump and run
-dump = ->
-  compileCode() unless sourceCompiled
-  if compiledJS
-    log compiledJS
-  else
-    showErrorMessage "compiler", "Fix: '#{currentMessage()}' first"
-
-run = ->
-  compileCode() unless sourceCompiled
-  if compiledJS
-    execute compiledJS
-  else
-    showErrorMessage "compiler", "Fix: '#{currentMessage()}' first"
-
-# TODO: create help out of the command definitions, make them pluggable instead of defined here
-commands = Commands.initialize [
-  "dump", "d", -> dump()
-  "run", "r", -> run()
-  "erase", "e", -> eraseMessages arguments...
-  "copy", "c", -> selectLastOutput()
-  "link", "l", -> saveToAdress()
-  "toggle", "t", -> toggleAutoCompilation()
-  "save", -> switchCurrentCode arguments...
-  "load", -> loadFromClient arguments...
-  "close", -> exitCurrentCode()
-  "delete", -> removeFromClient arguments...
-  "modes", "m", -> displayModes()
-  "mode", -> setMode arguments...
-  "canvas", -> createCanvas arguments...
-  "browse", "b", -> displayClient()
-  "help", "h", -> log(helpDescription)
-  "ph", -> history.print(log)
-]
-
-modes =
-  CoffeeScript:
-    id: "coffeescript"
-
-  IcedCoffeeScript:
-    id: "icedcoffeescript"
-
-  Ometa:
-    id: "ometa"
-
-  MetaCoffee:
-    id: "metacoffee"
-
-modesList = ->
-  join "\n", map keys(modes), (mode) ->
-    "#{if mode is currentMode then "> " else "  "}#{mode}"
-
-displayModes = ->
-  addMessage modesList(), "modesList"
-
-setNewMode = (name, callback) ->
-  name = 'CoffeeScript' unless name?.length
-  if name isnt currentMode
-    setMode name, callback
-  else
-    callback?()
-
-setMode = (name, callback) ->
-  config = modes[name]
-  if config?
-    modePath = "compilers/#{config.id}/mode"
-    sourceArea.session.setMode modePath
-    commandArea.session.setMode new CommandMode "compilers/#{config.id}"
-    currentMode = name
-    if isCurrentMessage "modesList"
-      setCurrentMessage modesList(), "modesList"
-    else
-      showFileMessage "#{name} compiler loaded"
-    callback?()
-  # , (error) ->
-  #   log "#{name} loading failed"
-  else
-    log "Wrong mode name, choose from:\n\n#{modesList()}"
-
-createCanvas = (width, height) ->
-  log "#canvas\n<canvas id='canvas' width=#{width} height=#{height}></canvas>"
-
-toggleAutoCompilation = ->
-  autoCompile = not autoCompile
-  log "Autocompilation switched #{if autoCompile then 'on' else 'off'}"
-
-getCompilerOptions = ->
-  # TODO: use prelude
-  $.extend {}, compilerOptions
-
-# compileCode = ->
-#   startColor = "#151515"
-#   endColor = "#ccc"
-#   normalColor = "#050505"
-#   indicator = $ "#compilationIndicator"
-#   indicateBy = (color) ->
-#     indicator.animate
-#       color: color
-#     ,
-#       complete: ->
-#         indicator.css color: color
-
-#   compileSource ->
-#     indicateBy startColor
-#   , ->
-#     indicateBy endColor
-#     indicateBy normalColor
-
-# compileSource = (start, finish) ->
-#   start()
-#   source = sourceArea.getValue()
-#   compiledJS = ""
-#   saveCurrent()
-#   try
-#     compiledJS = compiler.compile source, getCompilerOptions()
-#     hideError "compiler", "runtime"
-#   catch error
-#     showErrorMessage "compiler", "Compiler: #{error.message ? error}"
-#   sourceCompiled = true
-#   finish()
-#   $("#repl_permalink").attr "href", "##{sourceFragment}#{encodeURIComponent(source)}"
-
-execute = (code) ->
-  compiler.preExecute?()
-  eval code
-
-history = new History
-sourceChange = (e) ->
-  sourceCompiled = false
-  sourceChanged = true
-  history.add e
-  return
-
-# TODO: this is not used, it is connected to History
-printHistory = ->
-  insert = undefined
-  point = undefined
-  text = undefined
-  _i = undefined
-  _len = undefined
-  _results = undefined
-  text = [""]
-  insert = (from, to, what) ->
-    appended = undefined
-    curr = undefined
-    newLines = undefined
-    oldLines = undefined
-    singleLine = undefined
-    singleLine = from.line is to.line
-    if singleLine
-      curr = text[from.line]
-      text[from.line] = curr.slice(0, from.ch) + what[0] + curr.slice(to.ch)
-    else
-      text[from.line] = text[from.line].slice(0, from.ch) + what[0]
-      text[to.line] = what[what.length - 1] + text[to.line].slice(to.ch)
-    newLines = what.length
-    oldLines = 1 + to.line - from.line
-    if newLines > 2 or oldLines > 2
-      appended = (if singleLine then what.slice(1) else what.slice(1, -1))
-      text.splice.apply text, [
-        from.line + 1
-        Math.max(0, oldLines - newLines)
-      ].concat(__slice_.call(appended))
-
-  _results = []
-  _i = 0
-  _len = history.length
-
-  while _i < _len
-    point = history[_i]
-    insert point.from, point.to, point.text
-    _results.push log(text)
-    _i++
-  _results
-
-BROWSE_COOKIE = "table"
-autosave = ->
-  setTimeout ->
-    if sourceChanged
-      saveCurrent()
-      sourceChanged = false
-    autosave()
-  , AUTOSAVE_DELAY
-
-fileCookie = (name, value) ->
-  $.totalStorage cookieFilePrefix + name, value
-
-# TODO: for each file, save its non-command executed commands
-saveCurrent = ->
-  source = sourceArea.getValue()
-  value = serializeSource()
-
-  valueLines = (source.split "\n").length
-  exists = false
-
-  ammendClientTable saveName, "#{saveName},#{valueLines}"
-  fileCookie saveName, value
-  $.totalStorage LAST_CODE, saveName
-
-serializeSource = ->
-  source: sourceArea.getValue()
-  mode: currentMode
-  selection: sourceArea.getSelectionRange()
-  cursor: sourceArea.getCursorPosition()
-  scroll:
-    top: sourceArea.session.getScrollTop()
-    left: sourceArea.session.getScrollLeft()
-
-deseriazeSource = (serialized, callback) ->
-  {source, mode, selection, cursor, scroll} = serialized
-  sourceArea.setValue source
-  sourceArea.session.selection.setSelectionRange selection
-  sourceArea.moveCursorToPosition cursor
-  sourceArea.session.setScrollTop scroll.top
-  sourceArea.session.setScrollLeft scroll.left
-  setNewMode mode, callback
-
-saveTimeline = ->
-  $.totalStorage TIMELINE_COOKIE, timeline.newest(200)
-
-loadTimeline = ->
-  timeline.from ($.totalStorage TIMELINE_COOKIE) ? []
-
-removeFromClient = (name) ->
-  return unless name?
-  fileCookie saveName, null
-  ammendClientTable name
-  showFileMessage "#{name} deleted"
-
-ammendClientTable = (exclude, addition) ->
-  addition = null unless addition?
-  table = []
-  oldTable = $.totalStorage BROWSE_COOKIE
-  if oldTable?
-    for pair in oldTable.split ";"
-      [name, lines] = pair.split ","
-      table.push pair if name isnt exclude
-
-  table.push addition if addition
-  table = table.join ";"
-  table = null if table.length is 0
-  $.totalStorage BROWSE_COOKIE, table
-
-loadFromClient = (name) ->
-  name = $.totalStorage(LAST_CODE) unless name?
-  unless name?
-    setMode "CoffeeScript" unless compiler?
-    return
-  stored = fileCookie(name)
-  if stored?
-    saveName = name
-
-    deseriazeSource stored, ->
-      showFileMessage "" + saveName + " loaded"  if saveName isnt UNNAMED_CODE
-
-  else
-    showFileMessage "There is no " + name  if name isnt UNNAMED_CODE
-
-exitCurrentCode = ->
-  saveCurrent()
-  saveName = UNNAMED_CODE
-  sourceArea.setValue ""
-  saveCurrent()
-
-switchCurrentCode = (name) ->
-  saveCurrent()
-  saveName = name
-  saveCurrent()
-  showFileMessage "Working on " + saveName
-
-displayClient = ->
-  table = $.totalStorage(BROWSE_COOKIE)
-  output = ""
-  if table?.length > 0
-    for snippet in table.split ";"
-      [name, lines] = snippet.split ","
-      output += "#{name}, lines: #{lines}\n" if name isnt UNNAMED_CODE
-  if output is ""
-    log "No files saved"
-  else
-    log output
-
-outputScrollTop = ->
-  $("#rightColumn").animate
-    scrollTop: 0
-  , $("#rightColumn").scrollTop() / 10
-
-defaultEditor = ->
-  winSize =
-    w: $(window).width()
-    h: $(window).height()
-
-  column = floor winSize.w / 2
-  $("#leftColumn").width column - 30
-  resizeEditor()
-
-resizeEditor = (e) ->
-  winSize =
-    w: $(window).width()
-    h: $(window).height()
-
-  $("#centerBar").height winSize.h - 20
-  # $("#sourceWrap .CodeMirror-scroll").css "max-height", (winSize.h - 175) + "px"
-  $("#commandArea").css "height", 17 + "px"
-  $("#sourceArea").css "height", (winSize.h - 135) + "px"
-  $("#rightColumn").width winSize.w - $("#leftColumn").width() - 60
-  $("#rightColumn").css "max-height", (winSize.h - 25) + "px"
-  setMaxPreWidth $("#output pre")
-  sourceArea.resize()
-
-selectLastOutput = ->
-  (getMessage(0)).selectText()
-
-setMaxPreWidth = ($pre) ->
-  $pre.css "max-width", ($("#rightColumn").width() - 45) + "px"
-
-loadWith = (coffee) ->
-  sourceArea.setValue sourceArea.getValue() + coffee
-
-saveToAdress = ->
-  source = sourceArea.getValue()
-  window.location = "#" + sourceFragment + (encodeURIComponent(source))
-
-# TODO: an easy way to distinguish code from other text in logs
-helpDescription = """
-  Issue commands by typing \"< \" or \":\"
-  followed by space separated commands:
-
-  erase / e      - Clear all results
-  erase <not...> - Don't clear results containing givens
-  dump / d       - Dump generated javascript
-  run / r        - Run just the source code
-  copy / c       - Select last output (right-click to copy)
-  toggle / t     - Toggle autocompilation
-  link / l       - Create a link with current source code
-  mode <name>    - Switch to a different compiler
-  modes / m      - Show all available modes
-  canvas <w> <h> - Create a canvas given width and height
-  save <name>    - Save current code locally under name
-  load <name>    - Load code from local storage under name
-  delete <name>  - Remove code from local storage
-  browse / b     - Show content of local storage
-  help / h       - Show this help
-
-  Name with arbitrary characters (spaces) must be closed by \\
-  save Long file name.txt\\
-"""
-
-sourceArea = ace.edit 'sourceArea'
-sourceArea.setTheme "ace/theme/cobalt"
-sourceArea.session.on 'changeMode', ->
-  compiler = sourceArea.session.getMode()
-  sourceArea.session.$worker.on 'ok', ({data: {result}}) ->
-    saveCurrent()
-    compiledJS = result
-    hideError "compiler", "runtime"
-    sourceCompiled = true
-    # $("#repl_permalink").attr "href", "##{sourceFragment}#{encodeURIComponent(source)}"
-
-  sourceArea.session.$worker.on 'error', ({data: {text}}) ->
-    showErrorMessage "compiler", "Compiler: #{text}"
-
-sourceArea.setHighlightActiveLine true
-sourceArea.session.setTabSize 2
-sourceArea.setShowPrintMargin false
-
-sourceArea.session.on 'change', sourceChange
-
-sourceArea.commands.addCommand
-  name: 'leave'
-  bindKey: win: 'Esc', mac: 'Esc'
-  exec: ->
-    commandArea.focus()
-
-commandArea = ace.edit 'commandArea'
-commandArea.setTheme "ace/theme/cobalt"
-commandArea.setHighlightActiveLine false
-commandArea.setShowPrintMargin false
-commandArea.renderer.setShowGutter false
-
-commandArea.session.on 'changeMode', ->
-  commandWorker = commandArea.session.getMode().worker
-
-  # CommandWorker only compiles on user enter, hence this is an order to execute
-  # the source and the command
-  commandWorker.on 'ok', ({data: {result, type}}) ->
-    # TODO use prelude trim
-    source = $.trim commandArea.getValue()
-    return if source.length is 0
-
-    timeline.push source
-    hideError "command", "runtime"
-    if type is 'command'
-      for command in commands
-        match = command.match result
-        break if match?
-      saveTimeline()
-      outputScrollTop()
-    else
-      try
-        log execute compiledJS + result
-        saveTimeline()
-        outputScrollTop()
-      catch error
-        showErrorMessage "runtime", "Runtime: #{error}"
-
-    commandArea.setValue ""
-
-  commandWorker.on 'error', ({data: {text}}) ->
-    showErrorMessage "command", "Command Line: #{text}"
-
-# Execute on enter
-commandArea.commands.addCommand
-  name: 'execute'
-  bindKey: win: 'Enter', mac: 'Enter'
-  exec: ->
-    commandArea.session.getMode().updateWorker()
-
-commandArea.commands.addCommand
-  name: 'previous'
-  bindKey: win: 'Up', mac: 'Up'
-  exec: ->
-    timeline.temp commandArea.getValue() unless timeline.isInPast()
-    commandArea.setValue timeline.goBack()
-    commandArea.clearSelection()
-
-commandArea.commands.addCommand
-  name: 'following'
-  bindKey: win: 'Down', mac: 'Down'
-  exec: ->
-    commandArea.setValue timeline.goForward() if timeline.isInPast()
-    commandArea.clearSelection()
-
-commandArea.commands.addCommand
-  name: 'leave'
-  bindKey: win: 'Esc', mac: 'Esc'
-  exec: ->
-    sourceArea.focus()
-
-$("#commandWrap").mouseenter -> commandArea.focus()
-$("#sourceArea").mouseenter -> sourceArea.focus()
-
-# set correct background for border
-
-commandArea.renderer.on 'themeLoaded', ->
-  color = $("#sourceArea").css 'background-color'
-  $("#sourceArea").parent().css 'background-color', color
-  $("#commandArea").parent().css 'background-color', color
-
-$("#centerBar").draggable
-  axis: "x"
-  drag: (e, ui) ->
-    newRightColumnWidth = $(window).width() - ui.offset.left - 60
-    if newRightColumnWidth > 0
-      $("#leftColumn").width ui.offset.left - $("#leftColumn").position().left
-      $("#rightColumn").width newRightColumnWidth
-    ui.position = ui.originalPosition
-
-defaultEditor()
-$(window).resize resizeEditor
-$(window).unload ->
-  saveCurrent()
-
-hash = decodeURIComponent window.location.hash.replace /^#/, ""
-if hash.indexOf(sourceFragment) is 0
-  src = hash.substr(sourceFragment.length)
-  loadWith src
-  window.location.hash = ""
-  log "File loaded from URI, use the link command to generate new link."
-else
-  loadFromClient()
-loadTimeline()
-if timeline.size() < 10
-  log helpDescription


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com


tests: Fix broken componentlib test

tests: Fix broken componentlib test

The expects were effectively not checking anything...

--- test/componentlib.coffee
+++ test/componentlib.coffee
@@ -11,38 +11,48 @@
 else
   componentlib = require 'microflo/lib/componentlib'
 componentLib = new componentlib.ComponentLibrary
+library = __dirname + '/../microflo/core/components/arduino-standard.json'

 describe 'ComponentLibrary', ->
+  normal = []
+  all = []
+  skipped = []
+
+  before (done) ->
+    componentLib.loadSetFile library, (err) ->
+      chai.expect(err).to.be.a 'null'
+      normal = componentLib.listComponents(false, true)
+      all = componentLib.listComponents(true, true)
+      skipped = all.filter (n) -> normal.indexOf(n) == -1
+      done()
+  after (done) ->
+    done()
+
   describe 'listing all components', ->

-    normal = componentLib.listComponents(false, true)
-    all = componentLib.listComponents(true, true)
-    skipped = all.filter (n) -> normal.indexOf(n) == -1
-
-    it 'should give above 20 normal', ->
-      chai.expect normal.length > 20, 'normal.length ' + normal.length
+    it 'should give above 20 components', ->
+      chai.expect(normal.length).to.be.above 20
     it 'Max,Invalid should be skipped', ->
-      chai.expect normal.indexOf('_Max') == -1
-      chai.expect normal.indexOf('Invalid') == -1
-      chai.expect skipped.indexOf('_Max') != -1
-      chai.expect skipped.indexOf('Invalid') != -1
+      chai.expect(normal).to.not.contain '_Max'
+      chai.expect(normal).to.not.contain 'Invalid'
     it 'Split,Forward should be available', ->
-      chai.expect skipped.indexOf('Split') == -1
-      chai.expect skipped.indexOf('Forward') == -1
-      chai.expect normal.indexOf('Split') != -1
-      chai.expect normal.indexOf('Forward') != -1
+      chai.expect(normal).to.contain 'Split'
+      chai.expect(normal).to.contain 'Forward'
+      chai.expect(skipped).to.not.contain 'Split'
+      chai.expect(skipped).to.not.contain 'Forward'
     it 'no components have same id', ->
       defs = componentLib.getComponents true
       i = 0
       while i < all.length
-                j = 0
+        j = 0
         while j < all.length
           I = all[i]
           J = all[j]
           if I == J
-                        j++
+            j++
             continue
-          chai.expect defs[I].id != defs[J].id, I + ' has same ID as ' + J + ' : ' + defs[I].id
+          msg = I + ' has same ID as ' + J + ' : ' + defs[I].id
+          chai.expect(defs[I].id).to.not.equal defs[J].id, msg
           j++
         i++


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/controllable.coffee
+++ test/controllable.coffee
@@ -24,7 +24,7 @@
 test "should move player right while key is pressed", ->

-
+test "s"

 module()


teams: admin: stacks: bootsrapping results code highlighting

--- client/admin/lib/views/stacks/stackscustomviews.coffee
+++ client/admin/lib/views/stacks/stackscustomviews.coffee
@@ -1,5 +1,6 @@
 _                               = require 'lodash'
 kd                              = require 'kd'
+hljs                            = require 'highlight.js'
 globals                         = require 'globals'
 dateFormat                      = require 'dateformat'
 CustomViews                     = require 'app/commonviews/customviews'
@@ -122,13 +123,15 @@

       options.cssClass = kd.utils.curry options.cssClass, 'output-view'
       options.tagName  = 'pre'
-
-      container = @views.view options
+      container        = @views.view options
+      code             = @views.view tagName : 'code'
+
+      container.addSubView code

       container.addContent = (content...) =>
         content = content.join ' '
-        content = "[#{dateFormat Date.now(), 'HH:MM:ss'}] #{content}"
-        @addTo container, text: content
+        content = "[#{dateFormat Date.now(), 'HH:MM:ss'}] #{content}\n"
+        code.setPartial hljs.highlight('profile', content).value

       return container

@@ -222,6 +225,8 @@

       container = @views.container 'step-creds'

+      container.setClass 'has-markdown'
+
       views     = @addTo container,
         stepsHeaderView : 3
         container       :


reset opinion form properly

reset opinion form properly

--- client/app/CommonViews/opinions/opinionformview.coffee
+++ client/app/CommonViews/opinions/opinionformview.coffee
@@ -70,6 +70,10 @@
     @setTemplate @pistachio()
     @template.update()

+  reset:=>
+    @opinionBody.setValue ""
+    super
+
   submit:=>
     @once "FormValidationPassed", => @reset()
     super


Adapt formatOutput for search with grep

Adapt formatOutput for search with grep

--- client/ide/views/contentsearch/idecontentsearch.coffee
+++ client/ide/views/contentsearch/idecontentsearch.coffee
@@ -94,43 +94,39 @@
   formatOutput: (output, callback = noop) ->
     lines      = output.split '\n'
     formatted  = {}
-    stats      = {}
-
-    if lines[0] is '0 matches'
-      return @showWarning 'No results found, refine your search.'
+    stats      = {
+      numberOfMatches: 0,
+      numberOfSearchedFiles: 0
+    }

     for line in lines
-      parts    = line.split ':'
-      fileName = parts[1]  if parts[0] is '' and parts[1] and not parts[2] # filename line, like :Web/index.html
+      parts = line.split ":"
+      if parts.length < 3
+       continue
+
+      # Parse path
+      fileName = parts.shift()
+      fileName = fileName.trim()
+
+      # Parse line number
+      lineNumber = parseInt parts.shift()
+
+      # Parse line
+      line = parts.join ''

       unless formatted[fileName] # new filename found
         formatted[fileName] = [] # create an empty object for filename and continue to loop
-        continue

-      if parts.first.indexOf(';') > -1 # occurence found at this line
-        [lineNumber] = parts[0].split ';'
+      formatted[fileName].push { lineNumber, line, occurence: yes}
+      stats.numberOfMatches += 1

-        parts.splice 0, 1    # remove line information
-        line = parts.join '' # join the parts to have actual line again
-        formatted[fileName].push { lineNumber, line, occurence: yes }
-      else
-        if parts[0] is '--' # handle separators
-          formatted[fileName].push type: 'separator'
+    stats.numberOfSearchedFiles = Object.keys(formatted).length

-        if (parts[0] is '') and not parts[1] # avoid empty lines
-          continue
+    # No results
+    if stats.numberOfMatches == 0
+      return @showWarning 'No results found, refine your search.'

-        if parts[0] and not parts[1] and parts[1] isnt '' # stats line
-          if parts[0].indexOf('matches') > -1
-            stats.numberOfMatches = parts[0]
-          else if parts[0].indexOf('files searched') > -1
-            stats.numberOfSearchedFiles = parts[0]
-        else
-          [lineNumber] = parts
-          parts.splice 0, 1 # remove line information
-          line = parts.join() # join the parts to have actual line again
-          formatted[fileName].push { lineNumber, line }
-
+    # Send results
     callback formatted, stats

   createResultsView: (result, stats) ->


putstylesheets bug fixed

putstylesheets bug fixed

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -256,6 +256,8 @@
     if @isAppUpdateAvailable(name, version) and not devMode and forceUpdate
       @showUpdateRequiredModal manifest
       return callback()
+
+    putStyleSheets manifest

     @getAppScript manifest, (err, appScript)=>
       return warn err  if err


wrong prop

wrong prop

--- resources/assets/lib/report-user.coffee
+++ resources/assets/lib/report-user.coffee
@@ -25,7 +25,7 @@

 export class ReportUser extends PureComponent
   @defaultProps =
-    onClick: -> # do nothing
+    onFormClose: -> # do nothing

   constructor: (props) ->
     super props


Fix kiteController.run option toDo to method

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -295,7 +295,7 @@
       manifest        = @constructor.manifests[appName]
       userAppPath     = getAppPath manifest
       options         =
-        toDo          : "publishApp"
+        method        : "publishApp"
         withArgs      :
           version     : manifest.version
           appName     : manifest.name
@@ -335,7 +335,7 @@
       return no

     options         =
-      toDo          : "approveApp"
+      method        : "approveApp"
       withArgs      :
         version     : app.manifest.version
         appName     : app.manifest.name
@@ -448,7 +448,7 @@
                 callback? err
               else
                 options =
-                  toDo          : "installApp"
+                  method        : "installApp"
                   withArgs      :
                     owner       : acc.profile.nickname
                     appPath     : getAppPath app.manifest
@@ -536,7 +536,7 @@

         stack.push (cb)=>
           @kiteController.run
-            toDo        : "uploadFile"
+            method      : "uploadFile"
             withArgs    :
               path      : escapeFilePath "#{fsFolder.path}/.manifest"
               contents  : manifestStr
@@ -544,7 +544,7 @@

         stack.push (cb)=>
           @kiteController.run
-            toDo        : "uploadFile"
+            method      : "uploadFile"
             withArgs    :
               path      : escapeFilePath "#{fsFolder.path}/index.coffee"
               contents  : "do ->"
@@ -552,7 +552,7 @@

         stack.push (cb)=>
           @kiteController.run
-            toDo        : "uploadFile"
+            method      : "uploadFile"
             withArgs    :
               path      : escapeFilePath "#{fsFolder.path}/ChangeLog"
               contents  : """
@@ -595,7 +595,7 @@
         return

       @kiteController.run
-        toDo        : "downloadApp"
+        method      : "downloadApp"
         withArgs    :
           owner     : manifest.authorNick
           appName   : manifest.name


Resized main tab handle holder when new tab added.

--- client/landing/app/MainApp/maintabs/maintabview.coffee
+++ client/landing/app/MainApp/maintabs/maintabview.coffee
@@ -23,6 +23,9 @@
       if e.target is @getSingleton("contentPanel").domElement[0]
         @tabHandleContainer.setWidth @getWidth()
         @resizeTabHandles()
+
+    @on "PaneAdded", =>
+      @tabHandleContainer.setWidth @getWidth()

   # temp fix sinan 27 Nov 12
   # not calling @removePane but @_removePane


client: landing: teamCreation email passing from hubspot

--- client/landing/site.landing/coffee/teams/routes.coffee
+++ client/landing/site.landing/coffee/teams/routes.coffee
@@ -34,7 +34,8 @@
       if teamData.signup
         utils.storeNewTeamData 'signup', teamData.signup

-    utils.storeNewTeamData 'invitation', { email }
+    if email
+      utils.storeNewTeamData 'invitation', { email }

     handleRoute { params, query }


dashboard: make sure Stripe client is loaded

--- client/home/lib/billing/index.coffee
+++ client/home/lib/billing/index.coffee
@@ -32,17 +32,21 @@
     { mainController, reactor } = kd.singletons

     mainController.ready =>
-      PaymentFlux(reactor).actions.loadGroupCreditCard()

-      @wrapper.addSubView header 'Koding Subscription'
-      @wrapper.addSubView section 'Koding Subscription'
+      { actions } = PaymentFlux(reactor)

-      formView = new kd.FormView
-        cssClass: kd.utils.curry 'HomeAppView--billing-form', options.cssClass
+      actions.loadStripeClient().then =>
+        actions.loadGroupCreditCard()

-      formView.addSubView header 'Payment Information'
-      formView.addSubView section 'Credit Card'
-      formView.addSubView section 'Payment Information'
+        @wrapper.addSubView header 'Koding Subscription'
+        @wrapper.addSubView section 'Koding Subscription'

-      @wrapper.addSubView formView
+        formView = new kd.FormView
+          cssClass: kd.utils.curry 'HomeAppView--billing-form', options.cssClass

+        formView.addSubView header 'Payment Information'
+        formView.addSubView section 'Credit Card'
+        formView.addSubView section 'Payment Information'
+
+        @wrapper.addSubView formView
+


Home: back to new one

Home: back to new one

--- client/landing/Intro/includes.coffee
+++ client/landing/Intro/includes.coffee
@@ -1,4 +1,4 @@
 module.exports = [
-  "main.coffee",
-  "main.styl"
+  "home.coffee",
+  "styl/home.styl"
 ]


Add rebind notifications

Add rebind notifications

--- client/lanes/screens/Commands.coffee
+++ client/lanes/screens/Commands.coffee
@@ -15,7 +15,9 @@
         @screen[@options.modelName]

     setModel: (model) ->
+        @options.modelWillRebind?(model)
         @screen.data.rebind("#{@options.modelName}": model)
+        @options.modelDidRebind?(model)

     saveModel: ->
         @getModel().save()


Patch up variable importance handling. Refer to .variables in variable_importances when available instead of the model's column names. Don't rely on max_var: variable list is not truncated, so truncate after sorting. PP-103

--- client/src/scripts/model-view.coffee
+++ client/src/scripts/model-view.coffee
@@ -147,14 +147,19 @@
   return

 createVariableImportanceModel = (inputColumnNames, variableImportances) ->
-  data = times (Math.min variableImportances.max_var, variableImportances.varimp.length), (index) ->
-    columnName: inputColumnNames[index]
+  #TODO always refer to .variables when variables are available in variable_importances.
+  variables = variableImportances.variables or inputColumnNames
+
+  data = times variableImportances.varimp.length, (index) ->
+    columnName: variables[index] or '' #TODO remove or... when variables are available in variable_importances
     value: variableImportances.varimp[index]
     cumulativeScaledValue: 0
     hasCumulativeScaledValues: no
+
+  sortedData = sortBy data, (datum) -> -datum.value

   method: variableImportances.method
-  data: sortBy data, (datum) -> -datum.value
+  data: if sortedData.length < variableImportances.max_var then sortedData else sortedData.slice 0, variableImportances.max_var

 Steam.ModelView = (_, _model) ->
   stringify = (value) ->


Remove console.info

Remove console.info

--- core/app/backbone/initializers/site_initializer.coffee
+++ core/app/backbone/initializers/site_initializer.coffee
@@ -10,7 +10,6 @@

 enhanceSearchFormNavigation = ->
   $('.js-navbar-search-form').on 'submit', ->
-    console.info 'yo'
     url = '/search?s=' + encodeURIComponent $('.js-navbar-search-box').val()
     Backbone.history.navigate url, true
     false


added EJS as Grammar since JavaScript Template is not longer used by the EJS Atom Plugin

--- src/languages/ejs.coffee
+++ src/languages/ejs.coffee
@@ -9,6 +9,7 @@
   Supported Grammars
   ###
   grammars: [
+    "EJS"
     "JavaScript Template"
     "HTML (Angular)"
   ]


Ensure opening brackets get send in correct order based on inports

--- src/lib/Component.coffee
+++ src/lib/Component.coffee
@@ -207,9 +207,11 @@
           result[port].unshift context.closeIp.clone()

     if result.__bracketContext
-      # First see if there are any brackets to forward
-      for inport, context of result.__bracketContext
-        continue unless context.length
+      # First see if there are any brackets to forward. We need to reverse
+      # the keys so that they get added in correct order
+      Object.keys(result.__bracketContext).reverse().forEach (inport) =>
+        context = result.__bracketContext[inport]
+        return unless context.length
         for outport, ips of result
           continue if outport.indexOf('__') is 0
           unforwarded = context.filter (ctx) =>


api fix

api fix

--- src/loader/loader.coffee
+++ src/loader/loader.coffee
@@ -362,7 +362,7 @@
         return localforage.removeItem(key, cb)

     onNoManifest: (error) ->
-    onUpToDate: (event) ->
+    onUpToDate: (event, manifest) ->
     onUpdateFound: (event, manifest) -> @startUpdate()
     onUpdateFailed: (event, error)->
     onUpdateCompleted: (manifest) -> return true
@@ -471,7 +471,7 @@
             @logger.info("New manifest", @_new_manifest)
             if @_current_manifest?
                 if @_current_manifest.hash == @_new_manifest.hash
-                    @emit("UpToDate", @_current_manifest)
+                    @emit("UpToDate", event, @_current_manifest)
                     return

             @emit("UpdateFound", event, @_new_manifest)
@@ -572,7 +572,7 @@
                 return @_downloadModule(module, onDownload) unless module_source?

                 if @hash_func(module_source) != module.hash
-                    @emit("ModuleDownloadFailed", null, module)
+                    @emit("ModuleDownloadFailed", null, module, new HashMismatchedError(module.url, module.hash, hash))
                     return
                 module.source = module_source
                 module.loaded = module.size
@@ -631,9 +631,9 @@
             @emit("ModuleDownloadProgress", event, module)
             @_reportTotalProgress()
         module_request.onerror = (event) =>
-            @emit("ModuleDownloadFailed", event, module)
+            @emit("ModuleDownloadFailed", event, module, null)
         module_request.onabort = (event) =>
-            @emit("ModuleDownloadFailed", event, module)
+            @emit("ModuleDownloadFailed", event, module, null)
         module_request.send()
         return


default to https

default to https

--- lib/atom-butterfly.coffee
+++ lib/atom-butterfly.coffee
@@ -12,7 +12,7 @@
     chameleonServerAddress: 'http://localhost'
     tanant: ""
     username: ""
-    puzzleServerAddress: 'http://localhost:3000'
+    puzzleServerAddress: 'https://localhost:3000'

   activate: (state) ->
     @packageManager = new (require './package/package-manager')()


:lipstick:

:lipstick:

--- src/context-menu-manager.coffee
+++ src/context-menu-manager.coffee
@@ -29,7 +29,7 @@
 #   ]
 # }]
 # ```
-
+#
 # In your package's menu `.cson` file you need to specify it under a
 # `context-menu` key:
 #


Actually show button title

Actually show button title

--- resources/assets/coffee/react/beatmapset-page/hype.coffee
+++ resources/assets/coffee/react/beatmapset-page/hype.coffee
@@ -75,25 +75,32 @@
                 else
                   false

-        if @props.beatmapset.status == 'qualified'
-          div
-            className: "#{bn}__button"
-            if @userCanDisqualify()
-              title: osu.trans('beatmapsets.show.hype.disqualify.button_title')
-              el BigButton,
-                modifiers: ['full']
-                text: osu.trans 'beatmaps.nominations.disqualify'
-                icon: 'fas fa-thumbs-down'
-                props:
-                  href: @reportUrl()
-            else
-              title: osu.trans('beatmapsets.show.hype.report.button_title')
-              el BigButton,
-                modifiers: ['full']
-                text: osu.trans('beatmapsets.show.hype.report.button')
-                icon: 'fas fa-exclamation-triangle'
-                props:
-                  href: @reportUrl()
+        @renderReportButton()
+
+
+  renderReportButton: =>
+    return unless @props.beatmapset.status == 'qualified'
+
+    if @userCanDisqualify()
+      title = osu.trans('beatmapsets.show.hype.disqualify.button_title')
+      buttonParams =
+        text: osu.trans 'beatmaps.nominations.disqualify'
+        icon: 'fas fa-thumbs-down'
+    else
+      title = osu.trans('beatmapsets.show.hype.report.button_title')
+      buttonParams =
+        text: osu.trans('beatmapsets.show.hype.report.button')
+        icon: 'fas fa-exclamation-triangle'
+
+    div
+      className: "#{bn}__button"
+      title: title
+      el BigButton,
+        text: buttonParams.text
+        icon: buttonParams.icon
+        modifiers: ['full']
+        props:
+          href: @reportUrl()

   reportUrl: =>
     "#{route('beatmapsets.discussion', beatmapset: @props.beatmapset.id, beatmap: '-', mode: 'generalAll')}#new"


defactor dialogs

defactor dialogs

--- src/layout/header.coffee
+++ src/layout/header.coffee
@@ -1,6 +1,5 @@
 {my} = require '../my'
 {make} = require '../render/make'
-{dialogs} = require './dialogs'
 {done_dialog} = require './done_dialog'

 exports.header = (level) ->
@@ -24,7 +23,7 @@
   make.rows 'header', [
     make.columns 'progress', [
       "Level #{level.get('level_index')} of #{level.get('level_count')}"
-      dialogs(level)
+      make.anchor "skip", level.get 'next_params'
     ]
     { name: 'Level Progress', _LABEL: 'level_progress' }
     make.columns 'stats', [


Revert "Revert "linode deploys get nko dns""

This reverts commit 2bf51a58e289a839a1098eb42aa497d968d9c6ff.

Hours of sleep: 6
Cups of coffee: 1
Cans of soda: 1
Cans of redbull: 0

--- models/deploy.coffee
+++ models/deploy.coffee
@@ -48,7 +48,7 @@
   'http://' + switch @platform
     when 'joyent', 'nodejitsu', 'localdomain' then @hostname
     when 'heroku' then "nko2-#{team.slug}.herokuapp.com"
-    when 'linode' then @remoteAddress
+    when 'linode' then "#{team.slug}.nko2.nodeknockout.com"

 # callbacks
 DeploySchema.post 'save', ->


Allow PanelElements to be instantiated with markup

--- src/panel-element.coffee
+++ src/panel-element.coffee
@@ -1,5 +1,6 @@
 {CompositeDisposable} = require 'event-kit'
 {callAttachHooks} = require './space-pen-extensions'
+Panel = require './panel'

 class PanelElement extends HTMLElement
   createdCallback: ->
@@ -13,14 +14,15 @@
     @subscriptions.add @model.onDidDestroy(@destroyed.bind(this))
     this

-  getModel: -> @model
+  getModel: ->
+    @model or= new Panel({})

   getItemView: ->
-    atom.views.getView(@model.getItem())
+    atom.views.getView(@getModel().getItem())

   attachedCallback: ->
     callAttachHooks(@getItemView()) # for backward compatibility with SpacePen views
-    @visibleChanged(@model.isVisible())
+    @visibleChanged(@getModel().isVisible())

   visibleChanged: (visible) ->
     if visible


Display quickstart video / example link in the help sidebar.

--- src/core/components/help.coffee
+++ src/core/components/help.coffee
@@ -3,14 +3,16 @@
 _homeContent = null

 _homeMarkdown = """
-

+

 Using Flow for the first time?

-  <button type='button' data-action='assist' class='flow-button'>Assist Me
+  <button type='button' data-action='get-flow' data-pack-name='examples' data-flow-name='QuickStartVideos.flow' class='flow-button'>Quickstart Videos
   </button>

-

+

+
+Or, view example Flows to explore and learn H2O.

 ###### Star H2O on Github!

@@ -20,7 +22,7 @@

 %HELP_TOPICS%

-###### Packs
+###### Examples

 Flow packs are a great way to explore and learn H2O. Try out these Flows and run them in your browser.
Browse installed packs...


Use symbols for core types

Use symbols for core types

--- src/core/modules/prelude.coffee
+++ src/core/modules/prelude.coffee
@@ -21,31 +21,31 @@
   _typeOf = (a) ->
     type = Object::toString.call a
     if a is null
-      return 'null'
+      return TNull
     else if a is undefined
-      return 'undefined'
+      return TUndefined
     else if a is true or a is false or type is '[object Boolean]'
-      return 'Boolean'
+      return TBoolean
     else
       switch type
         when '[object String]'
-          return 'String'
+          return TString
         when '[object Number]'
-          return 'Number'
+          return TNumber
         when '[object Function]'
-          return 'Function'
+          return TFunction
         when '[object Object]'
-          return 'Object'
+          return TObject
         when '[object Array]'
-          return 'Array'
+          return TArray
         when '[object Arguments]'
-          return 'Arguments'
+          return TArguments
         when '[object Date]'
-          return 'Date'
+          return TDate
         when '[object RegExp]'
-          return 'RegExp'
+          return TRegExp
         when '[object Error]'
-          return 'Error'
+          return TError
         else
           return type


improvement: pulsing loading screen is removed on viewappended event

--- client/landing/app/MainApp/maincontroller/mainviews/mainview.coffee
+++ client/landing/app/MainApp/maincontroller/mainviews/mainview.coffee
@@ -1,14 +1,20 @@
 class MainView extends KDView

+  removePulsing = ->
+    if el = document.getElementById 'main-loading'
+      el.children[0].classList.add 'out'
+      KD.utils.wait 750, ->
+        el.classList.add 'out'
+        KD.utils.wait 750, ->
+          el.parentElement.removeChild el
+
+  attachListener = (instance, view)->
+    instance.getView().once 'viewAppended', removePulsing
+    KD.getSingleton('appManager').off 'AppManagerWantsToShowAnApp', attachListener
+
   viewAppended:->

-    if el = document.getElementById 'main-loading'
-      KD.utils.wait 750, ->
-        el.children[0].classList.add 'out'
-        KD.utils.wait 250, ->
-          el.classList.add 'out'
-          KD.utils.wait 750, ->
-            el.parentElement.removeChild el
+    KD.getSingleton('appManager').on 'AppManagerWantsToShowAnApp', attachListener

     @bindTransitionEnd()
     # @addServerStack()
@@ -83,12 +89,12 @@

     @contentPanel.on "ViewResized", (rest...)=> @emit "ContentPanelResized", rest...

-  addServerStack:->
-    @addSubView @serverStack = new KDView
-      domId : "server-rack"
-      click : ->
-        $('body').removeClass 'server-stack'
-        $('.kdoverlay').remove()
+  # addServerStack:->
+  #   @addSubView @serverStack = new KDView
+  #     domId : "server-rack"
+  #     click : ->
+  #       $('body').removeClass 'server-stack'
+  #       $('.kdoverlay').remove()

   addHeader:->


Fixed getPrototypeOf implementation

Fixed getPrototypeOf implementation

--- src/runtime/realm.coffee
+++ src/runtime/realm.coffee
@@ -100,6 +100,15 @@
               register(obj[k], restrict[k])
         return
       return nativeMetadata[obj.__mdid__] = new ObjectMetadata(obj)
+
+    getPrototypeOf = (obj) ->
+      if hasProp(obj, '__mdid__')
+        proto = nativeMetadata[obj.__mdid__].proto
+      else if hasProp(obj, '__md__')
+        proto = obj.__md__.proto
+      if proto
+        return proto
+      return prototypeOf(obj)

     getOwnPropertyDescriptor = (obj, key) =>

@@ -310,7 +319,7 @@

     nativeMetadata[Object.__mdid__].properties = {
       create: create
-      getPrototypeOf: prototypeOf
+      getPrototypeOf: getPrototypeOf
       defineProperty: defineProperty
     }

@@ -365,7 +374,7 @@
     }

     # retrieves the metadata from the closest object in the prototype chain
-    # that has a metadata
+    # that has a metadata object associated
     @mdproto = (obj) ->
       proto = prototypeOf(obj)
       if proto


New source of pizzas

New source of pizzas

animatedpizzagifs.com altered the site, and it is no longer hundreds of
pizza GIFs splashed across a single HTML document. As a result, we must
seek a new source of pizza GIFs.

--- src/scripts/pizza.coffee
+++ src/scripts/pizza.coffee
@@ -2,10 +2,11 @@
 #   Displays a random pizza gif from animatedpizzagifs.com
 #
 # Dependencies:
-#   "jsdom": "~0.2.13"
+#   "tumblrbot": "0.1.0"
 #
 # Configuration:
-#   HUBOT_MORE_PIZZA - Show pizza GIFs even when it's not directed at hubot
+#   HUBOT_TUMBLR_API_TOKEN
+#   HUBOT_MORE_PIZZA
 #
 # Commands:
 #   hubot pizza - Show a pizza gif
@@ -13,15 +14,12 @@
 # Author:
 #   iangreenleaf

-jsdom = require "jsdom"
-PIZZA = "http://animatedpizzagifs.com"
+tumblr = require 'tumblrbot'
+PIZZA = "pizzagifs.tumblr.com"

 module.exports = (robot) ->
-  func = if env.HUBOT_MORE_PIZZA then 'hear' else 'respond'
-  robot[func] /pizza/i, (msg) ->
-    msg.http(PIZZA)
-      .path("/")
-      .get() (err, res, body) ->
-        document = jsdom.jsdom body, null, features: { "QuerySelector": true, 'ProcessExternalResources': false }
-        img = msg.random document.querySelectorAll "li img"
-        msg.send "#{PIZZA}/#{img.src}"
+  func = if process.env.HUBOT_MORE_PIZZA then 'hear' else 'respond'
+  robot[func](/pizza/i, (msg) ->
+    tumblr.photos(PIZZA).random (post) ->
+      msg.send post.photos[0].original_size.url
+  )


open databrowser

open databrowser

--- src/steroids/Data.coffee
+++ src/steroids/Data.coffee
@@ -5,8 +5,9 @@
 Providers = require "./Providers"
 chalk = require "chalk"
 Help = require "./Help"
+dataHelpers = require "./dataHelpers"

-data_manager_url = "http://sandboxdb.testgyver.com/browser/projects"
+data_manager_url = "http://composer.testgyver.com/data/browser/projects"

 class Data


transformOrigin -> origin

transformOrigin -> origin

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -213,7 +213,7 @@
         if anchor is 'top'
           yOffset = -(i * @panelHeight)
         else
-          panel.style[css.transformOrigin] = 'bottom'
+          panel.style[css.origin] = 'bottom'
           yOffset = -((@hPanels * @panelHeight) - (@panelHeight * (i + 1)))

         content.style[css.transform] = @_transform [0, yOffset]


removed fixed dimensions

removed fixed dimensions

--- oridomi.coffee
+++ oridomi.coffee
@@ -354,8 +354,6 @@
     # Clone the `hPanel` prototype and adjust its styling for vertical use.
     vPanel = hPanel.cloneNode false
     vPanel.className = 'oridomi-panel-v'
-    vPanel.style.width = @panelWidth + bleed + 'px'
-    vPanel.style.height = '100%'
     vPanel.style[css.origin] = 'left'
     vPanel.appendChild vMask

@@ -367,8 +365,6 @@

     # Remove its padding and set a fixed width and height.
     @el.style.padding = '0'
-    @el.style.width = @width + 'px'
-    @el.style.height = @height + 'px'
     # Remove its background, border, and outline.
     @el.style.backgroundColor = 'transparent'
     @el.style.backgroundImage = 'none'


preserve external 3d transforms

preserve external 3d transforms

--- oridomi.coffee
+++ oridomi.coffee
@@ -264,10 +264,12 @@
   addStyle elClasses.clone, margin: '0'

   addStyle elClasses.holder,
-    width:     '100%'
-    height:    '100%'
-    position:  'absolute'
-    transform: 'translateY(-100%)'
+    width:          '100%'
+    height:         '100%'
+    position:       'absolute'
+    transform:      'translateY(-100%)'
+    transformStyle: p3d
+

   addStyle elClasses.stage,
     width:          '100%'


prefix this.cloneEl

prefix this.cloneEl

--- oridomi.coffee
+++ oridomi.coffee
@@ -500,11 +500,11 @@

     @el.classList.add elClasses.active
     showEl @_stages.left
-    @cloneEl = cloneEl @el, true, 'clone'
-    @cloneEl.classList.remove elClasses.active
-    hideEl @cloneEl
+    @_cloneEl = cloneEl @el, true, 'clone'
+    @_cloneEl.classList.remove elClasses.active
+    hideEl @_cloneEl
     @el.innerHTML   = ''
-    @el.appendChild @cloneEl
+    @el.appendChild @_cloneEl
     @el.appendChild @_stageHolder
     @$el = $ @el if $
     @accordion 0
@@ -897,7 +897,7 @@
         @isFrozen = true
         # Swap the visibility of the elements.
         hideEl @_stageHolder
-        showEl @cloneEl
+        showEl @_cloneEl
         @_setCursor false
         callback?()
     @
@@ -909,7 +909,7 @@
     if @isFrozen
       @isFrozen = false
       # Swap the visibility of the elements.
-      hideEl @cloneEl
+      hideEl @_cloneEl
       showEl @_stageHolder
       @_setCursor()
       # Set `lastAngle` to 0 so an immediately subsequent call to `freeze` triggers the callback.
@@ -926,7 +926,7 @@
       # Remove the data reference if using jQuery.
       $.data @el, baseName, null if $
       # Remove the oriDomi element from the DOM.
-      @el.innerHTML = @cloneEl.innerHTML
+      @el.innerHTML = @_cloneEl.innerHTML
       # Reset original styles.
       @el.classList.remove elClasses.active
       callback?()


html correction

html correction

--- html.coffee
+++ html.coffee
@@ -46,5 +46,5 @@
     render: (o) -> "<title>#{o.title}</title>"

   body: (o) ->
-    structure: o.structure
+    render: o.render
     options: o.options


cleanup

cleanup

--- src/ui/dispatcher.coffee
+++ src/ui/dispatcher.coffee
@@ -102,15 +102,12 @@

 handle 'searchentities', (query, max_results) ->
   ipc.send 'searchentities', query, max_results
-
 handle 'setsearchedentities', (r) ->
   convsettings.setSearchedEntities r
-
 handle 'selectentity', (e) -> convsettings.addSelectedEntity e
 handle 'deselectentity', (e) -> convsettings.removeSelectedEntity e
 handle 'createconversation', ->
     ids = (e.id.chat_id for e in convsettings.selectedEntities)
-    if ids.length == 0 then return alert 'No people selected' # TODO: handle this properly
     ipc.send 'createconversation', ids
 handle 'createconversationdone', (c) ->
     convsettings.setSearchedEntities []


Don't use grunt-newer when watching-building sass. :nut_and_bolt:

The `override` option also works, but just not using it is simpler.

--- build/src.coffee
+++ build/src.coffee
@@ -25,7 +25,7 @@
   watch:
     css:
       files: '{src,tests}/**/*.scss'
-      tasks: ['newer:copy:dist', 'newer:sass', 'newer:autoprefixer']
+      tasks: ['newer:copy:dist', 'sass', 'newer:autoprefixer']
     js:
       files: '{src,tests}/**/*.coffee'
       tasks: ['newer:coffee', 'newer:qunit']


`--fix-attributes` for init.coffee. Closes #446.

--- init.coffee
+++ init.coffee
@@ -105,6 +105,12 @@
 	]
 	type: 'bool'
 	help: 'Insert monsters.'
+,
+	names: [
+		'fix-attributes'
+	]
+	type: 'bool'
+	help: 'Set predefined attributes for all players.'
 ]

@@ -297,6 +303,39 @@
 	console.log('Done.')

+fixAttrs = ->
+	# ['uniusers', 'changeDefault', 'health',       1000],
+	# ['uniusers', 'changeDefault', 'health_max',   1000],
+	# ['uniusers', 'changeDefault', 'mana',         500],
+	# ['uniusers', 'changeDefault', 'mana_max',     500],
+	# ['uniusers', 'changeDefault', 'energy',       100],
+	# ['uniusers', 'changeDefault', 'power',        50],
+	# ['uniusers', 'changeDefault', 'defense',      50],
+	# ['uniusers', 'changeDefault', 'agility',      50],
+	# ['uniusers', 'changeDefault', 'accuracy',     50],
+	# ['uniusers', 'changeDefault', 'intelligence', 50],
+	# ['uniusers', 'changeDefault', 'initiative',   50],
+	process.stdout.write chalk.magenta 'Setting predefined attributes... '
+	dbConnection = createAnyDBConnection(config.DATABASE_URL)
+	dbConnection.query.sync(
+		dbConnection
+		'UPDATE uniusers SET '+
+			'health = 1000, '+
+			'health_max = 1000, '+
+			'mana = 500, '+
+			'mana_max = 500, '+
+			'energy = 100, '+
+			'power = 50, '+
+			'defense = 50, '+
+			'agility = 50, '+
+			'accuracy = 50, '+
+			'intelligence = 50, '+
+			'initiative = 50'
+	)
+	console.log chalk.green 'ok'
+
+
+
 sync(
 	->
 		if opts.help
@@ -314,6 +353,7 @@
 		unifyExport() if opts.unify_export
 		insertMonsters() if opts.monsters
 		optimize() if opts.optimize_tables
+		fixAttrs() if opts.fix_attributes
 		process.exit 0
 	(ex) ->
 		if ex? then throw ex


#109 - expose 'user-agent' header

#109 - expose 'user-agent' header

--- src/transport.coffee
+++ src/transport.coffee
@@ -130,7 +130,7 @@

         headers = {}
         for key in ['referer', 'x-client-ip', 'x-forwarded-for', \
-                    'x-cluster-client-ip', 'via', 'x-real-ip']
+                    'x-cluster-client-ip', 'via', 'x-real-ip', 'user-agent']
             headers[key] = req.headers[key] if req.headers[key]
         if headers
             @connection.headers = headers


Adding archive check for (.*) file suffixes

--- src/webserver.coffee
+++ src/webserver.coffee
@@ -250,7 +250,7 @@
                 fs.copy loc, new_loc, (err) =>
                   location_map['location'] = new_loc

-                  name_match = location_map['name'].match(/(\S+)\.(ipa|plist|dSYM\.tar\.gz)/)
+                  name_match = location_map['name'].match(/(\S+)\.(.*)/)
                   new_name = "#{ref}.#{name_match[2]}"
                   location_map['name'] = new_name
                   fn(err, location_map)


Remove usage of repository.async in Workspace

Signed-off-by: Nathan Sobo <2e8aa918660411855c6d44d5bb2da677aa033255@github.com>

--- src/workspace.coffee
+++ src/workspace.coffee
@@ -1097,7 +1097,7 @@
       checkoutHead = =>
         @project.repositoryForDirectory(new Directory(editor.getDirectoryPath()))
           .then (repository) ->
-            repository?.async.checkoutHeadForEditor(editor)
+            repository?.checkoutHeadForEditor(editor)

       if @config.get('editor.confirmCheckoutHeadRevision')
         @applicationDelegate.confirm


Only clear() markers from owned MarkerLayers

--- src/display-marker-layer.coffee
+++ src/display-marker-layer.coffee
@@ -27,7 +27,7 @@
   destroy: ->
     return if @destroyed
     @destroyed = true
-    @clear()
+    @clear() if @ownsBufferMarkerLayer
     @subscriptions.dispose()
     @bufferMarkerLayer.displayMarkerLayers.delete(this)
     @bufferMarkerLayer.destroy() if @ownsBufferMarkerLayer


Fix error when calling application executor from packaged app

--- src/flux/stores/database.coffee
+++ src/flux/stores/database.coffee
@@ -1,7 +1,7 @@
 Reflux = require 'reflux'
 Actions = require '../actions/database'
 Common = require '../common/application'
-Executor = new (require('remote').require('../browser/application-executor.coffee'))
+Executor = new (require('remote').require('../browser/application-executor'))

 cache =
   loading: false


:bug: Fix a typo

:bug: Fix a typo

--- lib/helpers.coffee
+++ lib/helpers.coffee
@@ -5,7 +5,7 @@

 Helpers = module.exports =
   error: (e) ->
-    atom.notifications.addError(e.message, {detail: e.stack, dismissible: true})
+    atom.notifications.addError(e.message, {detail: e.stack, dismissable: true})
   shouldTriggerLinter: (linter, bufferModifying, onChange, scopes) ->
     # Trigger lint-on-Fly linters on both events but on-save linters only on save
     # Because we want to trigger onFly linters on save when the


Initialize is no longer needed

Initialize is no longer needed

--- lib/motions.coffee
+++ lib/motions.coffee
@@ -4,7 +4,6 @@

 class Motion
   constructor: (@editor, @state) ->
-    @initialize?()

   isComplete: -> true
   isRecordable: -> false


Fix for issue #87

Fix for issue #87

--- src/knockback-core/knockback-collection-observable.coffee
+++ src/knockback-core/knockback-collection-observable.coffee
@@ -304,6 +304,7 @@

         observable = kb.utils.wrappedObservable(@)
         collection = @_collection()
+        return if (collection.indexOf(arg) == -1) # the model may have been removed before we got a chance to add it
         return if (view_model = @viewModelByModel(arg)) # it may have already been added by a change event
         @in_edit++
         view_model = @_createViewModel(arg)


Coffeescript is awesome

Coffeescript is awesome

--- lib/pg-hoff.coffee
+++ lib/pg-hoff.coffee
@@ -100,28 +100,27 @@

         pgHoff = @
         return @listServersView.connect(@listServersViewPanel)
-            .then (server) ->
+            .then (server) =>
                 if server.already_connected
                     atom.notifications.addInfo('Using ' + server.alias)
                 else
                     atom.notifications.addSuccess('Connected to ' + server.alias)

                 paneItem.alias = server.alias
-            .catch (error) ->
+            .catch (error) =>
                 atom.notifications.addError(error)
-            .finally ->
-                pgHoff.listServersViewPanel.hide()
+            .finally =>
+                @listServersViewPanel.hide()

     renderResults: (resultsets, pgHoff) ->
-        pgHoff.resultsViewPanel.show();
-        pgHoff.resultsView.update(resultsets)
+        @resultsViewPanel.show();
+        @resultsView.update(resultsets)

     keepGoing: (url, complete, pgHoff) ->
-        interval = setInterval( () ->
+        interval = setInterval( () =>
             return PgHoffServerRequest.Get(url, false)
-                .then (resultsets) ->
-                    i = 0
-                    for resultset in resultsets
+                .then (resultsets) =>
+                    for resultset, i in resultsets
                         if resultset.error
                             complete[i] = true
                             atom.notifications.addError(resultset.error)
@@ -131,34 +130,27 @@
                             else
                                 if complete[i] == false
                                     complete[i] = true
-                        i++

-                    pgHoff.renderResults(resultsets, pgHoff)
+                    @renderResults(resultsets, pgHoff)
                     if !complete.some( (val) -> return val == false )
                         clearInterval(interval)

-                .catch (err) ->
+                .catch (err) =>
                     console.error 'catch', err
                     clearInterval(interval)
                     atom.notifications.addError(err)
         , atom.config.get('pg-hoff.pollInterval'))

     executeQueryWithConnect: ->
-        alias = atom.workspace.getActivePaneItem().alias
-        pgHoff = @
-        if (alias)
-            pgHoff.executeQuery()
+        if atom.workspace.getActivePaneItem().alias?
+            @executeQuery()
         else
-            promise = @connect()
-            if not promise?
-                return
-            else
-                promise
-                    .then ->
-                        pgHoff.executeQuery()
-                    .catch (err) ->
-                        console.error 'Connect error', err
-                        atom.notifications.addError('Connect error')
+            return @connect()?.then =>
+                    @executeQuery()
+                .catch (err) ->
+                    console.error 'Connect error', err
+                    atom.notifications.addError('Connect error')
+
     executeQuery: ->
         selectedText = atom.workspace.getActiveTextEditor().getSelectedText().trim()
         pgHoff = @
@@ -166,11 +158,11 @@
             if atom.config.get('pg-hoff.executeAllWhenNothingSelected')
                 selectedText = atom.workspace.getActiveTextEditor().getText().trim()
             else
-                pgHoff.resultsViewPanel.hide()
+                resultsViewPanel.hide()
                 return

         return PgHoffQuery.Execute(selectedText)
-            .then (result) ->
+            .then (result) =>
                 complete = []
                 queryStillExecuting = false
                 for resultset in result.resultsets
@@ -184,10 +176,10 @@
                         else
                             complete.push(true)
                 if queryStillExecuting
-                    pgHoff.keepGoing(result.url, complete, pgHoff)
+                    @keepGoing(result.url, complete)

-                pgHoff.renderResults(result.resultsets, pgHoff)
-            .catch (err) ->
+                @renderResults(result.resultsets)
+            .catch (err) =>
                 atom.workspace.getActivePaneItem().alias = null
-                pgHoff.resultsViewPanel.hide()
+                @resultsViewPanel.hide()
                 atom.notifications.addError(err)


header/body customisation is kinda important

--- lib/results.coffee
+++ lib/results.coffee
@@ -11,7 +11,7 @@
     body.classList.add 'body'
     body

-  result: (ed) ->
+  result: (ed, opts) ->
     view = document.createElement 'div'
     view.classList.add 'ink', 'inline', 'result'
     view.style.position = 'relative'
@@ -21,8 +21,8 @@
     body = @body()
     view.appendChild header
     view.appendChild body
-    header.innerText = "Result"
-    body.innerText = "[1, 2, 3\n 4, 5, 6\n 7, 8, 9]"
+    header.innerText = opts.header
+    body.innerText = opts.body
     view: view
     header: header
     body: body
@@ -35,11 +35,13 @@
     r.hide = => @hideBody r
     r.toggle = => @toggle r

-  show: (ed, mark, {watch}={watch: true}) ->
+  show: (ed, mark, {watch, header, body}={}) ->
     mark.getBufferRange().isReversed and throw "Cannot add result to reversed marker"
     @removeLines ed, mark.getHeadBufferPosition().row,
                      mark.getTailBufferPosition().row
-    result = @result ed
+    result = @result ed,
+      header: header
+      body: body
     mark.result = result
     result.editor = ed
     result.marker = mark
@@ -53,7 +55,7 @@
     result.view.style.opacity = 0
     @timeout 10, =>
       result.view.style.opacity = null
-    watch and @watchText result
+    watch != false and @watchText result
     @watchNewline result
     result


Set carousel speed to 15 seconds

Set carousel speed to 15 seconds

--- scripts/modules/featured-books/featured-books.coffee
+++ scripts/modules/featured-books/featured-books.coffee
@@ -69,4 +69,4 @@

         # Start the carousel
         if @_carousel then clearInterval(@_carousel)
-        @_carousel = setInterval(nextFeatured, 3000)
+        @_carousel = setInterval(nextFeatured, 15000)


use array instead of else statement

use array instead of else statement

--- lib/installed-package-view.coffee
+++ lib/installed-package-view.coffee
@@ -112,7 +112,7 @@
       for child in fs.listSync(@pack.path)
         extension = path.extname(child)
         name = path.basename(child, extension)
-        if name.toLowerCase() is 'changelog' | 'history'
+        if name.toLowerCase() in ['changelog', 'history']
           atom.workspaceView.open(child)
           break
       false


Rename isDirectory() to isDirectorySync()

--- lib/package-generator-view.coffee
+++ lib/package-generator-view.coffee
@@ -67,7 +67,7 @@
       relativePath = @replacePackageNamePlaceholders(relativePath, packageName)

       sourcePath = path.join(@getPackagePath(), relativePath)
-      if fsUtils.isDirectory(templateChildPath)
+      if fsUtils.isDirectorySync(templateChildPath)
         fsUtils.makeTree(sourcePath)
       if fsUtils.isFile(templateChildPath)
         fsUtils.makeTree(path.dirname(sourcePath))


More explicit warning messages

More explicit warning messages

--- lib/behaviours.coffee
+++ lib/behaviours.coffee
@@ -16,7 +16,7 @@
     behaviour.apply context, args

   else
-    console.warn 'Behaviour not found'
+    console.warn "Attach failed, behaviour \"#{behaviour}\" not found"

   return

@@ -45,7 +45,7 @@
       behaviours[name].options = options

     else
-      console.warn 'Configure failed, behaviour not found'
+      console.warn "Configure failed, behaviour \"#{name}\" not found"

   define: (name, behaviour, options) ->
     check name, String


Rename for clarity

Rename for clarity

--- lib/diffs-view.coffee
+++ lib/diffs-view.coffee
@@ -5,7 +5,7 @@

 """

-CommitTemplateString = """
+CommitSummaryTemplateString = """

@@ -71,9 +71,9 @@
         commitNode = commitNode.parentNode
       if commitNode?
         sha = commitNode.querySelector('.sha').textContent
-        @renderDiff(sha)
+        @renderCommitDetail(sha)

-    @commitTemplate = TemplateHelper.addTemplate(this, CommitTemplateString)
+    @commitTemplate = TemplateHelper.addTemplate(this, CommitSummaryTemplateString)

     @renderHistory().catch (error) ->
       console.error error.message, error
@@ -82,7 +82,16 @@
   getTitle: ->
     'Yeah, view that diff!'

-  renderCommit: (commit) ->
+  renderHistory: ->
+    new Promise (resolve, reject) =>
+      @history.walkHistory (commit) =>
+        promise = @renderCommitSummary(commit)
+        resolve(commit)
+        promise
+    .then (firstCommit) =>
+      @renderCommitDetail(firstCommit.sha())
+
+  renderCommitSummary: (commit) ->
     # We still dont have a good view framework yet
     commitNode = TemplateHelper.renderTemplate(@commitTemplate)
     commitNode.querySelector('.sha').textContent = commit.sha()
@@ -91,16 +100,7 @@
     commitNode.firstElementChild.id = "sha-#{commit.sha()}"
     @historyNode.appendChild(commitNode)

-  renderHistory: ->
-    new Promise (resolve, reject) =>
-      @history.walkHistory (commit) =>
-        promise = @renderCommit(commit)
-        resolve(commit)
-        promise
-    .then (firstCommit) =>
-      @renderDiff(firstCommit.sha())
-
-  renderDiff: (sha) ->
+  renderCommitDetail: (sha) ->
     @diffsNode.innerHTML = ''

     for commitNode in @querySelectorAll('.commit')


Hide the button from an action if it's not truly a button

--- js/inner.coffee
+++ js/inner.coffee
@@ -153,8 +153,11 @@
       success: komp => @status() == "success"
       failed: komp => @status() == "failed"

-    @action_header_button_style =
-      @action_header_style
+    @action_header_button_style = komp =>
+      if @has_content()
+        @action_header_style
+      else
+        {}

     @action_log_style =
       minimize: @minimize


change foo to user

change foo to user

--- app/assets/javascripts/initializers/current_user.js.coffee
+++ app/assets/javascripts/initializers/current_user.js.coffee
@@ -11,8 +11,8 @@
         container.register('foo:current', ->
           @store.getById('user', currentUserId)
         , instantiate: false)
-        application.inject('controller', 'getCurrentUser', 'foo:current')
-        application.inject('route', 'getCurrentUser', 'foo:current')
+        application.inject('controller', 'getCurrentUser', 'user:current')
+        application.inject('route', 'getCurrentUser', 'user:current')
         ETahi.advanceReadiness()
       , (error) -> null
       )


Fix the year filter for brand new users. [#42995289]

--- app/assets/javascripts/views/_shared/year.filter.js.coffee
+++ app/assets/javascripts/views/_shared/year.filter.js.coffee
@@ -16,8 +16,9 @@
       year: year

   render: ->
+    yearFilter = localStorage.getItem("yearFilter")
     @$el.html StaffPlan.Templates.Shared.yearFilter
       relevantYears: StaffPlan.relevantYears.sort()
-      buttonText: "Showing: #{if localStorage.getItem("yearFilter") == "all" then "All Fiscal Years" else "FY #{localStorage.getItem("yearFilter")}"}"
+      buttonText: "Showing: #{if(yearFilter == null || yearFilter == "all") then "All Fiscal Years" else "FY #{yearFilter}"}"

     @


Apps: Removed app couldn't be created event handler when app is created.

--- client/app/Applications/StartTab.kdapplication/views/appthumbview.coffee
+++ client/app/Applications/StartTab.kdapplication/views/appthumbview.coffee
@@ -212,12 +212,16 @@

     return if $(event.target).closest('.icon-container').length > 0 or \
               $(event.target).closest('.dev-mode').length > 0
-    manifest = @getData()
+
     @showLoader()
+
+    manifest   = @getData()
     appManager = KD.getSingleton "appManager"
-    appManager.once "AppCouldntBeCreated", => @hideLoader()
+    hideLoader = => @hideLoader()
+    appManager.once "AppCouldntBeCreated", => hideLoader()
     appManager.open manifest.name, =>
-      @hideLoader()
+      hideLoader()
+      appManager.off "AppCouldntBeCreated", hideLoader
       KD.track "Apps", "ApplicationRun", manifest.name

   showLoader:->


Fixed argument format.

Fixed argument format.

--- client/app/CommonViews/paymentwidgets.coffee
+++ client/app/CommonViews/paymentwidgets.coffee
@@ -53,9 +53,7 @@
       callback err or not account or not account.cardNumber

   checkSubscription:(callback)->
-    KD.remote.api.JRecurlySubscription.checkUserSubscription
-      planCode: @planCode
-    , (err, subs)=>
+    KD.remote.api.JRecurlySubscription.checkUserSubscription @planCode, (err, subs)=>
       subscribed = no
       subs.forEach (sub)=>
         if sub.status in ['canceled', 'active']


Client: Activity: Added handleSetParticipantDeleteFlag and handleUnsetParticipantDeleteFlag event handlers to set/unset _mayDelete flag to user

--- client/app/lib/flux/stores/usersstore.coffee
+++ client/app/lib/flux/stores/usersstore.coffee
@@ -26,6 +26,8 @@
     @on actions.BLOCK_USER_SUCCESS, @handleBlockUserSuccess
     @on actions.BLOCK_USER_FAIL, @handleBlockUserFail

+    @on actions.SET_CREATE_CHANNEL_PARTICIPANT_DELETE_FLAG, @handleSetParticipantDeleteFlag
+    @on actions.UNSET_CREATE_CHANNEL_PARTICIPANT_DELETE_FLAG, @handleUnsetParticipantDeleteFlag

   ###*
    * Load account.
@@ -161,3 +163,30 @@
   ###
   handleBlockUserFail: (users, account) -> users

+
+  ###*
+   * It sets _mayDelete value by given accountId.
+   *
+   * @param {Immutable.Map} users
+   * @param {object} payload
+   * @param {string} payload.accountId
+  ###
+  handleSetParticipantDeleteFlag: (users, { accountId }) ->
+
+    return users = users.setIn [accountId, '_mayDelete'], yes
+
+
+  ###*
+   * It removes _mayDelete value by given accountId.
+   *
+   * @param {Immutable.Map} users
+   * @param {object} payload
+   * @param {string} payload.accountId
+  ###
+  handleUnsetParticipantDeleteFlag: (users, { accountId }) ->
+
+    user = users.get accountId
+    user = user.remove '_mayDelete'
+    users = users.set accountId, user
+    return users
+


app/storage: do not hardcode default version and group name

--- client/app/lib/appstorage.coffee
+++ client/app/lib/appstorage.coffee
@@ -1,87 +1,107 @@
-whoami = require './util/whoami'
-kd = require 'kd'
-KDObject = kd.Object
-module.exports = class AppStorage extends KDObject
+kd       = require 'kd'
+whoami   = require './util/whoami'

-  constructor: (appId, version = '1.0')->
-    @_applicationID = appId
+module.exports =
+
+class AppStorage extends kd.Object
+
+  @DEFAULT_VERSION: '1.0'
+
+  DEFAULT_GROUP_NAME = 'bucket'
+
+  constructor: (appId, version = AppStorage.DEFAULT_VERSION) ->
+
+    @_applicationID      = appId
     @_applicationVersion = version
+
     @reset()
+
     super

-  fetchStorage: (callback, force = no)->

-    [appId, version] = [@_applicationID, @_applicationVersion]
+  fetchStorage: (callback, force = no) ->
+
+    [ appId, version ] = [ @_applicationID, @_applicationVersion ]

     if not @_storage or force
-      {mainController} = kd.singletons
+
+      { mainController } = kd.singletons
+
       mainController.ready =>
-        whoami().fetchAppStorage {appId, version}, (error, storage) =>
+        whoami().fetchAppStorage { appId, version }, (error, storage) =>
+
           if not error and storage
             @_storage = storage
             callback? @_storage
-            @emit "storageFetched"
-            @emit "ready"
+            @emit 'storageFetched'
+            @emit 'ready'
           else
             callback? null
+
     else
+
       kd.utils.defer =>
         callback? @_storage
-        @emit "storageFetched"
-        @emit "ready"
+        @emit 'storageFetched'
+        @emit 'ready'

-  fetchValue: (key, callback, group = 'bucket', force = no)->
+
+  fetchValue: (key, callback, group = DEFAULT_GROUP_NAME, force = no) ->

     @reset()
-    @fetchStorage (storage)->
+
+    @fetchStorage (storage) ->
       callback  if storage?[group]?[key] then storage[group][key]
     , force

-  getValue: (key, group = 'bucket')->
+
+  getValue: (key, group = DEFAULT_GROUP_NAME) ->

     return unless @_storage
     return if @_storageData[group]?[key]? then @_storageData[group][key]
     return if @_storage[group]?[key]? then @_storage[group][key]

-  setValue: (key, value, callback, group = 'bucket')->
+
+  setValue: (key, value, callback, group = DEFAULT_GROUP_NAME) ->

     pack = @zip key, group, value

     @_storageData[group] = {}  unless @_storageData[group]?
     @_storageData[group][key] = value

-    @fetchStorage (storage)->
+    @fetchStorage (storage) ->
       storage?.update {
         $set: pack
       }, -> callback?()

-  setDefaults: (defaults)->
+  setDefaults: (defaults) ->

     for own key, value of defaults
       @setValue key, value  unless (@getValue key)?

-  unsetKey: (key, callback, group = 'bucket')->
+  unsetKey: (key, callback, group = DEFAULT_GROUP_NAME) ->

     pack = @zip key, group, 1

-    @fetchStorage (storage)=>
+    @fetchStorage (storage) =>
       delete @_storageData[group]?[key]
       storage.update {
         $unset: pack
       }, -> callback?()

+
   reset: ->
+
     @_storage = null
     @_storageData = {}
+

   zip: (key, group, value) ->

     pack = {}
     _key = group+'.'+key
     pack[_key] = value
+
     pack
-
-
-


Create video action button when video session connected

--- client/ide/lib/views/chat/idechatview.coffee
+++ client/ide/lib/views/chat/idechatview.coffee
@@ -43,6 +43,8 @@
     @once 'CollaborationNotInitialized', @bound 'removeLoader'
     @once 'CollaborationEnded',          @bound 'destroy'

+    @on 'VideoSessionConnected', @bound 'handleVideoSessionConnected'
+
     @on 'VideoCollaborationActive', @bound 'handleVideoActive'
     @on 'VideoCollaborationEnded',  @bound 'handleVideoEnded'
     @on 'VideoActiveParticipantDidChange', @bound 'handleVideoActiveParticipantChanged'
@@ -154,6 +156,11 @@
     else @unsetClass 'is-videoActive'

     kd.utils.defer @bound 'focus'
+
+
+  handleVideoSessionConnected: (options) ->
+
+    @chatPane.createVideoActionButton options.action

   handleVideoActive: ->


Add tooltips and color-swatches to datum on visualizations

--- client/src/scripts/scoring-sheet-view.coffee
+++ client/src/scripts/scoring-sheet-view.coffee
@@ -587,11 +587,18 @@
   markup: div()
   behavior: render

+createInspectionColorSwatch = ->
+  pop geyser.generate [ "div style='display:inline-block;width:12px;height:12px;margin-right:7px;background-color:$color'" ]
+
 createMetricInspection = (variables, metric) ->
-  [ div, h1, h2, table, tbody, tr, th, td ] = geyser.generate words 'div h1 h2 table.table.table-condensed tbody tr th td'
+  [ div, h1, h2, table, tbody, tr, th, td, span ] = geyser.generate words 'div h1 h2 table.table.table-condensed tbody tr th td span'
+  swatch = createInspectionColorSwatch()

   div [
-    h1 metric.caption
+    h1  [
+      swatch '', $color:metric.color
+      span metric.caption
+    ]
     table tbody map variables, (variable) ->
       value = variable.read metric
       tr [
@@ -601,7 +608,8 @@
   ]

 createThresholdInspection = (variables, metric, index) ->
-  [ div, h1, h2, table, grid, tbody, tr, th, td ] = geyser.generate words 'div h1 h2 table.table.table-condensed table.table.table-bordered tbody tr th td'
+  [ div, h1, h2, table, grid, tbody, tr, th, td, span ] = geyser.generate words 'div h1 h2 table.table.table-condensed table.table.table-bordered tbody tr th td span'
+  swatch = createInspectionColorSwatch()

   tabulateProperties = (index) ->
     table tbody map variables, (variable) ->
@@ -611,7 +619,10 @@
       ]

   div [
-    h1 metric.caption
+    h1  [
+      swatch '', $color:metric.color
+      span metric.caption
+    ]
     h2 'Outputs'
     tabulateProperties index
   ]
@@ -690,6 +701,8 @@
     .attr 'cy', (d) -> scaleY readY d
     .attr 'stroke', (d) -> d.color
     .on 'click', (d) -> inspect d
+    .append 'title'
+    .text (d) -> d.caption

   el

@@ -794,6 +807,8 @@
         d3.select(@).style 'stroke', metric.color
       .on 'mouseout', (index) ->
         d3.select(@).style 'stroke', 'none'
+      .append 'title'
+      .text metric.caption
   el

 createFilter = (variable) ->


Tests: Teams: Added wait selector

Tests: Teams: Added wait selector

--- client/test/lib/teams/teamslikeunlike.coffee
+++ client/test/lib/teams/teamslikeunlike.coffee
@@ -41,9 +41,9 @@

   deletePost: (browser) ->
-
+
     message = helpers.getFakeText()
-
+
     user = teamsHelpers.loginTeam(browser)
     teamsHelpers.createChannel(browser, user)
     teamsHelpers.sendComment(browser, message)
@@ -52,24 +52,25 @@

   editPostUsingUPkey: (browser) ->
-
+
     message           = helpers.getFakeText()
     chatInputSelector = '.ChatPaneFooter .ChatInputWidget textarea'
     textSelector      = '.ChatItem .SimpleChatListItem.ChatItem-contentWrapper .ChatListItem-itemBodyContainer'
     editingSelector   = '.SimpleChatListItem.editing .ChatItem-updateMessageForm.visible .ChatInputWidget textarea'
     chatItem          = '.Pane-body .ChatList .ChatItem:nth-of-type(3)'
-
+
     user = teamsHelpers.loginTeam(browser)
     teamsHelpers.createChannel(browser, user)
     teamsHelpers.sendComment(browser, message)
-
+
     browser
       .waitForElementVisible  textSelector, 20000
       .setValue               chatInputSelector, browser.Keys.UP_ARROW
-      .waitForElementVisible  editingSelector, 20000
+      .waitForElementVisible  editingSelector, 20000
       .clearValue             editingSelector
+      .pause                  3000 #slow down
       .setValue               editingSelector, 'Message after editing' + browser.Keys.ENTER
       .waitForElementVisible  chatItem, 20000
       .pause                  3000 #waiting for text to be changed
       .assert.containsText    chatItem, 'Message after editing'
-      .end()+      .end()


Mirror the changes in Aura

Mirror the changes in Aura

--- src/client/component/templates.coffee
+++ src/client/component/templates.coffee
@@ -91,9 +91,9 @@
     deferred: undefined
     initialize: (app) ->
       module.domFind = app.core.dom.find
-      module.deferred = app.core.data.deferred
+      module.deferred = app.core.promises.deferred
       app.core.template.load = (names=[], ref, el, format="hbs") ->
-        dfd = app.core.data.deferred()
+        dfd = app.core.promises.deferred()
         names = [names] if _.isString(names)
         componentProps =
           componentName: ref.replace('__component__$', '').split('@')[0]


Renomeia $template para context e retira redundancias

--- src/coffee/portal-sku-selector.coffee
+++ src/coffee/portal-sku-selector.coffee
@@ -61,7 +61,7 @@
 			@selectedDimensionsMap[key] = undefined if foundCurrent
 			foundCurrent = true if key is dimensionName

-	# Renders the DOM elements of the Sku Selector, given the JSON and the templates
+	# Renders the DOM elements of the Sku Selector, given the context
 	renderSkuSelector: (context) =>
 		dimensionIndex = 0

@@ -121,11 +121,11 @@
 					skuDimensionValue = sku.dimensions[dimension]
 					# If the dimension value matches, enable the button
 					if skuDimensionValue is value
-						selectors.itemDimensionValueInput(dimension, value, $template).removeAttr('disabled')
+						selectors.itemDimensionValueInput(dimension, value, context).removeAttr('disabled')
 					# If the dimension value matches and this sku is available, show as selectable
 					if skuDimensionValue is value and sku.available
-						selectors.itemDimensionValueInput(dimension, value, $template).removeClass('item_unavaliable')
-						selectors.itemDimensionValueLabel(dimension, value, $template).removeClass('disabled item_unavaliable')
+						selectors.itemDimensionValueInput(dimension, value, context).removeClass('item_unavaliable')
+						selectors.itemDimensionValueLabel(dimension, value, context).removeClass('disabled item_unavaliable')

 $.fn.skuSelector = (productId, name, dimensions, skus, options = {}) ->
@@ -143,9 +143,9 @@
 	available = skuSelectorObj.findAvailableSkus()
 	if available.length is 0
 		# showWarningUnavailable
-		options.selectors.warnUnavailable($template).find('input#notifymeSkuId').val(skus[0].sku)
-		options.selectors.warnUnavailable($template).show()
-		$('.skuselector-buy-btn', $template).hide()
+		options.selectors.warnUnavailable(this).find('input#notifymeSkuId').val(skus[0].sku)
+		options.selectors.warnUnavailable(this).show()
+		options.selectors.buyButton(this).hide()
 	else if available.length is 1
 		updatePrice(available[0], options, this)

@@ -271,32 +271,32 @@
 	el = (if available.length > 0 then available else dimArray).filter('input:enabled')[0]
 	$(el).attr('checked', 'checked').change() if dimArray.length > 0

-updatePrice = (sku, options, template) ->
+updatePrice = (sku, options, context) ->
 	if sku and sku.available
-		updatePriceAvailable(sku, options, template)
+		updatePriceAvailable(sku, options, context)
 	else
-		updatePriceUnavailable(options, template)
-
-updatePriceAvailable = (sku, options, template) ->
+		updatePriceUnavailable(options, context)
+
+updatePriceAvailable = (sku, options, context) ->
 	listPrice = formatCurrency sku.listPrice
 	bestPrice = formatCurrency sku.bestPrice
 	installments = sku.installments
 	installmentValue = formatCurrency sku.installmentsValue

 	# Modifica href do botão comprar
-	options.updateBuyButtonURL($.skuSelector.getAddUrlForSku(sku.sku), template)
-	options.selectors.price(template).show()
-	options.selectors.buyButton(template).show()
-	options.selectors.listPriceValue(template).text("R$ #{listPrice}")
-	options.selectors.bestPriceValue(template).text("R$ #{bestPrice}")
+	options.updateBuyButtonURL($.skuSelector.getAddUrlForSku(sku.sku), context)
+	options.selectors.price(context).show()
+	options.selectors.buyButton(context).show()
+	options.selectors.listPriceValue(context).text("R$ #{listPrice}")
+	options.selectors.bestPriceValue(context).text("R$ #{bestPrice}")
 	if installments > 1
-		options.selectors.installment(template).text("ou até #{installments}x de R$ #{installmentValue}")
-
-updatePriceUnavailable = (options, template) ->
+		options.selectors.installment(context).text("ou até #{installments}x de R$ #{installmentValue}")
+
+updatePriceUnavailable = (options, context) ->
 	# Modifica href do botão comprar
-	options.updateBuyButtonURL('javascript:void(0);', template)
-	options.selectors.price(template).hide()
-	options.selectors.buyButton(template).hide()
+	options.updateBuyButtonURL('javascript:void(0);', context)
+	options.selectors.price(context).hide()
+	options.selectors.buyButton(context).hide()
 	# $('.notifyme-skuid').val()

 # Sanitizes text: "Caçoá (teste 2)" becomes "cacoateste2"
@@ -318,30 +318,4 @@
 	if value? and not isNaN value
 		return parseFloat(value/100).toFixed(2).replace('.',',').replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.')
 	else
-		return "Grátis"
-
-# Disable unselectable SKUs given the current selections
-disableInvalidInputs = (uniqueDimensionsMap, undefinedDimensions, selectableSkus, $template, selectors) ->
-	# First, find the first undefined dimension selection list
-	firstUndefinedDimensionName = undefinedDimensions[0]
-
-	# If there is no undefined dimension, there is nothing to disable.
-	return unless firstUndefinedDimensionName
-
-	for dimension in undefinedDimensions
-		# Second, disable all options in this row, add disabled class, remove checked class and matching removeAttr checked
-		selectors.itemDimensionInput(dimension, $template).addClass('item_unavaliable').removeAttr('checked').removeClass('checked sku-picked').attr('disabled', 'disabled')
-		selectors.itemDimensionLabel(dimension, $template).addClass('disabled item_unavaliable').removeClass('checked sku-picked')
-
-		# Third, enable all selectable options in this row
-		for value in uniqueDimensionsMap[dimension]
-			# Search for the sku dimension value corresponding to this dimension
-			for sku in selectableSkus
-				skuDimensionValue = sku.dimensions[dimension]
-				# If the dimension value matches, enable the button
-				if skuDimensionValue is value
-					selectors.itemDimensionValueInput(dimension, value, $template).removeAttr('disabled')
-				# If the dimension value matches and this sku is available, show as selectable
-				if skuDimensionValue is value and sku.available
-					selectors.itemDimensionValueInput(dimension, value, $template).removeClass('item_unavaliable')
-					selectors.itemDimensionValueLabel(dimension, value, $template).removeClass('disabled item_unavaliable')+		return "Grátis"


:bug: do not automatically open the web view URL

--- src/components/navbar/book-links.cjsx
+++ src/components/navbar/book-links.cjsx
@@ -25,8 +25,6 @@
         </a>
       )

-    window.open(course.webview_url, 'cc-webview-link')
-
     <li className='book-links'>
       {links}
     </li>


load paystation script and get token in parallel

--- resources/assets/coffee/_classes/store-checkout.coffee
+++ resources/assets/coffee/_classes/store-checkout.coffee
@@ -20,31 +20,34 @@
   @initialize: ->
     return unless document.querySelector('#js-xsolla-pay')
     document.querySelector('#js-xsolla-pay').disabled = true
+    # load script
+    deferredScript = $.Deferred()
+    script = document.createElement('script')
+    script.type = "text/javascript"
+    script.async = true
+    script.src = "https://static.xsolla.com/embed/paystation/1.0.7/widget.min.js"
+    script.addEventListener 'load', ->
+      deferredScript.resolve()
+    , false
+    head = document.getElementsByTagName('head')[0]
+    head.appendChild(script)
+
+    deferredToken = $.Deferred()
+    # get token
     xhr = @getXsollaToken()
     xhr.done (data) ->
-      console.log(data)
-      StoreCheckout.initializeXsollaCheckout(data)
+      deferredToken.resolve(data)

-  @initializeXsollaCheckout: (token) ->
+    $.when(deferredScript, deferredToken).done (_, token) =>
+      options = @optionsWithToken(token)
+      XPayStationWidget.init(options)
+      document.querySelector('#js-xsolla-pay').disabled = false
+
+  @optionsWithToken: (token) ->
     options =
       access_token: token,
       sandbox: true

-    StoreCheckout.initButton(options)
-
-  @initButton: (options) ->
-    s = document.createElement('script')
-    s.type = "text/javascript"
-    s.async = true
-    s.src = "https://static.xsolla.com/embed/paystation/1.0.7/widget.min.js"
-    s.addEventListener 'load', ->
-      console.debug 'xsolla widget loaded'
-      console.log(options)
-      XPayStationWidget.init(options)
-      document.querySelector('#js-xsolla-pay').disabled = false
-    , false
-    head = document.getElementsByTagName('head')[0]
-    head.appendChild(s)
-
   @getXsollaToken: ->
     $.get laroute.route('store.payments.xsolla-token')
+