Stream no longer uses an explicit global suspend method.

--- lib/stream_test.coffee
+++ lib/stream_test.coffee
@@ -1,16 +1,13 @@
-suspend = (code) ->
-  cache = {
-    force: ->
-      val = code()
-      this.force = () -> val
-      val
-  }
-  -> cache.force()
-
-
 class Stream
   constructor: (@first, rest) ->
-    @rest = if rest? then suspend(rest) else -> null
+    if typeof(rest) == 'function'
+      @rest = () -> @force_rest(rest())
+    else
+      @force_rest(rest)
+
+  force_rest: (val) ->
+    @rest = () -> val
+    val

   take_while: (pred) ->
     if pred(@first)
@@ -48,17 +45,17 @@
     new Stream(op(this.first, other.first), =>
       this.rest().combine(other.rest(), op) if this.rest() and other.rest())

-  plus:  (other) -> this.combine(other, (a,b) -> a + b)
-  minus: (other) -> this.combine(other, (a,b) -> a - b)
-  times: (other) -> this.combine(other, (a,b) -> a * b)
-  by:    (other) -> this.combine(other, (a,b) -> a / b)
+  plus:  (other) -> @combine(other, (a,b) -> a + b)
+  minus: (other) -> @combine(other, (a,b) -> a - b)
+  times: (other) -> @combine(other, (a,b) -> a * b)
+  by:    (other) -> @combine(other, (a,b) -> a / b)

   accumulate: (start, op) ->
     new_start = op(start, @first)
     new Stream(new_start, => @rest().accumulate(new_start, op) if @rest())

-  sums:     -> this.accumulate(0, (a,b) -> a + b)
-  products: -> this.accumulate(1, (a,b) -> a * b)
+  sums:     -> @accumulate(0, (a,b) -> a + b)
+  products: -> @accumulate(1, (a,b) -> a * b)

   merge: (other) -> new Stream(@first, => other.merge(@rest()) if other)

@@ -80,8 +77,7 @@
       stream = stream.rest()
     results

-  toString: ->
-    this.toArray().join(', ')
+  toString: -> @toArray().join(', ')

 Stream.iterate = (start, step) ->
   new Stream(start, -> Stream.iterate(step(start), step))
@@ -135,8 +131,8 @@
 puts fibonacci.take_while((n) ->  n < 1000000).last()
 puts()

-test   = (p) -> (n) -> n % p != 0
-sieve  = (s) -> new Stream(s.first, -> sieve(s.rest().select(test(s.first))))
+next   = (s) -> sieve(s.rest().select((n) -> n % s.first != 0))
+sieve  = (s) -> new Stream(s.first, -> next(s))
 primes = sieve(Stream.from(2))

 puts "The prime numbers between 10000 and 10100:"


Remove jQuery from utils

Remove jQuery from utils

--- lib/utils/index.coffee
+++ lib/utils/index.coffee
@@ -1,5 +1,4 @@
 debug = require('debug') 'kd:utils'
-$ = require 'jquery'

 module.exports =


remove depreciated code in store

remove depreciated code in store

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -31,7 +31,6 @@
       @eventClearCart()
       @eventUpdateCartNavCounter()
       @eventUpdateConfig()
-      @eventSelectPreset()
       @eventSelectLicense()
       @eventFillCartFromQueryString()
       @eventRenderCart()
@@ -135,11 +134,6 @@
                 product_id = ['pupil',worldId,eyeId,licenseId].join("_")
               else
                 product_id = ['pupil',worldId,eyeId].join("_")
-
-              # id = [worldId,eyeId]
-              # price = @_calcConfigSubTotal([@worldConfigActiveClass,@eyeConfigActiveClass,@licenseConfigActiveClass])
-              # specs = $(@worldConfigActiveClass).data('specs') + "," + $(@eyeConfigActiveClass).data('specs')
-              # license = $(@licenseConfigActiveClass).data('id')
             else
               product_id = $(addToCartBtn).attr('id')

@@ -216,17 +210,6 @@
         if $(@eyeConfigActiveClass).attr('id') is "e120b"
           $("#w30").addClass("StoreConfig--state-inactive")

-  eventSelectPreset: ->
-    if $(@storePage).length > 0
-      $(@storeConfigPresetClass).click (event)=>
-        event.preventDefault()
-        activeLink = $(event.currentTarget)
-        [worldId,eyeId] = $(activeLink).data('preset').split(" ")
-        worldLink = "button[id='#{worldId}']"
-        eyeLink = "button[id='#{eyeId}']"
-        @_setActiveState([worldLink, eyeLink])
-        @_swapImg([worldLink, eyeLink])
-        @_updateConfigSubTotal()

   eventRenderCart: ->
     if $(@cartPage).length > 0
@@ -659,7 +642,6 @@
       @eventUpdateCartNavCounter()

-
   _getOrderPermalink: ->
     data = []
     i = 0
@@ -723,12 +705,6 @@
       for url in imageUrls
         (new Image()).src = url

-  _calcConfigSubTotal: (links)->
-    sum = 0
-    for link in links
-      sum += $(link).data('cost')
-    return sum
-
   _updateConfigSubTotal: ->
     activeWorldId = $(@worldConfigActiveClass).attr('id')
     activeEyeId = $(@eyeConfigActiveClass).attr('id')


fix(macModal): Error message referencing undefined variable.

--- src/services/modal.coffee
+++ src/services/modal.coffee
@@ -137,7 +137,7 @@
     #
     register: (id, element, options, transclude) ->
       if @registered[id]?
-        throw new Error "Modal #{modalId} already registered"
+        throw new Error "Modal #{id} already registered"

       @registered[id] = {element, options, transclude}


Revert "remove dead references"

Revert "remove dead references"

This reverts commit dc69339565dbb93023202a241eb6e0c227d7db2a.

--- js/src/service/StorageClient.coffee
+++ js/src/service/StorageClient.coffee
@@ -7,6 +7,7 @@
   'kryptnostic.kryptnostic-object'
   'kryptnostic.crypto-service-loader'
   'kryptnostic.pending-object-request'
+  'kryptnostic.search-indexing-service'
 ], (require) ->
   'use strict'

@@ -17,6 +18,7 @@
   CryptoServiceLoader   = require 'kryptnostic.crypto-service-loader'
   ObjectApi             = require 'kryptnostic.object-api'
   Logger                = require 'kryptnostic.logger'
+  SearchIndexingService = require 'kryptnostic.search-indexing-service'

   logger = Logger.get('StorageClient')

@@ -31,6 +33,7 @@
     constructor : ->
       @objectApi             = new ObjectApi()
       @cryptoServiceLoader   = new CryptoServiceLoader()
+      @searchIndexingService = new SearchIndexingService()

     getObjectIds : ->
       return @objectApi.getObjectIds()
@@ -79,6 +82,8 @@
         @encrypt({ id, body, cryptoService })
       .then (encrypted) =>
         @submitObjectBlocks(encrypted)
+      .then =>
+        @searchIndexingService.submit({ id, storageRequest })
       .then ->
         return id


なぜかherokuでstartsWithの部分で落ちるためコメントアウト

なぜかherokuでstartsWithの部分で落ちるためコメントアウト

--- node_modules/hubot-discord/src/discord.coffee
+++ node_modules/hubot-discord/src/discord.coffee
@@ -16,9 +16,9 @@

      run: ->
         @options =
-            token: process.env.HUBOT_DISCORD_TOKEN
+            token: "Bot " + process.env.HUBOT_DISCORD_TOKEN
         # require oauth token type
-        @options.token = "Bot " + @options.token if not @options.token.startsWith "Bot "
+        #@options.token = "Bot " + @options.token if not @options.token.startsWith "Bot "

         @client = new Discord.Client {forceFetchUsers: true, autoReconnect: true}
         @client.on 'ready', @.ready


Removed event for callback that doesn't exist

--- core/app/backbone/views/channels_view.coffee
+++ core/app/backbone/views/channels_view.coffee
@@ -31,9 +31,6 @@
     list:   '.channel-listing-container'
     header: '.channel-listing-header'

-  initialize: ->
-    @bindTo @collection, 'reset', @setUserFromChannels, this
-
   onRender: ->
     @list.show new ChannelListView(collection: @collection)
     @header.show new ChannelHeaderView(@options)


add missing require

add missing require

--- services/web/app/coffee/Features/Templates/TemplatesController.coffee
+++ services/web/app/coffee/Features/Templates/TemplatesController.coffee
@@ -2,6 +2,7 @@
 Project = require('../../../js/models/Project').Project
 ProjectUploadManager = require('../../../js/Features/Uploads/ProjectUploadManager')
 ProjectOptionsHandler = require('../../../js/Features/Project/ProjectOptionsHandler')
+ProjectRootDocManager = require('../../../js/Features/Project/ProjectRootDocManager')
 AuthenticationController = require('../../../js/Features/Authentication/AuthenticationController')
 settings = require('settings-sharelatex')
 fs = require('fs')


fix combined fleets' fp

fix combined fleets' fp

--- views/henseiItem.cjsx
+++ views/henseiItem.cjsx
@@ -157,8 +157,9 @@
           break if !fleet[0]?
           if @props.deckItem.details[index].length > 3
             totalLv = @props.deckItem.details[index][0]
-            fpTotal = @props.deckItem.details[index][2]
-            fpBasic = fpAlv = null
+            fpBasic = @props.deckItem.details[index][1]
+            fpAlv = @props.deckItem.details[index][2]
+            fpTotal = fpBasic + fpAlv
             los = @props.deckItem.details[index][3]
             losA = @props.deckItem.details[index][4]
           else


import plugin-translator

import plugin-translator

--- views/henseiItem.cjsx
+++ views/henseiItem.cjsx
@@ -6,6 +6,10 @@
 i18n = require '../node_modules/i18n'
 {__} = i18n

+try
+  Translator = require 'poi-plugin-translator'
+catch err
+  console.log err

 # [shipId, [lv, cond], [slotId], [slotLv], [slotALv]]
 # {version: 3, f1: {s1: {id: '100', lv: 40, luck: -1, items:{i1:{id:1, rf: 4, rp:},...,ix:{id:200}}}, s2:{}...},...}


support changing properties in GraphComponent

--- app/graphing.coffee
+++ app/graphing.coffee
@@ -175,14 +175,18 @@
     displayName: 'GraphComponent'
     render: ->
       React.DOM.div {className: 'graph'}
+    componentWillReceiveProps: (nextProps) ->
+      @state.unsubscribe()
+      @subscribe(nextProps.model, @state.graph)
     componentDidMount: ->
       node = @getDOMNode()
       graph = GraphDrawing.create(node)
-      # FIXME #175 props can change
-      unsubscribe = @props.model.onValue ({data, params}) =>
+      @subscribe(@props.model, graph)
+      @setState {graph}
+    subscribe: (model, graph) ->
+      @setState unsubscribe: model.onValue ({data, params}) =>
         return unless data?
         graph.draw(data, params)
-      @setState {graph, unsubscribe}
     componentWillUnmount: ->
       if @state
         @state.graph.destroy()


:lipstick:

:lipstick:

--- spec/editor-component-spec.coffee
+++ spec/editor-component-spec.coffee
@@ -1075,7 +1075,7 @@
       expect(inputNode.offsetTop).toBe 0
       expect(inputNode.offsetLeft).toBe 0

-  describe "mouse interactions on the scrollView", ->
+  describe "mouse interactions on the lines", ->
     linesNode = null

     beforeEach ->


link urls

link urls

--- models/sponsor.coffee
+++ models/sponsor.coffee
@@ -363,9 +363,10 @@
     simple, low flat fees with no hidden fees or account minimums. A pioneer in
     integrating new social media as part of its innovative online trading
     platform, TradeKing recently launched a trading and market data API
-    available at developers.tradeking.com.
+    available at [developers.tradeking.com][2].

     [1]: http://www.tradeking.com
+    [2]: http://developers.tradeking.com
     '''
 ,
   name:  'Tropo'


removed console log on pages response

removed console log on pages response

--- routes/pages.coffee
+++ routes/pages.coffee
@@ -43,7 +43,6 @@
   catch err
     lookup["slug"] = id

-  console.log "Retrieving page: " + id
   db.collection "pages", (err, collection) ->
     collection.findOne lookup, (err, item) ->
       res.send error: "A DB error has occurred"  if err


Add Mongolian language

Add Mongolian language

--- app/locale/locale.coffee
+++ app/locale/locale.coffee
@@ -46,6 +46,7 @@
   'mi': { nativeDescription: 'te reo Māori', englishDescription: 'Māori' }
   'mk-MK': { nativeDescription: 'Македонски', englishDescription: 'Macedonian' }
   'hi': { nativeDescription: 'मानक हिन्दी', englishDescription: 'Hindi' }
+  'mn': { nativeDescription: 'Монгол хэл', englishDescription: 'Mongolian' }
   'ms': { nativeDescription: 'Bahasa Melayu', englishDescription: 'Bahasa Malaysia' }
   'my': { nativeDescription: 'မြန်မာစကား', englishDescription: 'Myanmar language' }
   'nl': { nativeDescription: 'Nederlands', englishDescription: 'Dutch' }


Runs isort synchronously to avoid race conditions.

--- lib/atom-isort.coffee
+++ lib/atom-isort.coffee
@@ -63,18 +63,10 @@
     options = {cwd: @getFileDir()}

     process = require 'child_process'
-
-    proc = process.spawn isortPath, params, options
-    output = []
-    proc.stdout.setEncoding 'utf8'
-    proc.stdout.on 'data', (chunk) ->
-      output.push chunk
-    proc.stdout.on 'end', (chunk) ->
-      output.join()
-    proc.on 'exit', (exit_code, signal) =>
-      if exit_code == 127
-        @updateStatusbarText '?', false
-      else if exit_code != 0
-        @updateStatusbarText 'x', false
-      else
-        @updateStatusbarText '√', true
+    exit_code = process.spawnSync(isortPath, params, options).status
+    if exit_code == 127
+      @updateStatusbarText '?', false
+    else if exit_code != 0
+      @updateStatusbarText 'x', false
+    else
+      @updateStatusbarText '√', true


Fix a minor file cound bug

Fix a minor file cound bug

--- app/mixins/socket.coffee
+++ app/mixins/socket.coffee
@@ -33,8 +33,6 @@
     file_new: (data)->
       Notify.info "New file added"
       project = @store.push "project", @store.normalize "project", data.project
-      fileCount = project.get "fileCount"
-      project.set "fileCount", fileCount + 1
       file = @store.push "file", @store.normalize "file", data.file
       for analysis in data.analyses
         @store.push "analysis", @store.normalize "analysis", analysis


Calculate additional includes after you come back from the server to get a true count of how many things that you actually need to go back to the server for

--- vendor/assets/javascripts/brainstem/loaders/abstract-loader.coffee
+++ vendor/assets/javascripts/brainstem/loaders/abstract-loader.coffee
@@ -9,7 +9,6 @@

   setup: (loadOptions) ->
     @_parseLoadOptions(loadOptions)
-    @_calculateAdditionalIncludes()
     @_createObjectReferences()
     @_interceptOldSuccess()

@@ -42,14 +41,6 @@
     @loadOptions.cacheKey = [@loadOptions.order || "updated_at:desc", filterKeys, @loadOptions.page, @loadOptions.perPage, @loadOptions.limit, @loadOptions.offset].join('|')

     @cachedCollection = @storageManager.storage @_getCollectionName()
-
-  _calculateAdditionalIncludes: ->
-    @additionalIncludesCount = 0
-    @completedIncludesCount = 0
-
-    if @loadOptions.include
-      for elem in @loadOptions.include when _.values(elem)[0].length
-        @additionalIncludesCount += 1

   _createObjectReferences: ->
     throw "Implement in your subclass"
@@ -115,10 +106,26 @@
   _updateStorageManagerFromResponse: ->
     throw "Implement in your subclass"

+  _calculateAdditionalIncludes: ->
+    @completedIncludesCount = 0
+    @additionalIncludes = []
+
+    for hash in @loadOptions.include
+      associationName = _.keys(hash)[0]
+      associationIds = @_getIdsForAssociation(associationName)
+      associationInclude = hash[associationName]
+
+      if associationIds.length && associationInclude.length
+        @additionalIncludes.push
+          name: associationName
+          ids: associationIds
+          include: associationInclude
+
   _onLoadSuccess: (data) ->
     @_updateObjects(@internalObject, data)
+    @_calculateAdditionalIncludes()

-    if @additionalIncludesCount
+    if @additionalIncludes.length
       @_loadAdditionalIncludes()
     else
       @loadOptions.success()
@@ -127,28 +134,21 @@
     throw "Implement in your subclass"

   _loadAdditionalIncludes: ->
-    for hash in @loadOptions.include
-      associationName = _.keys(hash)[0]
-      associationIds = @_getIdsForAssociation(associationName)
-      nextLevelInclude = hash[associationName]
+    for association in @additionalIncludes
+      collectionName = @_getModel().associationDetails(association.name).collectionName

-      if !associationIds.length
-        @_onAdditionalIncludeLoadSuccess()
-
-      else if nextLevelInclude.length
-        collectionName = @_getModel().associationDetails(associationName).collectionName
-        loadOptions =
-          only: associationIds
-          include: nextLevelInclude
-          error: @loadOptions.error
-          success: @_onAdditionalIncludeLoadSuccess
+      loadOptions =
+        only: association.ids
+        include: association.include
+        error: @loadOptions.error
+        success: @_onAdditionalIncludeLoadSuccess

-        @storageManager.loadCollection(collectionName, loadOptions)
+      @storageManager.loadCollection(collectionName, loadOptions)

   _onAdditionalIncludeLoadSuccess: =>
     @completedIncludesCount += 1

-    if @completedIncludesCount == @additionalIncludesCount
+    if @completedIncludesCount == @additionalIncludes.length
       @loadOptions.success()

   _getModel: ->


going deeper in coffee script =)

going deeper in coffee script =)

--- vendor/assets/javascripts/rails-google-maps/autocomplete.js.coffee
+++ vendor/assets/javascripts/rails-google-maps/autocomplete.js.coffee
@@ -1,12 +1,10 @@
 root = exports ? this

 class root.Autocomplete
-  source: ()->
+  source: ()=>
     []
-  select: ()->
-    ()->
-  change: ()->
-    ()->
+  select: ()=>
+  change: ()=>
   minChars: 2

   constructor: (@selector)->
@@ -14,9 +12,9 @@

   apply: ()->
     $(@selector).autocomplete
-      source: @source()
-      select: @select()
-      change: @change()
+      source: @source
+      select: @select
+      change: @change
     this.afterApply()

   afterApply: ()->
@@ -33,17 +31,15 @@
     @gmap.onSucceed.push (address)=>
       $(@selector).val address

-  source: ()->
-    (request, response) =>
-      @gmap.searchGeocodes request.term, (results)->
-        response $.map results, (item) ->
-          label: item.formatted_address
-          value: item.formatted_address
-          geocode: item
+  source: (request, response) =>
+    @gmap.searchGeocodes request.term, (results)->
+      response $.map results, (item) ->
+        label: item.formatted_address
+        value: item.formatted_address
+        geocode: item

-  select: ()->
-    (event, ui) =>
-      @gmap.update ui.item.geocode
+  select: (event, ui) =>
+    @gmap.update ui.item.geocode

   afterApply: ()->
     @syncWithMap()


Embedded source maps with local source files

--- src/tintan/compile.coffee
+++ src/tintan/compile.coffee
@@ -1,6 +1,7 @@
 require 'colors'
 fs     = require 'fs'
 path   = require 'path'
+btoa   = require 'btoa'
 coffee = require 'coffee-script'
 spawn  = require('child_process').spawn
 touch  = require 'touch'
@@ -83,17 +84,15 @@
         compileOpts =
           sourceMap: true
           filename: source
-          sourceFiles: [@options.src + '/' + sourceFile]
-          generatedFile: @options.target + '/' + sourceFile.replace @options.ext, '.js'
+          sourceFiles: ['file://' + process.cwd() + '/' + @options.src + source.split(@options.src)[-1..][0]]
+          generatedFile: @options.target + target.split(@options.target)[-1..][0]

         jsm = coffee.compile c, compileOpts
         j = jsm.js
         sm = jsm.v3SourceMap

-        mapFile = sourceFile.replace @options.ext, '.map'
-        mapDir = path.dirname target.replace @options.target, 'build/map/' + @options.target
-        jake.file.mkdirP mapDir
-        fs.writeFileSync "#{mapDir}/#{mapFile}", sm, 'utf-8'
+        sf = @options.src + source.split(@options.src)[-1..][0]
+        j = "#{j}\n//# sourceMappingURL=data:application/json;base64,#{btoa unescape encodeURIComponent sm}\n//# sourceURL=#{sf}"

       else
         j = coffee.compile c


Fix console errors [#157200617]

Fix console errors
[#157200617]


Allow <TextBlock> to work client-side (used by preview feature).

--- entry/TextBlock.cjsx
+++ entry/TextBlock.cjsx
@@ -50,7 +50,9 @@
                 unless anno.url
                     return
                 attrs.href = anno.url
-                unless @props.plain
+                # global.config.HOST is used server-side, window.location.hostname is used client-side.
+                _hostname = global?.config?.HOST or window?.location.hostname
+                if _hostname and not @props.plain
                     _parsed = url.parse(anno.url)
                     if _parsed.host and _parsed.host isnt global.config.HOST
                         attrs['data-external'] = true


Social: add a new function for fetching profile feed of a user

--- client/Main/socialapicontroller.coffee
+++ client/Main/socialapicontroller.coffee
@@ -175,3 +175,5 @@
       channelApiChannelsResFunc 'fetchFollowedChannels', args...
     searchTopics         : (args...)->
       channelApiChannelsResFunc 'searchTopics', args...
+    fetchProfileFeed     : (args...)->
+      channelApiActivitiesResFunc 'fetchProfileFeed', args...


Implement new attributeChanged event from oskite, use it as file changes

--- client/app/MainApp/fs/fswatcher.coffee
+++ client/app/MainApp/fs/fswatcher.coffee
@@ -27,13 +27,16 @@
     vmController = KD.getSingleton 'vmController'
     @vmName or= (@getOption 'vmName') or vmController.defaultVmName

+    unless @vmName
+      return callback? {message: "No VM provided!"}
+
     FSWatcher.stopWatching @getFullPath()

     vmController.run
       method     : 'fs.readDirectory'
       vmName     : @vmName
       withArgs   :
-        onChange : (change)=> @fileChanged @path, change
+        onChange : (change)=> @changeHappened @path, change
         path     : FSHelper.plainPath @path
         watchSubdirectories : @getOption 'recursive'
     , (err, response)=>
@@ -54,7 +57,10 @@
   fileRemoved:(change)->
     # warn "File removed:", change.file.fullPath

-  fileChanged:(path, change)->
+  fileChanged:(change)->
+    # warn "File updated:", change.file.fullPath
+
+  changeHappened:(path, change)->

     if @getOption 'ignoreTempChanges'
       return  if /^\.|\~$/.test change.file.name
@@ -65,6 +71,8 @@
         else @fileAdded change
       when 'removed'
         @fileRemoved change
+      when 'attributesChanged'
+        @fileChanged change

     # log "Change happened on #{@path}:", change


Fix /pbv command link

Fix /pbv command link

--- client/app/js/concerns/commands.coffee
+++ client/app/js/concerns/commands.coffee
@@ -114,9 +114,9 @@
         messages.push("#{linkToDex(dexEntry, icon + formattedName)}:
           #{formeData.pokeBattleValue}")
   if messages.length > 10
-    messages = _.sample(messages, 10)
-    messages.push("<a href='//www.pokebattle.com/dex/pokemon/?pbv=<#{pbv + 1}'
-      target='_blank'>See more Pokemon »")
+    messages = _.sample(messages, 10)
+    messages.push(linkToDex("pokemon/?pbv=<#{pbv + 1}",
+      "See more Pokemon »"))
   if messages.length > 0
     plural = if messages.length == 1 then "is" else "are"
     messages.unshift("There #{plural} #{counter} Pokemon with a PBV of


Account Settings: Credentials: Change AWS's color

--- client/app/lib/providers/config.coffee
+++ client/app/lib/providers/config.coffee
@@ -24,7 +24,7 @@
     name                   : "Amazon Web Services"
     link                   : "https://aws.amazon.com"
     title                  : "AWS"
-    color                  : "#b0f710"
+    color                  : "#F9A900"
     description            : "Amazon Web Services"
     advancedFields         : [
                               'subnet', 'sg', 'vpc',


Fix paginate when switching account

Fix paginate when switching account

--- client/app/stores/message_store.coffee
+++ client/app/stores/message_store.coffee
@@ -166,6 +166,11 @@

         handle ActionTypes.MESSAGE_FLAG, (message) ->
             onReceiveRawMessage message
+
+        handle ActionTypes.SELECT_ACCOUNT, (value) ->
+            _params.after     = '-'
+            _params.before    = '-'
+            _params.pageAfter = '-'

         handle ActionTypes.LIST_FILTER, (filter) ->
             _messages  = _messages.clear()


Fix FieldChart issue which failed to render chart on closed view


included in the other branch - remove it

--- client/landing/includes.coffee
+++ client/landing/includes.coffee
@@ -243,7 +243,6 @@
   "app/MainApp/sidebar/sidebarresizehandle.coffee",
   "app/MainApp/sidebar/virtualizationcontrols.coffee",
   "app/MainApp/sidebar/footermenuitem.coffee",
-  "app/MainApp/sidebar/findersettingsbuttonview.coffee",
   "app/MainApp/sidebar/modals/introductiontooltip/introductionitem.coffee",
   "app/MainApp/sidebar/modals/introductiontooltip/introductionchilditem.coffee",
   "app/MainApp/sidebar/modals/introductiontooltip/introductionadminform.coffee",


Fix TinyMCE media modal menu refresh on folder creation.

--- MediaAdminBundle/Resources/public/coffee/view/MediaModalView.coffee
+++ MediaAdminBundle/Resources/public/coffee/view/MediaModalView.coffee
@@ -25,12 +25,8 @@

   render: (options) ->
     @setElement @renderTemplate('OpenOrchestraMediaAdminBundle:BackOffice:Underscore/mediaModalView', @options)
-    opts =
-      accordion: true
-      speed: $.menu_speed
-      closedSign: ""
-      openedSign: ""
-    $(@el).jarvismenu opts
+
+    @initMenu()

     if currentModal != null
       $('.modal-dialog', currentModal).replaceWith $('.modal-dialog', @$el)
@@ -42,6 +38,16 @@
         currentModal = null
         this.remove()
         return
+
+  initMenu: (activeNode) ->
+    @updateNavigation(activeNode) if activeNode?
+
+    opts =
+      accordion: true
+      speed: $.menu_speed
+      closedSign: ""
+      openedSign: ""
+    $(@el).jarvismenu opts

   closeModal: ->
     if currentModal
@@ -63,8 +69,10 @@
     $.ajax
       url: @options.url
       method: 'GET'
+      context: @
       success: (response) ->
         $('.modal-body-menu', currentModal).html response
+        @initMenu($('#media-modal-' + $('#oo_folder_id').val()))
     return

   openFormFolder: (event) ->


Handle back path for login page

Handle back path for login page

--- app/assets/javascripts/angular/controllers/RegistryLoginCtrl.coffee
+++ app/assets/javascripts/angular/controllers/RegistryLoginCtrl.coffee
@@ -14,7 +14,7 @@

     $scope.login = () ->
       registryloginService.setCredentials($scope.username, $scope.password)
-      back = $rootScope.loginback
+      back = $rootScope.loginback || '/'
       $rootScope.loginback = undefined
       $location.path(back)


refine factory

refine factory

--- ngtuvok/src/components/backend/data.factory.coffee
+++ ngtuvok/src/components/backend/data.factory.coffee
@@ -1,3 +1,3 @@
 angular.module 'ngtuvok'
   .factory "DataFactory", ($resource) ->
-    $resource '/api/collections/posts'+    $resource '/api/collections/posts/:id'


Only indicate JSON parse errors when they actually happen.

--- lib/adapters/redis/key_value.coffee
+++ lib/adapters/redis/key_value.coffee
@@ -3,11 +3,12 @@
 module.exports = class RedisKeyValue extends RedisAdapter
   get: (key, callback) ->
     @redis.get key, (err, val) ->
-      try
-        callback err, (JSON.parse(val) if val)
+      parsed = try
+        JSON.parse val
       catch e
-        console.log 'failed trying to parse key', key, ':', val
+        console.log 'failed trying to parse key', key, ':', val, 'got error', e # XXX
         throw e
+      callback err, parsed
   get_all: (keys, callback) ->
     @redis.mget keys, (err, arr) ->
       return callback(err) if err


修复 自定义控件template.attributes为空导致的bug

修复 自定义控件template.attributes为空导致的bug

--- src/widget/support.coffee
+++ src/widget/support.coffee
@@ -1,275 +1,275 @@
 $.xCreate.templateProcessors.push (template) ->
-	if template instanceof cola.Widget
-		dom = template.getDom()
-		dom.setAttribute(cola.constants.IGNORE_DIRECTIVE, "")
-		return dom
-	return
+    if template instanceof cola.Widget
+        dom = template.getDom()
+        dom.setAttribute(cola.constants.IGNORE_DIRECTIVE, "")
+        return dom
+    return

 $.xCreate.attributeProcessor["c-widget"] = ($dom, attrName, attrValue, context) ->
-	return unless attrValue
-	if typeof attrValue == "string"
-		$dom.attr(attrName, attrValue)
-	else if context
-		configKey = cola.uniqueId()
-		$dom.attr("c-widget-config", configKey)
-		widgetConfigs = context.widgetConfigs
-		if !widgetConfigs
-			context.widgetConfigs = widgetConfigs = {}
-		widgetConfigs[configKey] = attrValue
-	return
+    return unless attrValue
+    if typeof attrValue == "string"
+        $dom.attr(attrName, attrValue)
+    else if context
+        configKey = cola.uniqueId()
+        $dom.attr("c-widget-config", configKey)
+        widgetConfigs = context.widgetConfigs
+        if !widgetConfigs
+            context.widgetConfigs = widgetConfigs = {}
+        widgetConfigs[configKey] = attrValue
+    return

 cola.xRender.nodeProcessors.push (node, context) ->
-	if node instanceof cola.Widget
-		widget = node
-	else if node.$type
-		widget = cola.widget(node, context.namespace)
-	if widget
-		dom = widget.getDom()
-		dom.setAttribute(cola.constants.IGNORE_DIRECTIVE, "")
-	return dom
+    if node instanceof cola.Widget
+        widget = node
+    else if node.$type
+        widget = cola.widget(node, context.namespace)
+    if widget
+        dom = widget.getDom()
+        dom.setAttribute(cola.constants.IGNORE_DIRECTIVE, "")
+    return dom

 cola.Model::widgetConfig = (id, config) ->
-	if arguments.length == 1
-		if typeof id == "string"
-			return @_widgetConfig?[id]
-		else
-			config = id
-			@widgetConfig(k, v) for k, v of config
-	else
-		@_widgetConfig ?= {}
-		@_widgetConfig[id] = config
-	return
+    if arguments.length == 1
+        if typeof id == "string"
+            return @_widgetConfig?[id]
+        else
+            config = id
+            @widgetConfig(k, v) for k, v of config
+    else
+        @_widgetConfig ?= {}
+        @_widgetConfig[id] = config
+    return

 ALIAS_REGEXP = new RegExp("\\$default", "g")

 _findWidgetConfig = (scope, name) ->
-	while scope
-		widgetConfig = scope._widgetConfig?[name]
-		if widgetConfig then break
-		scope = scope.parent
-	return widgetConfig
+    while scope
+        widgetConfig = scope._widgetConfig?[name]
+        if widgetConfig then break
+        scope = scope.parent
+    return widgetConfig

 _compileWidgetDom = (dom, widgetType) ->
-	if not widgetType.attributes._inited or not widgetType.events._inited
-		cola.preprocessClass(widgetType)
-
-	config =
-		$constr: widgetType
-
-	removeAttrs = null
-	for attr in dom.attributes
-		attrName = attr.name
-		if attrName.indexOf("c-") is 0
-			prop = attrName.slice(2)
-			if widgetType.attributes.$has(prop) and prop isnt "class"
-				if prop is "bind"
-					config[prop] = attr.value
-				else
-					config[prop] = cola._compileExpression(attr.value)
-
-				removeAttrs ?= []
-				removeAttrs.push(attrName)
-			else
-				isEvent = widgetType.events.$has(prop)
-				if not isEvent and prop.indexOf("on") is 0
-					if widgetType.events.$has(prop.slice(2))
-						isEvent = true
-						prop = prop.slice(2)
-
-				if isEvent
-					config[prop] = cola._compileExpression(attr.value)
-					removeAttrs ?= []
-					removeAttrs.push(attrName)
-		else
-			prop = attrName
-			if widgetType.attributes.$has(prop)
-				config[prop] = attr.value
-			else
-				isEvent = widgetType.events.$has(prop)
-				if not isEvent and prop.indexOf("on") is 0
-					if widgetType.events.$has(prop.slice(2))
-						isEvent = true
-						prop = prop.slice(2)
-
-						removeAttrs ?= []
-						removeAttrs.push(attrName)
-
-				if isEvent
-					config[prop] = attr.value
-
-	if removeAttrs
-		dom.removeAttribute(attr) for attr in removeAttrs
-	return config
+    if not widgetType.attributes._inited or not widgetType.events._inited
+        cola.preprocessClass(widgetType)
+
+    config =
+        $constr: widgetType
+
+    removeAttrs = null
+    for attr in dom.attributes
+        attrName = attr.name
+        if attrName.indexOf("c-") is 0
+            prop = attrName.slice(2)
+            if widgetType.attributes.$has(prop) and prop isnt "class"
+                if prop is "bind"
+                    config[prop] = attr.value
+                else
+                    config[prop] = cola._compileExpression(attr.value)
+
+                removeAttrs ?= []
+                removeAttrs.push(attrName)
+            else
+                isEvent = widgetType.events.$has(prop)
+                if not isEvent and prop.indexOf("on") is 0
+                    if widgetType.events.$has(prop.slice(2))
+                        isEvent = true
+                        prop = prop.slice(2)
+
+                if isEvent
+                    config[prop] = cola._compileExpression(attr.value)
+                    removeAttrs ?= []
+                    removeAttrs.push(attrName)
+        else
+            prop = attrName
+            if widgetType.attributes.$has(prop)
+                config[prop] = attr.value
+            else
+                isEvent = widgetType.events.$has(prop)
+                if not isEvent and prop.indexOf("on") is 0
+                    if widgetType.events.$has(prop.slice(2))
+                        isEvent = true
+                        prop = prop.slice(2)
+
+                        removeAttrs ?= []
+                        removeAttrs.push(attrName)
+
+                if isEvent
+                    config[prop] = attr.value
+
+    if removeAttrs
+        dom.removeAttribute(attr) for attr in removeAttrs
+    return config

 _compileWidgetAttribute = (scope, dom, context) ->
-	widgetConfigStr = dom.getAttribute("c-widget")
-	if widgetConfigStr
-		dom.removeAttribute("c-widget")
-		if context.defaultPath
-			widgetConfigStr = widgetConfigStr.replace(ALIAS_REGEXP, context.defaultPath)
-
-		config = cola.util.parseStyleLikeString(widgetConfigStr, "$type")
-		if config
-			importNames = null
-			for p, v of config
-				importName = null
-				if p.charCodeAt(0) == 35
-					importName = p.substring(1)
-				else if p == "$type" and typeof v == "string" and v.charCodeAt(0) == 35 # `#`
-					importName = v.substring(1)
-				if importName
-					delete config[p]
-					importNames ?= []
-					importNames.push(importName)
-
-			if importNames
-				for importName in importNames
-					importConfig = _findWidgetConfig(scope, importName)
-					if importConfig
-						config[ip] = iv for ip, iv of importConfig
-	return config
+    widgetConfigStr = dom.getAttribute("c-widget")
+    if widgetConfigStr
+        dom.removeAttribute("c-widget")
+        if context.defaultPath
+            widgetConfigStr = widgetConfigStr.replace(ALIAS_REGEXP, context.defaultPath)
+
+        config = cola.util.parseStyleLikeString(widgetConfigStr, "$type")
+        if config
+            importNames = null
+            for p, v of config
+                importName = null
+                if p.charCodeAt(0) == 35
+                    importName = p.substring(1)
+                else if p == "$type" and typeof v == "string" and v.charCodeAt(0) == 35 # `#`
+                    importName = v.substring(1)
+                if importName
+                    delete config[p]
+                    importNames ?= []
+                    importNames.push(importName)
+
+            if importNames
+                for importName in importNames
+                    importConfig = _findWidgetConfig(scope, importName)
+                    if importConfig
+                        config[ip] = iv for ip, iv of importConfig
+    return config

 cola._userDomCompiler.$.push((scope, dom, attr, context) ->
-	return null if cola.util.userData(dom, cola.constants.DOM_ELEMENT_KEY)
-	return null unless dom.nodeType is 1
-
-	if dom.id
-		jsonConfig = _findWidgetConfig(scope, dom.id)
-
-	parentWidget = context.parentWidget
-	tagName = dom.tagName
-
-	configKey = dom.getAttribute("c-widget-config")
-	if configKey
-		dom.removeAttribute("c-widget-config")
-		config = context.widgetConfigs?[configKey]
-	else
-		config = _compileWidgetAttribute(scope, dom, context)
-		if not config
-			widgetType = parentWidget?.childTagNames?[tagName]
-			widgetType ?= WIDGET_TAGS_REGISTRY[tagName]
-			if widgetType
-				config = _compileWidgetDom(dom, widgetType)
-	return null unless config or jsonConfig
-
-	config ?= {}
-	if jsonConfig
-		for k, v of jsonConfig
-			if not config.hasOwnProperty(k) then config[k] = v
-
-	if typeof config is "string"
-		config = {
-			$type: config
-		}
-
-	if config.$constr instanceof Function
-		constr = config.$constr
-	else
-		constr = cola.resolveType((parentWidget?.CHILDREN_TYPE_NAMESPACE or "widget"), config, cola.Widget)
-	config.$constr = context.parentWidget = constr
-
-	if cola.util.isCompatibleType(cola.AbstractLayer, constr) and config.lazyRender
-		cola.util.userData(dom, cola.constants.DOM_SKIP_CHILDREN, true)
-
-	return (scope, dom) ->
-		context.parentWidget = parentWidget
-		config.dom = dom
-		oldScope = cola.currentScope
-		cola.currentScope = scope
-		try
-			widget = cola.widget(config)
-			return widget
-		finally
-			cola.currentScope = oldScope
+    return null if cola.util.userData(dom, cola.constants.DOM_ELEMENT_KEY)
+    return null unless dom.nodeType is 1
+
+    if dom.id
+        jsonConfig = _findWidgetConfig(scope, dom.id)
+
+    parentWidget = context.parentWidget
+    tagName = dom.tagName
+
+    configKey = dom.getAttribute("c-widget-config")
+    if configKey
+        dom.removeAttribute("c-widget-config")
+        config = context.widgetConfigs?[configKey]
+    else
+        config = _compileWidgetAttribute(scope, dom, context)
+        if not config
+            widgetType = parentWidget?.childTagNames?[tagName]
+            widgetType ?= WIDGET_TAGS_REGISTRY[tagName]
+            if widgetType
+                config = _compileWidgetDom(dom, widgetType)
+    return null unless config or jsonConfig
+
+    config ?= {}
+    if jsonConfig
+        for k, v of jsonConfig
+            if not config.hasOwnProperty(k) then config[k] = v
+
+    if typeof config is "string"
+        config = {
+            $type: config
+        }
+
+    if config.$constr instanceof Function
+        constr = config.$constr
+    else
+        constr = cola.resolveType((parentWidget?.CHILDREN_TYPE_NAMESPACE or "widget"), config, cola.Widget)
+    config.$constr = context.parentWidget = constr
+
+    if cola.util.isCompatibleType(cola.AbstractLayer, constr) and config.lazyRender
+        cola.util.userData(dom, cola.constants.DOM_SKIP_CHILDREN, true)
+
+    return (scope, dom) ->
+        context.parentWidget = parentWidget
+        config.dom = dom
+        oldScope = cola.currentScope
+        cola.currentScope = scope
+        try
+            widget = cola.widget(config)
+            return widget
+        finally
+            cola.currentScope = oldScope
 )

 cola.registerTypeResolver "widget", (config) ->
-	return unless config
-	if config.$constructor and cola.util.isSuperClass(cola.Widget, config.$constructor)
-		return config.$constructor
-	if config.$type
-		return cola[cola.util.capitalize(config.$type)]
-	return
+    return unless config
+    if config.$constructor and cola.util.isSuperClass(cola.Widget, config.$constructor)
+        return config.$constructor
+    if config.$type
+        return cola[cola.util.capitalize(config.$type)]
+    return

 cola.registerType("widget", "_default", cola.Widget)

 cola.widget = (config, namespace, model) ->
-	return null unless config
-	if typeof config == "string"
-		ele = window[config]
-		return null unless ele
-		if ele.nodeType
-			widget = cola.util.userData(ele, cola.constants.DOM_ELEMENT_KEY)
-			if model and widget._scope isnt model
-				widget = null
-			return if widget instanceof cola.Widget then widget else null
-		else
-			group = []
-			for e in ele
-				widget = cola.util.userData(e, cola.constants.DOM_ELEMENT_KEY)
-				if widget instanceof cola.Widget and (not model or widget._scope is model)
-					group.push(widget)
-			if not group.length
-				return null
-			else if group.length is 1
-				return group[0]
-			else
-				return cola.Element.createGroup(group)
-	else
-		if config instanceof Array
-			group = []
-			for c in config
-				group.push(cola.widget(c, namespace, model))
-			return cola.Element.createGroup(group)
-		else if config.nodeType == 1
-			widget = cola.util.userData(config, cola.constants.DOM_ELEMENT_KEY)
-			if model and widget._scope isnt model
-				widget = null
-			return if widget instanceof cola.Widget then widget else null
-		else
-			constr = config.$constr or cola.resolveType(namespace or "widget", config, cola.Widget)
-			if model and not config.scope
-				config.scope = model
-			return new constr(config)
+    return null unless config
+    if typeof config == "string"
+        ele = window[config]
+        return null unless ele
+        if ele.nodeType
+            widget = cola.util.userData(ele, cola.constants.DOM_ELEMENT_KEY)
+            if model and widget._scope isnt model
+                widget = null
+            return if widget instanceof cola.Widget then widget else null
+        else
+            group = []
+            for e in ele
+                widget = cola.util.userData(e, cola.constants.DOM_ELEMENT_KEY)
+                if widget instanceof cola.Widget and (not model or widget._scope is model)
+                    group.push(widget)
+            if not group.length
+                return null
+            else if group.length is 1
+                return group[0]
+            else
+                return cola.Element.createGroup(group)
+    else
+        if config instanceof Array
+            group = []
+            for c in config
+                group.push(cola.widget(c, namespace, model))
+            return cola.Element.createGroup(group)
+        else if config.nodeType == 1
+            widget = cola.util.userData(config, cola.constants.DOM_ELEMENT_KEY)
+            if model and widget._scope isnt model
+                widget = null
+            return if widget instanceof cola.Widget then widget else null
+        else
+            constr = config.$constr or cola.resolveType(namespace or "widget", config, cola.Widget)
+            if model and not config.scope
+                config.scope = model
+            return new constr(config)

 cola.findWidget = (dom, type) ->
-	if type and typeof type == "string"
-		typeName = type
-		type = WIDGET_TAGS_REGISTRY[typeName]
-		type = cola.resolveType("widget", { $type: typeName }) unless type
-		return null unless type
-
-	if dom instanceof cola.Widget
-		dom = dom.getDom()
-
-	find = (win, dom, type) ->
-		parentDom = dom.parentNode
-		while parentDom
-			dom = parentDom
-			widget = cola.util.userData(dom, cola.constants.DOM_ELEMENT_KEY)
-			if widget
-				if not type or widget instanceof type
-					return widget
-			parentDom = dom.parentNode
-
-		if win.parent
-			try
-				parentFrames = win.parent.jQuery("iframe,frame")
-			catch
-				# do nothing
-
-			if parentFrames
-				frame = null
-				parentFrames.each () ->
-					if @contentWindow is win
-						frame = @
-						return false
-
-				if frame
-					widget = find(win.parent, frame, type)
-		return widget
-
-	return find(window, dom, type)
+    if type and typeof type == "string"
+        typeName = type
+        type = WIDGET_TAGS_REGISTRY[typeName]
+        type = cola.resolveType("widget", {$type: typeName}) unless type
+        return null unless type
+
+    if dom instanceof cola.Widget
+        dom = dom.getDom()
+
+    find = (win, dom, type) ->
+        parentDom = dom.parentNode
+        while parentDom
+            dom = parentDom
+            widget = cola.util.userData(dom, cola.constants.DOM_ELEMENT_KEY)
+            if widget
+                if not type or widget instanceof type
+                    return widget
+            parentDom = dom.parentNode
+
+        if win.parent
+            try
+                parentFrames = win.parent.jQuery("iframe,frame")
+            catch
+# do nothing
+
+            if parentFrames
+                frame = null
+                parentFrames.each () ->
+                    if @contentWindow is win
+                        frame = @
+                        return false
+
+                if frame
+                    widget = find(win.parent, frame, type)
+        return widget
+
+    return find(window, dom, type)

 cola.Model::widget = (config) -> cola.widget(config, null, @)

@@ -280,118 +280,119 @@
 WIDGET_TAGS_REGISTRY = {}

 _extendWidget = (superCls, definition) ->
-	cls = (config) ->
-		if not cls.attributes._inited or not cls.events._inited
-			cola.preprocessClass(cls)
-
-		if definition.create then @on("create", definition.create)
-		if definition.destroy then @on("destroy", definition.destroy)
-		if definition.initDom then @on("initDom", (self, arg) => @initDom(arg.dom))
-		if definition.refreshDom then @on("refreshDom", (self, arg) => @refreshDom(arg.dom))
-
-		@on("attributeChange", (self, arg) =>
-			attr = arg.attribute
-			@_widgetModel.data._onDataMessage(["@" + attr], cola.constants.MESSAGE_PROPERTY_CHANGE, {})
-			value = @_get(attr)
-			if value and (value instanceof cola.Entity or value instanceof cola.EntityList)
-				@_entityProps[attr] = value
-			else
-				delete @_entityProps[attr]
-			return
-		)
-
-		@_entityProps = {}
-		@_widgetModel = new cola.WidgetModel(@, config?.scope or cola.currentScope)
-		cls.__super__.constructor.call(@, config)
-		return
-
-	`extend(cls, superCls)`
-
-	cls.tagName = definition.tagName?.toUpperCase() or ""
-	cls.parentWidget = definition.parentWidget if definition.parentWidget
-
-	cls.attributes = definition.attributes or {}
-
-	cls.attributes.widgetModel =
-		readOnly: true
-		getter: () -> @_widgetModel
-
-	cls.attributes.template =
-		readOnlyAfterCreate: true
-
-	if definition.events then cls.events = definition.events
-
-	if definition.template
-		template = definition.template
-		if typeof template is "string" and template.match(/^\#[\w\-\$]*$/)
-			template = document.getElementById(template.substring(1))
-			if template
-				definition.template = template.innerHTML
-				$fly(template).remove()
-
-		cls.attributes.template =
-			defaultValue: definition.template
-
-	cls::_createDom = () ->
-		if @_template
-			dom = cola.xRender(@_template or {}, @_widgetModel)
-			@_domCreated = true
-			return dom
-		else
-			return superCls::_createDom.apply(@)
-
-	cls::_initDom = (dom) ->
-		superCls::_initDom.call(@, dom)
-		template = @_template
-		if template and not @_domCreated
-			templateDom = @xRender(template)
-			if templateDom?.nodeType is 11	# fragment
-				templateDom = templateDom.firstElementChild
-
-			if templateDom
-				for attr in templateDom.attributes
-					attrName = attr.name
-					if attrName is "class"
-						$fly(dom).addClass(attr.value)
-					else if attrName isnt "style"
-						dom.setAttribute(attrName, attr.value) if not dom.hasAttribute(attrName)
-
-				for cssName of templateDom.style
-					dom.style[cssName] = templateDom.style[cssName] if dom.style[cssName] is ""
-
-				while templateDom.firstChild
-					dom.appendChild(templateDom.firstChild)
-		return
-
-	cls::xRender = (template, context) -> cola.xRender(template, @_widgetModel, context)
-
-	for prop, def of definition
-		if definition.hasOwnProperty(prop) and typeof def is "function"
-			cls::[prop] = def
-
-	return cls
+    cls = (config) ->
+        if not cls.attributes._inited or not cls.events._inited
+            cola.preprocessClass(cls)
+
+        if definition.create then @on("create", definition.create)
+        if definition.destroy then @on("destroy", definition.destroy)
+        if definition.initDom then @on("initDom", (self, arg) => @initDom(arg.dom))
+        if definition.refreshDom then @on("refreshDom", (self, arg) => @refreshDom(arg.dom))
+
+        @on("attributeChange", (self, arg) =>
+            attr = arg.attribute
+            @_widgetModel.data._onDataMessage(["@" + attr], cola.constants.MESSAGE_PROPERTY_CHANGE, {})
+            value = @_get(attr)
+            if value and (value instanceof cola.Entity or value instanceof cola.EntityList)
+                @_entityProps[attr] = value
+            else
+                delete @_entityProps[attr]
+            return
+        )
+
+        @_entityProps = {}
+        @_widgetModel = new cola.WidgetModel(@, config?.scope or cola.currentScope)
+        cls.__super__.constructor.call(@, config)
+        return
+
+    `extend(cls, superCls)`
+
+    cls.tagName = definition.tagName?.toUpperCase() or ""
+    cls.parentWidget = definition.parentWidget if definition.parentWidget
+
+    cls.attributes = definition.attributes or {}
+
+    cls.attributes.widgetModel =
+        readOnly: true
+        getter: () -> @_widgetModel
+
+    cls.attributes.template =
+        readOnlyAfterCreate: true
+
+    if definition.events then cls.events = definition.events
+
+    if definition.template
+        template = definition.template
+        if typeof template is "string" and template.match(/^\#[\w\-\$]*$/)
+            template = document.getElementById(template.substring(1))
+            if template
+                definition.template = template.innerHTML
+                $fly(template).remove()
+
+        cls.attributes.template =
+            defaultValue: definition.template
+
+    cls::_createDom = () ->
+        if @_template
+            dom = cola.xRender(@_template or {}, @_widgetModel)
+            @_domCreated = true
+            return dom
+        else
+            return superCls::_createDom.apply(@)
+
+    cls::_initDom = (dom) ->
+        superCls::_initDom.call(@, dom)
+        template = @_template
+        if template and not @_domCreated
+            templateDom = @xRender(template)
+            if templateDom?.nodeType is 11    # fragment
+                templateDom = templateDom.firstElementChild
+
+            if templateDom
+                if templateDom.attributes
+                    for attr in templateDom.attributes
+                        attrName = attr.name
+                        if attrName is "class"
+                            $fly(dom).addClass(attr.value)
+                        else if attrName isnt "style"
+                            dom.setAttribute(attrName, attr.value) if not dom.hasAttribute(attrName)
+
+                for cssName of templateDom.style
+                    dom.style[cssName] = templateDom.style[cssName] if dom.style[cssName] is ""
+
+                while templateDom.firstChild
+                    dom.appendChild(templateDom.firstChild)
+        return
+
+    cls::xRender = (template, context) -> cola.xRender(template, @_widgetModel, context)
+
+    for prop, def of definition
+        if definition.hasOwnProperty(prop) and typeof def is "function"
+            cls::[prop] = def
+
+    return cls

 cola.defineWidget = (type, definition) ->
-	if not cola.util.isSuperClass(cola.Widget, type)
-		definition = type
-		type = cola.TemplateWidget
-
-	if definition
-		type = _extendWidget(type, definition)
-
-	tagName = type.tagName?.toUpperCase()
-	if tagName and type.parentWidget
-		childTagNames = type.parentWidget.childTagNames
-		if not childTagNames
-			type.parentWidget.childTagNames = childTagNames = {}
-		if childTagNames[tagName]
-			throw new cola.Exception("Tag name \"#{tagName}\" is already registered in \"#{type.parentWidget.tagName}\".")
-		childTagNames[tagName] = type
-	else if tagName
-		if WIDGET_TAGS_REGISTRY[tagName]
-			throw new cola.Exception("Tag name \"#{tagName}\" is already registered.")
-		WIDGET_TAGS_REGISTRY[tagName] = type
-	return type
+    if not cola.util.isSuperClass(cola.Widget, type)
+        definition = type
+        type = cola.TemplateWidget
+
+    if definition
+        type = _extendWidget(type, definition)
+
+    tagName = type.tagName?.toUpperCase()
+    if tagName and type.parentWidget
+        childTagNames = type.parentWidget.childTagNames
+        if not childTagNames
+            type.parentWidget.childTagNames = childTagNames = {}
+        if childTagNames[tagName]
+            throw new cola.Exception("Tag name \"#{tagName}\" is already registered in \"#{type.parentWidget.tagName}\".")
+        childTagNames[tagName] = type
+    else if tagName
+        if WIDGET_TAGS_REGISTRY[tagName]
+            throw new cola.Exception("Tag name \"#{tagName}\" is already registered.")
+        WIDGET_TAGS_REGISTRY[tagName] = type
+    return type

 cola.registerWidget = cola.defineWidget

@@ -402,277 +403,277 @@
 TEMP_TEMPLATE = null

 cola.TemplateSupport =
-	_templateSupport: true
-
-	destroy: () ->
-		if @_templates
-			delete @_templates[name] for name of @_templates
-		return
-
-	_parseTemplates: () ->
-		return unless @_dom
-		child = @_dom.firstChild
-		while child
-			if child.nodeName == "TEMPLATE"
-				@_regTemplate(child)
-			child = child.nextSibling
-		@_regDefaultTempaltes()
-		return
-
-	_trimTemplate: (dom) ->
-		child = dom.firstChild
-		while child
-			next = child.nextSibling
-			if child.nodeType == 3
-				if $.trim(child.nodeValue) == ""
-					dom.removeChild(child)
-			child = next
-		return
-
-	_regTemplate: (name, template) ->
-		if arguments.length == 1
-			template = name
-			if template.nodeType
-				name = template.getAttribute("name")
-			else
-				name = template.name
-		@_templates ?= {}
-		@_templates[name or "default"] = template
-		return
-
-	_regDefaultTempaltes: () ->
-		for name, template of @constructor.TEMPLATES
-			if @_templates?.hasOwnProperty(name) or !template
-				continue
-			@_regTemplate(name, template)
-		return
-
-	_getTemplate: (name = "default", defaultName) ->
-		return null unless @_templates
-		template = @_templates[name]
-		if !template and defaultName
-			name = defaultName
-			template = @_templates[name]
-
-		if template and !template._trimed
-			if template.nodeType
-				if template.nodeName == "TEMPLATE"
-					if !template.firstChild
-						html = template.innerHTML
-						if html
-							TEMP_TEMPLATE ?= document.createElement("div")
-							template = TEMP_TEMPLATE
-							template.innerHTML = html
-					@_trimTemplate(template)
-					if template.firstChild == template.lastChild
-						template = template.firstChild
-					else
-						templs = []
-						child = template.firstChild
-						while child
-							templs.push(child)
-							child = child.nextSibling
-						template = templs
-				@_templates[name] = template
-			else
-				@_doms ?= {}
-				template = $.xCreate(template, @_doms)
-				if @_doms.widgetConfigs
-					@_templateContext ?= {}
-					if @_templateContext.widgetConfigs
-						widgetConfigs = @_templateContext.widgetConfigs
-						for k, c of @_doms.widgetConfigs
-							widgetConfigs[k] = c
-					else
-						@_templateContext.widgetConfigs = @_doms.widgetConfigs
-				@_templates[name] = template
-			template._trimed = true
-
-		return template
-
-	_cloneTemplate: (template, supportMultiNodes) ->
-		if template instanceof Array
-			if supportMultiNodes and template.length > 1
-				fragment = document.createDocumentFragment()
-				fragment.appendChild(templ.cloneNode(true)) for templ in template
-				return fragment
-			else
-				return template[0].cloneNode(true)
-		else
-			return template.cloneNode(true)
+    _templateSupport: true
+
+    destroy: () ->
+        if @_templates
+            delete @_templates[name] for name of @_templates
+        return
+
+    _parseTemplates: () ->
+        return unless @_dom
+        child = @_dom.firstChild
+        while child
+            if child.nodeName == "TEMPLATE"
+                @_regTemplate(child)
+            child = child.nextSibling
+        @_regDefaultTempaltes()
+        return
+
+    _trimTemplate: (dom) ->
+        child = dom.firstChild
+        while child
+            next = child.nextSibling
+            if child.nodeType == 3
+                if $.trim(child.nodeValue) == ""
+                    dom.removeChild(child)
+            child = next
+        return
+
+    _regTemplate: (name, template) ->
+        if arguments.length == 1
+            template = name
+            if template.nodeType
+                name = template.getAttribute("name")
+            else
+                name = template.name
+        @_templates ?= {}
+        @_templates[name or "default"] = template
+        return
+
+    _regDefaultTempaltes: () ->
+        for name, template of @constructor.TEMPLATES
+            if @_templates?.hasOwnProperty(name) or !template
+                continue
+            @_regTemplate(name, template)
+        return
+
+    _getTemplate: (name = "default", defaultName) ->
+        return null unless @_templates
+        template = @_templates[name]
+        if !template and defaultName
+            name = defaultName
+            template = @_templates[name]
+
+        if template and !template._trimed
+            if template.nodeType
+                if template.nodeName == "TEMPLATE"
+                    if !template.firstChild
+                        html = template.innerHTML
+                        if html
+                            TEMP_TEMPLATE ?= document.createElement("div")
+                            template = TEMP_TEMPLATE
+                            template.innerHTML = html
+                    @_trimTemplate(template)
+                    if template.firstChild == template.lastChild
+                        template = template.firstChild
+                    else
+                        templs = []
+                        child = template.firstChild
+                        while child
+                            templs.push(child)
+                            child = child.nextSibling
+                        template = templs
+                @_templates[name] = template
+            else
+                @_doms ?= {}
+                template = $.xCreate(template, @_doms)
+                if @_doms.widgetConfigs
+                    @_templateContext ?= {}
+                    if @_templateContext.widgetConfigs
+                        widgetConfigs = @_templateContext.widgetConfigs
+                        for k, c of @_doms.widgetConfigs
+                            widgetConfigs[k] = c
+                    else
+                        @_templateContext.widgetConfigs = @_doms.widgetConfigs
+                @_templates[name] = template
+            template._trimed = true
+
+        return template
+
+    _cloneTemplate: (template, supportMultiNodes) ->
+        if template instanceof Array
+            if supportMultiNodes and template.length > 1
+                fragment = document.createDocumentFragment()
+                fragment.appendChild(templ.cloneNode(true)) for templ in template
+                return fragment
+            else
+                return template[0].cloneNode(true)
+        else
+            return template.cloneNode(true)

 cola.DataWidgetMixin =
-	_dataWidget: true
-
-	_bindSetter: (bindStr) ->
-		return if @_bind == bindStr
-
-		if @_bindInfo
-			bindInfo = @_bindInfo
-			if @_watchingPaths
-				for path in @_watchingPaths
-					@_scope.data.unbind(path.join("."), @_bindProcessor)
-			delete @_bindInfo
-
-		@_bind = bindStr
-
-		if bindStr and @_scope
-			@_bindInfo = bindInfo = {}
-
-			bindInfo.expression = expression = cola._compileExpression(bindStr)
-			if expression.repeat or expression.setAlias
-				throw new cola.Exception("Expression \"#{bindStr}\" must be a simple expression.")
-			if (expression.type == "MemberExpression" or expression.type == "Identifier") and not expression.hasCallStatement and not expression.convertors
-				bindInfo.isWriteable = true
-				i = bindStr.lastIndexOf(".")
-				if i > 0
-					bindInfo.entityPath = bindStr.substring(0, i)
-					bindInfo.property = bindStr.substring(i + 1)
-				else
-					bindInfo.entityPath = null
-					bindInfo.property = bindStr
-
-			if !@_bindProcessor
-				@_bindProcessor = bindProcessor = {
-					_processMessage: (bindingPath, path, type, arg) =>
-						if @_filterDataMessage
-							if not @_filterDataMessage(path, type, arg)
-								return
-						else
-							unless cola.constants.MESSAGE_REFRESH <= type <= cola.constants.MESSAGE_CURRENT_CHANGE or @_watchingMoreMessage
-								return
-
-						if @_bindInfo.watchingMoreMessage
-							cola.util.delay(@, "processMessage", 100, () ->
-								if @_processDataMessage
-									@_processDataMessage(@_bindInfo.watchingPaths[0],
-										cola.constants.MESSAGE_REFRESH, {})
-								else
-									@_refreshBindingValue()
-								return
-							)
-						else
-							if @_processDataMessage
-								@_processDataMessage(path, type, arg)
-							else
-								@_refreshBindingValue()
-						return
-				}
-
-			paths = expression.paths
-			if not paths and expression.hasCallStatement
-				paths = ["**"]
-				bindInfo.watchingMoreMessage = expression.hasCallStatement or expression.convertors
-
-			if paths
-				@_watchingPaths = paths
-				for p, i in paths
-					@_scope.data.bind(p, bindProcessor)
-					paths[i] = p.split(".")
-
-				if @_processDataMessage
-					@_processDataMessage(null, cola.constants.MESSAGE_REFRESH, {})
-				else
-					@_refreshBindingValue()
-		return
-
-	destroy: () ->
-		if @_watchingPaths
-			for path in @_watchingPaths
-				@_scope.data.unbind(path.join("."), @_bindProcessor)
-		return
-
-	readBindingValue: (dataCtx) ->
-		return unless @_bindInfo?.expression
-		dataCtx ?= {}
-		return @_bindInfo.expression.evaluate(@_scope, "async", dataCtx)
-
-	writeBindingValue: (value) ->
-		return unless @_bindInfo?.expression
-		if !@_bindInfo.isWriteable
-			throw new cola.Exception("Expression \"#{@_bind}\" is not writable.")
-		@_scope.set(@_bind, value)
-		return
-
-	getBindingProperty: () ->
-		return unless @_bindInfo?.expression and @_bindInfo.isWriteable
-		return @_scope.data.getProperty(@_bind)
-
-	getBindingDataType: () ->
-		return unless @_bindInfo?.expression and @_bindInfo.isWriteable
-		return @_scope.data.getDataType(@_bind)
-
-	_isRootOfTarget: (changedPath, targetPath) ->
-		if !changedPath or !targetPath then return true
-		if targetPath instanceof Array
-			targetPaths = targetPath
-			for targetPath in targetPaths
-				isRoot = true
-				for part, i in changedPath
-					if part != targetPath[i]
-						isRoot = false
-						break
-				if isRoot then return true
-			return false
-		else
-			for part, i in changedPath
-				if part != targetPath[i]
-					return false
-			return true
+    _dataWidget: true
+
+    _bindSetter: (bindStr) ->
+        return if @_bind == bindStr
+
+        if @_bindInfo
+            bindInfo = @_bindInfo
+            if @_watchingPaths
+                for path in @_watchingPaths
+                    @_scope.data.unbind(path.join("."), @_bindProcessor)
+            delete @_bindInfo
+
+        @_bind = bindStr
+
+        if bindStr and @_scope
+            @_bindInfo = bindInfo = {}
+
+            bindInfo.expression = expression = cola._compileExpression(bindStr)
+            if expression.repeat or expression.setAlias
+                throw new cola.Exception("Expression \"#{bindStr}\" must be a simple expression.")
+            if (expression.type == "MemberExpression" or expression.type == "Identifier") and not expression.hasCallStatement and not expression.convertors
+                bindInfo.isWriteable = true
+                i = bindStr.lastIndexOf(".")
+                if i > 0
+                    bindInfo.entityPath = bindStr.substring(0, i)
+                    bindInfo.property = bindStr.substring(i + 1)
+                else
+                    bindInfo.entityPath = null
+                    bindInfo.property = bindStr
+
+            if !@_bindProcessor
+                @_bindProcessor = bindProcessor = {
+                    _processMessage: (bindingPath, path, type, arg) =>
+                        if @_filterDataMessage
+                            if not @_filterDataMessage(path, type, arg)
+                                return
+                        else
+                            unless cola.constants.MESSAGE_REFRESH <= type <= cola.constants.MESSAGE_CURRENT_CHANGE or @_watchingMoreMessage
+                                return
+
+                        if @_bindInfo.watchingMoreMessage
+                            cola.util.delay(@, "processMessage", 100, () ->
+                                if @_processDataMessage
+                                    @_processDataMessage(@_bindInfo.watchingPaths[0],
+                                        cola.constants.MESSAGE_REFRESH, {})
+                                else
+                                    @_refreshBindingValue()
+                                return
+                            )
+                        else
+                            if @_processDataMessage
+                                @_processDataMessage(path, type, arg)
+                            else
+                                @_refreshBindingValue()
+                        return
+                }
+
+            paths = expression.paths
+            if not paths and expression.hasCallStatement
+                paths = ["**"]
+                bindInfo.watchingMoreMessage = expression.hasCallStatement or expression.convertors
+
+            if paths
+                @_watchingPaths = paths
+                for p, i in paths
+                    @_scope.data.bind(p, bindProcessor)
+                    paths[i] = p.split(".")
+
+                if @_processDataMessage
+                    @_processDataMessage(null, cola.constants.MESSAGE_REFRESH, {})
+                else
+                    @_refreshBindingValue()
+        return
+
+    destroy: () ->
+        if @_watchingPaths
+            for path in @_watchingPaths
+                @_scope.data.unbind(path.join("."), @_bindProcessor)
+        return
+
+    readBindingValue: (dataCtx) ->
+        return unless @_bindInfo?.expression
+        dataCtx ?= {}
+        return @_bindInfo.expression.evaluate(@_scope, "async", dataCtx)
+
+    writeBindingValue: (value) ->
+        return unless @_bindInfo?.expression
+        if !@_bindInfo.isWriteable
+            throw new cola.Exception("Expression \"#{@_bind}\" is not writable.")
+        @_scope.set(@_bind, value)
+        return
+
+    getBindingProperty: () ->
+        return unless @_bindInfo?.expression and @_bindInfo.isWriteable
+        return @_scope.data.getProperty(@_bind)
+
+    getBindingDataType: () ->
+        return unless @_bindInfo?.expression and @_bindInfo.isWriteable
+        return @_scope.data.getDataType(@_bind)
+
+    _isRootOfTarget: (changedPath, targetPath) ->
+        if !changedPath or !targetPath then return true
+        if targetPath instanceof Array
+            targetPaths = targetPath
+            for targetPath in targetPaths
+                isRoot = true
+                for part, i in changedPath
+                    if part != targetPath[i]
+                        isRoot = false
+                        break
+                if isRoot then return true
+            return false
+        else
+            for part, i in changedPath
+                if part != targetPath[i]
+                    return false
+            return true

 cola.DataItemsWidgetMixin =
-	_dataItemsWidget: true
-	_alias: "item"
-
-	_bindSetter: (bindStr) ->
-		return if @_bind == bindStr
-
-		@_bind = bindStr
-		@_itemsRetrieved = false
-
-		delete @_simpleBindPath
-		if bindStr
-			expression = cola._compileExpression(bindStr, "repeat")
-			if not expression.repeat
-				throw new cola.Exception("Expression \"#{bindStr}\" must be a repeat expression.")
-			@_alias = expression.alias
-
-			if (expression.type is "MemberExpression" or expression.type is "Identifier") and not expression.hasCallStatement and not expression.convertors
-				@_simpleBindPath = expression.paths[0]
-
-		@_itemsScope.setExpression(expression)
-		return
-
-	constructor: () ->
-		@_itemsScope = itemsScope = new cola.ItemsScope(@_scope)
-
-		itemsScope.onItemsRefresh = (arg) => @_onItemsRefresh(arg)
-		itemsScope.onItemRefresh = (arg) => @_onItemRefresh(arg)
-		itemsScope.onItemInsert = (arg) => @_onItemInsert(arg)
-		itemsScope.onItemRemove = (arg) => @_onItemRemove(arg)
-		itemsScope.onItemsLoadingStart = (arg) => @_onItemsLoadingStart?(arg)
-		itemsScope.onItemsLoadingEnd = (arg) => @_onItemsLoadingEnd?(arg)
-		if @_onCurrentItemChange
-			itemsScope.onCurrentItemChange = (arg) => @_onCurrentItemChange(arg)
-
-	_getItems: () ->
-		if !@_itemsRetrieved
-			@_itemsRetrieved = true
-			@_itemsScope.retrieveItems()
-		return {
-			items: @_itemsScope.items
-			originItems: @_itemsScope.originItems
-		}
-
-	_getBindDataType: () ->
-		items = @_getItems().originItems
-		if items
-			if items instanceof cola.EntityList
-				dataType = items.dataType
-			else if items instanceof Array and items.length
-				item = items[0]
-				if item and item instanceof cola.Entity
-					dataType = item.dataType
-		else if @_simpleBindPath
-			dataType = @_scope.data.getDataType(@_simpleBindPath)
-		return dataType+    _dataItemsWidget: true
+    _alias: "item"
+
+    _bindSetter: (bindStr) ->
+        return if @_bind == bindStr
+
+        @_bind = bindStr
+        @_itemsRetrieved = false
+
+        delete @_simpleBindPath
+        if bindStr
+            expression = cola._compileExpression(bindStr, "repeat")
+            if not expression.repeat
+                throw new cola.Exception("Expression \"#{bindStr}\" must be a repeat expression.")
+            @_alias = expression.alias
+
+            if (expression.type is "MemberExpression" or expression.type is "Identifier") and not expression.hasCallStatement and not expression.convertors
+                @_simpleBindPath = expression.paths[0]
+
+        @_itemsScope.setExpression(expression)
+        return
+
+    constructor: () ->
+        @_itemsScope = itemsScope = new cola.ItemsScope(@_scope)
+
+        itemsScope.onItemsRefresh = (arg) => @_onItemsRefresh(arg)
+        itemsScope.onItemRefresh = (arg) => @_onItemRefresh(arg)
+        itemsScope.onItemInsert = (arg) => @_onItemInsert(arg)
+        itemsScope.onItemRemove = (arg) => @_onItemRemove(arg)
+        itemsScope.onItemsLoadingStart = (arg) => @_onItemsLoadingStart?(arg)
+        itemsScope.onItemsLoadingEnd = (arg) => @_onItemsLoadingEnd?(arg)
+        if @_onCurrentItemChange
+            itemsScope.onCurrentItemChange = (arg) => @_onCurrentItemChange(arg)
+
+    _getItems: () ->
+        if !@_itemsRetrieved
+            @_itemsRetrieved = true
+            @_itemsScope.retrieveItems()
+        return {
+        items: @_itemsScope.items
+        originItems: @_itemsScope.originItems
+        }
+
+    _getBindDataType: () ->
+        items = @_getItems().originItems
+        if items
+            if items instanceof cola.EntityList
+                dataType = items.dataType
+            else if items instanceof Array and items.length
+                item = items[0]
+                if item and item instanceof cola.Entity
+                    dataType = item.dataType
+        else if @_simpleBindPath
+            dataType = @_scope.data.getDataType(@_simpleBindPath)
+        return dataType


add file tooltip

add file tooltip

--- lib/file-links.coffee
+++ lib/file-links.coffee
@@ -12,6 +12,9 @@
         f file, line

   linkify: (view) ->
+    @withFileLinks view, (a, file) ->
+      atom.tooltips.add a,
+        title: -> file
     @onClick view, (file, line) ->
       atom.workspace.open file,
         initialLine: line


:lipstick:

:lipstick:

--- lib/find-model.coffee
+++ lib/find-model.coffee
@@ -108,13 +108,6 @@
     marker.destroy() for marker in @markers ? []
     @markers = []

-  # incrementCurrentMarkerIndex: =>
-  #   @currentMarkerIndex = ++@currentMarkerIndex % @markers.length
-  #
-  # decrementCurrentMarkerIndex: =>
-  #   @currentMarkerIndex--
-  #   @currentMarkerIndex = @markers.length - 1 if @currentMarkerIndex < 0
-
   firstMarkerIndexAfterCursor: ->
     selection = @editSession.getSelection()
     {start, end} = selection.getBufferRange()


Admin: Integrations: Removed dummy data.

--- client/admin/lib/views/integrations/adminintegrationitemview.coffee
+++ client/admin/lib/views/integrations/adminintegrationitemview.coffee
@@ -3,50 +3,6 @@
 remote         = require('app/remote').getInstance()
 KDButtonView   = kd.ButtonView
 KDListItemView = kd.ListItemView
-
-DUMMY_DATA     =
-  setupData    :
-    name       : 'Airbrake'
-    logo       : 'https://koding-cdn.s3.amazonaws.com/temp-images/airbrake.png'
-    summary    : 'Error monitoring and handling.'
-    desc       : """
-
Airbrake captures errors generated by your team's web applications, and aggregates the results for easy review.

-
This integration will post notifications in Slack when an error is reported in Airbrake.

-    """
-    channels   : [
-      { name   : '#general',   id: '123' }
-      { name   : '#random',    id: '124' }
-      { name   : '#off-topic', id: '125' }
-    ]
-  detailsData  :
-    name    : 'Airbrake'
-    logo    : 'https://koding-cdn.s3.amazonaws.com/temp-images/airbrake.png'
-    summary : 'Error monitoring and handling.'
-    desc    : """
-
Airbrake captures errors generated by your team's web applications, and aggregates the results for easy review.

-
This integration will post notifications in Slack when an error is reported in Airbrake.

-    """
-    channels : [
-      { name: '#general',   id: '123' }
-      { name: '#random',    id: '124' }
-      { name: '#off-topic', id: '125' }
-    ]
-    selectedChannel : '123'
-    webhookUrl      : 'https://hooks.koding.com/services/123/abc/def'
-    instructions    : """
-      #### Step 1
-
-      In your Airbrake dashboard, click on the menu button in the top navigation, and then select **Integrations** from the sub-menu.
-
-      ![airbrake_step1.png](https://koding-cdn.s3.amazonaws.com/temp-images/airbrake_step1.png)
-
-
-      #### Step 2
-
-      Click on Slack in the list of integrations, add `https://hooks.slack.com/services/123/abc/def` as the Slack webhook, and choose your notification settings. Press the Save button when you're done.
-
-      ![airbrake_step2.png](https://koding-cdn.s3.amazonaws.com/temp-images/airbrake_step2.png)
-    """

 module.exports = class AdminIntegrationItemView extends KDListItemView
@@ -76,6 +32,7 @@

   fetchIntegrationChannels: ->
+
     data = @getData()

     @fetchChannels (err, channels) =>
@@ -87,19 +44,13 @@
       @emit 'IntegrationGroupsFetched', data

-  fetchIntegrationDetails: ->
-    { title, summary, description, iconPath } = @getData()
+  fetchChannels: (callback) ->

-    remote.api.JAccount.some {}, {}, (err, data) =>
-      @button.hideLoader()
-      @emit 'IntegrationConfigureRequested', DUMMY_DATA.detailsData
-
-
-  fetchChannels: (callback) ->
     kd.singletons.socialapi.account.fetchChannels (err, channels) =>
       return callback err  if err

       decoratedChannels = []
+
       for channel in channels
         { id, typeConstant, name, purpose, participantsPreview } = channel


Workspace: Separated create user list method.

--- client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
+++ client/landing/CollaborativeWorkspace/collaborativeworkspace.coffee
@@ -299,7 +299,11 @@
     return  if @userList
     @userListContainer.setClass "active"

-    @userListContainer.addSubView @userList = new CollaborativeWorkspaceUserList {
+    @createUserList()
+    @userListContainer.addSubView @userList
+
+  createUserList: ->
+    @userList = new CollaborativeWorkspaceUserList {
       @workspaceRef
       @sessionKey
       container : @userListContainer


Refactor the progressbar

Refactor the progressbar

--- rrrspec-web/assets/javascripts/tasksets.coffee
+++ rrrspec-web/assets/javascripts/tasksets.coffee
@@ -54,52 +54,40 @@
   class ProgressBarView extends Backbone.View
     el: '.progressbars'

-    render: ->
-      tasks = @model.get('tasks')
+    showBar: (bar, percentage, text) ->
+      if percentage == 0
+        bar.attr('style', 'width: 0%')
+        bar.text('')
+      else
+        bar.attr('style', "width: #{100*percentage}%")
+        bar.text(text)
+    hideBar: (bar) -> @showBar(bar, 0, '')
+
+    renderSpecBar: (tasks) ->
       if @model.isFinished()
         @$('.spec-progress').removeClass('progress-striped active')
-        @$('.spec-progress-bar').attr('style', 'width: 0%')
-        @$('.spec-progress-bar').text('')
-        if tasks.numPassedTask > 0
-          @$('.passed-spec-bar').attr('style', "width: #{100*tasks.numPassedTask/tasks.numTask}%")
-          @$('.passed-spec-bar').text(tasks.numPassedTask)
-        if tasks.numPendingTask > 0
-          @$('.pending-spec-bar').attr('style', "width: #{100*tasks.numPendingTask/tasks.numTask}%")
-          @$('.pending-spec-bar').text(tasks.numPendingTask)
-        if tasks.numFailedTask > 0
-          @$('.failed-spec-bar').attr('style', "width: #{100*tasks.numFailedTask/tasks.numTask}%")
-          @$('.failed-spec-bar').text(tasks.numFailedTask)
+        @hideBar(@$('.spec-progress-bar'))
+        @showBar(@$('.passed-spec-bar'), tasks.numPassedTask/tasks.numTask, tasks.numPassedTask)
+        @showBar(@$('.pending-spec-bar'), tasks.numPendingTask/tasks.numTask, tasks.numPendingTask)
+        @showBar(@$('.failed-spec-bar'), tasks.numFailedTask/tasks.numTask, tasks.numFailedTask)
       else
         numFinishedTask = tasks.numPassedTask + tasks.numPendingTask + tasks.numFailedTask
-        percentage = 100*numFinishedTask/tasks.numTask
+        percentage = numFinishedTask/tasks.numTask
         @$('.spec-progress').addClass('progress-striped active')
-        @$('.spec-progress-bar').attr('style', "width: #{percentage}%")
-        @$('.spec-progress-bar').text("#{numFinishedTask}/#{tasks.numTask}(#{percentage}%)")
-        @$('.passed-spec-bar').attr('style', 'width: 0%')
-        @$('.passed-spec-bar').text('')
-        @$('.pending-spec-bar').attr('style', 'width: 0%')
-        @$('.pending-spec-bar').text('')
-        @$('.failed-spec-bar').attr('style', 'width: 0%')
-        @$('.failed-spec-bar').text('')
-
-      if tasks.numPassedExample > 0
-        @$('.passed-example-bar').attr('style', "width: #{100*tasks.numPassedExample/tasks.numExample}%")
-        @$('.passed-example-bar').text(tasks.numPassedExample)
-      else
-        @$('.passed-example-bar').attr('style', "width: 0%")
-        @$('.passed-example-bar').text('')
-      if tasks.numPendingExample > 0
-        @$('.pending-example-bar').attr('style', "width: #{100*tasks.numPendingExample/tasks.numExample}%")
-        @$('.pending-example-bar').text(tasks.numPendingExample)
-      else
-        @$('.pending-example-bar').attr('style', "width: 0%")
-        @$('.pending-example-bar').text('')
-      if tasks.numFailedExample > 0
-        @$('.failed-example-bar').attr('style', "width: #{100*tasks.numFailedExample/tasks.numExample}%")
-        @$('.failed-example-bar').text(tasks.numFailedExample)
-      else
-        @$('.failed-example-bar').attr('style', "width: 0%")
-        @$('.failed-example-bar').text('')
+        @showBar(@$('.spec-progress-bar'), percentage, "#{numFinishedTask}/#{tasks.numTask} (#{100*percentage}%)")
+        @hideBar(@$('.passed-spec-bar'))
+        @hideBar(@$('.pending-spec-bar'))
+        @hideBar(@$('.failed-spec-bar'))
+
+    renderExampleBar: (tasks) ->
+      @showBar(@$('.passed-example-bar'), tasks.numPassedExample/tasks.numExample, tasks.numPassedExample)
+      @showBar(@$('.pending-example-bar'), tasks.numPendingExample/tasks.numExample, tasks.numPendingExample)
+      @showBar(@$('.failed-example-bar'), tasks.numFailedExample/tasks.numExample, tasks.numFailedExample)
+
+    render: ->
+      tasks = @model.get('tasks')
+      @renderSpecBar(tasks)
+      @renderExampleBar(tasks)

   class TaskListView extends Backbone.View
     el: '.tasklist'


Updated facebook user roles.

Updated facebook user roles.

--- models/person.coffee
+++ models/person.coffee
@@ -1,4 +1,5 @@
 _ = require 'underscore'
+colors = require 'colors'
 mongoose = require 'mongoose'
 auth = require 'mongoose-auth'
 env = require '../config/env'
@@ -61,6 +62,12 @@
       myHostname: env.hostname
       appId: env.facebook_app_id
       appSecret: env.secrets.facebook
+      findOrCreateUser: (session, accessTok, accessTokExtra, fb) ->
+        promise = @Promise()
+        Person.findOrCreateFromFacebook fb, (err, person) ->
+          return promise.fail err if err
+          promise.fulfill person
+        promise

 ROLES.forEach (t) ->
   PersonSchema.virtual(t).get -> @role == t
@@ -105,6 +112,12 @@
   @image_url ||= twitter.profileImageUrl.replace('_normal.', '.')
   @role ||= 'nomination'

+PersonSchema.method 'updateFromFacebook', (facebook) ->
+  console.log arguments.cyan
+  @facebook_name = facebook.alias
+  @name ||= facebook.name.full
+  @role ||= 'voter'
+
 PersonSchema.static 'findOrCreateFromTwitter', (twitter, callback) ->
   Person.findOne
     $or: [
@@ -116,5 +129,17 @@
       try person.updateFromTwitter twitter catch e then callback(e)
       person.save (err) -> callback(err, person)

+PersonSchema.static 'findOrCreateFromFacebook', (facebook, callback) ->
+  console.log arguments.magenta
+  Person.findOne
+    $or: [
+      { facebook_name: facebook.alias }
+      { 'fb.id': facebook.id }]
+    (error, person) ->
+      return callback(error) if error
+      person ||= new Person
+      try person.updateFromFacebook facebook catch e then callback(e)
+      person.save (err) -> callback(err, person)
+
 Person = mongoose.model 'Person', PersonSchema
 Person.ROLES = ROLES


Atom config update

Atom config update

--- etc/atom/config.cson
+++ etc/atom/config.cson
@@ -1,36 +1,30 @@
 "*":
-  "exception-reporting":
-    userId: "f87332bf-54f7-bc72-aeba-5b58d78cb5d4"
-  "release-notes":
-    viewedVersion: "0.95.0"
-  welcome:
-    showOnStartup: false
-  metrics:
-    userId: "305d8eb962055d82cd69f9974fcc3c7d0e3f288e"
-  editor:
-    fontFamily: "Source Code Pro"
-    showIndentGuide: true
-    softWrapAtPreferredLineLength: true
-    invisibles: {}
+  "atom-beautify":
+    _analyticsUserId: "542ad6ff-4e4a-479a-bee1-7e619cab00b0"
+    analytics: false
+    js_jslint_happy: true
+  "bracket-matcher":
+    autocompleteBrackets: false
   core:
+    audioBeep: false
     disabledPackages: [
       "Zen"
       "symbols-tree-view"
     ]
+    projectHome: "/Users/stillers/workspace"
     themes: [
       "atom-dark-ui"
       "solarized-dark-syntax"
     ]
-    projectHome: "/Users/stillers/workspace"
-    audioBeep: false
-  "bracket-matcher":
-    autocompleteBrackets: false
+  editor:
+    fontFamily: "Source Code Pro"
+    invisibles: {}
+    showIndentGuide: true
+    softWrapAtPreferredLineLength: true
+  "exception-reporting":
+    userId: "f87332bf-54f7-bc72-aeba-5b58d78cb5d4"
   "find-and-replace":
     focusEditorAfterSearch: true
-  "atom-beautify":
-    _analyticsUserId: "542ad6ff-4e4a-479a-bee1-7e619cab00b0"
-    analytics: false
-    js_jslint_happy: true
   linter:
     lintOnChange: false
     showErrorPanel: false
@@ -40,8 +34,14 @@
     statusIconScope: "File"
   "linter-jshint":
     lintInlineJavaScript: true
+  metrics:
+    userId: "305d8eb962055d82cd69f9974fcc3c7d0e3f288e"
+  minimap: {}
+  "release-notes":
+    viewedVersion: "0.95.0"
   "symbols-tree-view":
     autoToggle: true
   tabs:
     usePreviewTabs: true
-  minimap: {}
+  welcome:
+    showOnStartup: false


Move VimiumHelpDialog out of showHelpDialog

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -768,6 +768,33 @@
   Marks.setPreviousPosition()
   new FindMode()

+VimiumHelpDialog =
+  # This setting is pulled out of local storage. It's false by default.
+  getShowAdvancedCommands: -> Settings.get("helpDialog_showAdvancedCommands")
+
+  init: () ->
+    this.dialogElement = document.getElementById("vimiumHelpDialog")
+    this.dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].addEventListener("click",
+      VimiumHelpDialog.toggleAdvancedCommands, false)
+    this.dialogElement.style.maxHeight = window.innerHeight - 80
+    this.showAdvancedCommands(this.getShowAdvancedCommands())
+
+  #
+  # Advanced commands are hidden by default so they don't overwhelm new and casual users.
+  #
+  toggleAdvancedCommands: (event) ->
+    event.preventDefault()
+    showAdvanced = VimiumHelpDialog.getShowAdvancedCommands()
+    VimiumHelpDialog.showAdvancedCommands(!showAdvanced)
+    Settings.set("helpDialog_showAdvancedCommands", !showAdvanced)
+
+  showAdvancedCommands: (visible) ->
+    VimiumHelpDialog.dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].innerHTML =
+      if visible then "Hide advanced commands" else "Show advanced commands"
+    advancedEls = VimiumHelpDialog.dialogElement.getElementsByClassName("advanced")
+    for el in advancedEls
+      el.style.display = if visible then "table-row" else "none"
+
 window.showHelpDialog = (html, fid) ->
   return if (isShowingHelpDialog || !document.body || fid != frameId)
   isShowingHelpDialog = true
@@ -779,33 +806,6 @@

   container.innerHTML = html
   container.getElementsByClassName("closeButton")[0].addEventListener("click", hideHelpDialog, false)
-
-  VimiumHelpDialog =
-    # This setting is pulled out of local storage. It's false by default.
-    getShowAdvancedCommands: -> Settings.get("helpDialog_showAdvancedCommands")
-
-    init: () ->
-      this.dialogElement = document.getElementById("vimiumHelpDialog")
-      this.dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].addEventListener("click",
-        VimiumHelpDialog.toggleAdvancedCommands, false)
-      this.dialogElement.style.maxHeight = window.innerHeight - 80
-      this.showAdvancedCommands(this.getShowAdvancedCommands())
-
-    #
-    # Advanced commands are hidden by default so they don't overwhelm new and casual users.
-    #
-    toggleAdvancedCommands: (event) ->
-      event.preventDefault()
-      showAdvanced = VimiumHelpDialog.getShowAdvancedCommands()
-      VimiumHelpDialog.showAdvancedCommands(!showAdvanced)
-      Settings.set("helpDialog_showAdvancedCommands", !showAdvanced)
-
-    showAdvancedCommands: (visible) ->
-      VimiumHelpDialog.dialogElement.getElementsByClassName("toggleAdvancedCommands")[0].innerHTML =
-        if visible then "Hide advanced commands" else "Show advanced commands"
-      advancedEls = VimiumHelpDialog.dialogElement.getElementsByClassName("advanced")
-      for el in advancedEls
-        el.style.display = if visible then "table-row" else "none"

   VimiumHelpDialog.init()


Disable pre-loading of Vomnibar iframe.

Disable pre-loading of Vomnibar iframe.

Pre-loading the Vomnibar iframe seems to be causing some issues with the
dev console.  This PR disables pre-loading of the Vomnibar.

I'm going to try this out for a while.  If it doesn't seem to sluggish,
then I'll merge it.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -112,19 +112,6 @@
   new InsertMode permanent: true
   new GrabBackFocus if isEnabledForUrl
   normalMode # Return the normalMode object (for the tests).
-
-initializeOnEnabledStateKnown = (isEnabledForUrl) ->
-  installModes() unless normalMode
-  if isEnabledForUrl
-    unless Utils.isFirefox() and document.documentElement.namespaceURI != "http://www.w3.org/1999/xhtml"
-      # We only initialize (and activate) the Vomnibar in the top frame.  Also, we do not initialize the
-      # Vomnibar until we know that Vimium is enabled.  Thereafter, there's no more initialization to do.
-      #
-      # NOTE(mrmr1993): In XML documents on Firefox, injecting HTML into the DOM breaks the rendering, so we
-      # lazy load the Vomnibar. This comes with the expected issues, but is better than breaking all XML
-      # documents.
-      DomUtils.documentComplete Vomnibar.init.bind Vomnibar if DomUtils.isTopFrame()
-    initializeOnEnabledStateKnown = ->

 #
 # Complete initialization work that should be done prior to DOMReady.
@@ -305,7 +292,7 @@
   Frame.addEventListener "isEnabledForUrl", (response) ->
     {isEnabledForUrl, passKeys, frameIsFocused, isFirefox} = response
     Utils.isFirefox = -> isFirefox
-    initializeOnEnabledStateKnown isEnabledForUrl
+    installModes() unless normalMode
     normalMode.setPassKeys passKeys
     # Hide the HUD if we're not enabled.
     HUD.hide true, false unless isEnabledForUrl


Fix reminder creation bug.

Fix reminder creation bug.

--- controllers/remindersController.coffee
+++ controllers/remindersController.coffee
@@ -9,7 +9,7 @@
 	body = req.body
 	if body.amPm == "PM" then body.hours = body.hours + 12
 	reminderWhen = new Date body.year, body.month-1, body.day, body.hours, body.minutes
-	reminderTime = new Date (reminder_when.getTime() - (body.reminderOffset * 60 * 1000))
+	reminderTime = new Date (reminderWhen.getTime() - (body.reminderOffset * 60 * 1000))
 	reminderTypes = body.reminderTypes or []
 	reminderTypes = if !Array.isArray(reminderTypes) then [body.reminderTypes]
 	reminder =


Fix teacher autofill solution button to get correct code language

--- ozaria/site/views/play/level/tome/CastButtonView.coffee
+++ ozaria/site/views/play/level/tome/CastButtonView.coffee
@@ -98,7 +98,8 @@

   onFillSolution: ->
     return unless me.canAutoFillCode()
-    store.dispatch('game/autoFillSolution')
+    codeLanguage = _.values(@spells)[0]?.language or utils.getQueryVariable('codeLanguage') or 'python'
+    store.dispatch('game/autoFillSolution', codeLanguage)

   onSpellChanged: (e) ->
     @updateCastButton()


Update amd-tamer task to use variables and new naming scheme

--- grunt/amd_tamer.coffee
+++ grunt/amd_tamer.coffee
@@ -4,10 +4,10 @@
       namespace: '<%= package.name %>',
       base: 'src/'
     src: ['src/**/*.js'],
-    dest: 'build/debug/js/<%= package.name %>.js'
+    dest: '<%= buildDebug %>/js/<%= package.name %>.js'
   all:
     options:
       footer: '//# sourceMappingURL=all.js.map'
-      base: 'build/debug/js'
-    src: ['build/debug/js/**/*.js']
-    dest: 'build/debug/all.js'
+      base: '<%= buildDebug %>/js'
+    src: ['<%= buildDebug %>/js/**/*.js']
+    dest: '<%= buildDebug %>/all.js'


Send target as well on detection

Send target as well on detection

--- components/DetectTarget.coffee
+++ components/DetectTarget.coffee
@@ -11,6 +11,7 @@
     @outPorts =
       pass: new noflo.Port 'object'
       fail: new noflo.Port 'object'
+      target: new noflo.Port 'object'

     @inPorts.target.on 'data', (data) ->
       parts = data.split '='
@@ -28,16 +29,22 @@
             passed = false
         if passed
           @outPorts.pass.send data
+          if @outPorts.target.isAttached()
+            @outPorts.target.send data[Object.keys(data)[0].target]
         else
           @outPorts.fail.send data
         return
       if @detectTarget data[Object.keys(data)[0]]
         @outPorts.pass.send data
+        if @outPorts.target.isAttached()
+          @outPorts.target.send data[Object.keys(data)[0].targe]
       else
         @outPorts.fail.send data
     @inPorts.in.on 'disconnect', =>
       @outPorts.pass.disconnect()
       @outPorts.fail.disconnect()
+      if @outPorts.target.isAttached()
+        @outPorts.target.disconnect()

   detectTarget: (element) ->
     for key, value of @target


GetHistogram: Normalize output to [0.0-1.0], also give Y' brightess

--- components/GetHistogram.coffee
+++ components/GetHistogram.coffee
@@ -5,22 +5,43 @@
     a[i] = 0
   return a

+normalize = (a, max) ->
+  for i in [0...a.length]
+    a[i] = (a[i]/max)
+  return a
+
+# Perceptual brightness
+# CIE Y'601. Input: sR'G'B' (gamma) [0.0-1.0]
+cie_y601 = (r, g, b) ->
+  return 0.299*r + 0.587*g + 0.114*b
+
 computeHistogram = (canvas) ->
   res =
     r: zero new Array 256
     g: zero new Array 256
     b: zero new Array 256
+    y: zero new Array 256

   # TODO: check if individual scanlines is faster
   ctx = canvas.getContext '2d'
   imageData = ctx.getImageData 0, 0, canvas.width, canvas.height
-  pixels = imageData.data
-  for i in [0...pixels.length] by 4
-    [r, g, b] = [pixels[i], pixels[i+1], pixels[i+1]]
+  data = imageData.data
+  for i in [0...data.length] by 4
+    [r, g, b] = [data[i], data[i+1], data[i+2]]
+    y = cie_y601 r/255, g/255, b/255
+    y = Math.floor y*255
     res.r[r]+=1
-    res.g[r]+=1
+    res.g[g]+=1
     res.b[b]+=1
+    res.y[y]+=1

+  # Normalize such that 1.0 means all pixels have this color
+  pixels = data.length/4
+  normalize res.r, pixels
+  normalize res.g, pixels
+  normalize res.b, pixels
+  normalize res.y, pixels
+
   return res

 exports.getComponent = ->


Crawler: Added notification related query string to end of login links in activity.

--- server/lib/crawler/staticpages/activity.coffee
+++ server/lib/crawler/staticpages/activity.coffee
@@ -214,14 +214,14 @@

               #{userInteractionMeta}

-                  Like
-
+                  Like
+
                           #{likesCount}

-                      Comment
-
+                      Comment
+
                           #{commentsCount}


That's what she said 3

That's what she said 3

--- scripts/twss.coffee
+++ scripts/twss.coffee
@@ -2,7 +2,7 @@

 module.exports = (robot) ->
   robot.hear /(.*)/, (msg)->
-    if twss.is msg
+    if twss.is msg.match[1]
       if Math.random() < 0.9
         msg.send "That's what she said"
       else


oauth: fix popup error parameter handling

--- server/lib/server/templates/oauth_popup.coffee
+++ server/lib/server/templates/oauth_popup.coffee
@@ -1,6 +1,6 @@
 module.exports = ({error, provider})->
+  error = if error? then "\"#{error}\"" else null
   """
-
   <!DOCTYPE html>
   <html lang="en">
   <head>


Add new type of logs (box) and new log method (success)

--- packages/rocketchat-logger/server.coffee
+++ packages/rocketchat-logger/server.coffee
@@ -59,6 +59,10 @@
 			name: 'info'
 			color: 'blue'
 			level: 1
+		success:
+			name: 'info'
+			color: 'green'
+			level: 1
 		warn:
 			name: 'warn'
 			color: 'magenta'
@@ -82,6 +86,14 @@
 				@[type] = (args...) =>
 					@_log
 						type: type
+						level: typeConfig.level
+						method: typeConfig.name
+						arguments: args
+
+				@[type+"Box"] = (args...) =>
+					@_log
+						type: type
+						box: true
 						level: typeConfig.level
 						method: typeConfig.name
 						arguments: args
@@ -181,6 +193,26 @@

 		return details

+	makeABox: (message) ->
+		if not _.isArray(message)
+			message = message.split("\n")
+
+		len = 0
+		for line in message
+			len = Math.max(len, line.length)
+
+		len += 4
+
+		text = message.map (msg) =>
+			return "|" + s.lrpad(msg, len) + "|"
+
+		text = text.join("\n")
+		topLine = "+" + s.pad('', len, '=') + "+"
+		separator = "|" + s.pad('', len, '') + "|"
+		bottomLine = "+" + s.pad('', len, '=') + "+"
+		return [topLine, separator, text, separator, bottomLine]
+
+
 	_log: (options) ->
 		if LoggerManager.enabled is false
 			LoggerManager.addToQueue @, arguments
@@ -191,8 +223,29 @@
 		if LoggerManager.logLevel < options.level
 			return

-		options.arguments.unshift @getPrefix(options)
-		console.log.apply console, options.arguments
+		prefix = @getPrefix(options)
+
+		if options.box is true and _.isString(options.arguments[0])
+			color = undefined
+			if @defaultTypes[options.type]?
+				color = @defaultTypes[options.type].color
+
+			box = @makeABox options.arguments[0], color
+			subPrefix = '➔'
+			if color?
+				subPrefix = subPrefix[color]
+
+			console.log subPrefix, prefix
+			for line in box
+				if color?
+					console.log subPrefix, line[color]
+				else
+					console.log subPrefix, line
+		else
+			options.arguments.unshift prefix
+			console.log.apply console, options.arguments
+
+		return

 processString = (string, date) ->
 	if string[0] is '{'


Fix hive test

Fix hive test

--- hdp/hive_client.coffee
+++ hdp/hive_client.coffee
@@ -61,34 +61,22 @@
     , (err) ->
       next err, if configured then ctx.OK else ctx.PASS

-    # if hdfs dfs -test -d /user/test/hive_#{ctx.config.host}/check_hive_tb; then exit 2; fi
-    # hive -e "
-    #   CREATE DATABASE IF NOT EXISTS check_hive_db  LOCATION '/user/test/hive_#{ctx.config.host}'; \\
-    #   USE check_hive_db; \\
-    #   CREATE TABLE IF NOT EXISTS check_hive_tb(col1 STRING, col2 INT);" || exit 1
-    # echo "a,1\\nb,2\\nc,3" > /tmp/check_hive;
-    # hdfs dfs -mkdir -p /user/test/hive_#{ctx.config.host}/check_hive_tb
-    # hdfs dfs -put /tmp/check_hive /user/test/hive_#{ctx.config.host}/check_hive_tb/data || exit 1
-    # hive -e "SELECT SUM(col2) FROM check_hive_db.check_hive_tb;" || exit 1
-    # hive -e "DROP TABLE check_hive_db.check_hive_tb; DROP DATABASE check_hive_db;" || exit 1
-    # rm -rf /tmp/check_hive
-    # hdfs dfs -touchz /user/test/hive_#{ctx.config.host}
-
 module.exports.push name: 'HDP Hive & HCat client # Check Metastore', timeout: -1, callback: (ctx, next) ->
   {hive_metastore_host, hive_metastore_port} = ctx.config.hdp
   ctx.waitForConnection hive_metastore_host, hive_metastore_port, (err) ->
+    host = ctx.config.host.split('.')[0]
     ctx.execute
       cmd: mkcmd.test ctx, """
       if hdfs dfs -test -d /user/test/hive_#{ctx.config.host}/check_metastore_tb; then exit 2; fi
       hdfs dfs -mkdir -p /user/test/hive_#{ctx.config.host}/check_metastore_tb
       echo -e 'a|1\\\\nb|2\\\\nc|3' | hdfs dfs -put - /user/test/hive_#{ctx.config.host}/check_metastore_tb/data
       hive -e "
-        CREATE DATABASE IF NOT EXISTS check_hive_db  LOCATION '/user/test/hive_#{ctx.config.host}'; \\
-        USE check_hive_db; \\
+        CREATE DATABASE IF NOT EXISTS check_#{host}_db  LOCATION '/user/test/hive_#{ctx.config.host}'; \\
+        USE check_#{host}_db; \\
         CREATE TABLE IF NOT EXISTS check_metastore_tb(col1 STRING, col2 INT); \\
       "
-      hive -e "SELECT SUM(col2) FROM check_hive_db.check_metastore_tb;"
-      hive -e "DROP TABLE check_hive_db.check_metastore_tb; DROP DATABASE check_hive_db;"
+      hive -e "SELECT SUM(col2) FROM check_#{host}_db.check_metastore_tb;"
+      hive -e "DROP TABLE check_#{host}_db.check_metastore_tb; DROP DATABASE check_#{host}_db;"
       #hdfs dfs -mkdir -p /user/test/hive_#{ctx.config.host}/check_metastore_tb
       """
       code_skipped: 2
@@ -101,15 +89,16 @@
   url = "jdbc:hive2://#{hive_server2_host}:#{hive_server2_port}/default;principal=hive/#{hive_server2_host}@#{realm}"
   query = (query) -> "/usr/lib/hive/bin/beeline -u \"#{url}\" -n #{test_user} -p #{test_password} -e \"#{query}\" "
   ctx.waitForConnection hive_server2_host, hive_server2_port, (err) ->
+    host = ctx.config.host.split('.')[0]
     ctx.execute
       cmd: mkcmd.test ctx, """
       if hdfs dfs -test -d /user/test/hive_#{ctx.config.host}/check_server2_tb; then exit 2; fi
       hdfs dfs -mkdir -p /user/test/hive_#{ctx.config.host}/check_server2_tb
       echo -e 'a|1\\\\nb|2\\\\nc|3' | hdfs dfs -put - /user/test/hive_#{ctx.config.host}/check_server2_tb/data
-      #{query "CREATE DATABASE IF NOT EXISTS check_hive_db  LOCATION '/user/test/hive_#{ctx.config.host}'"}
-      #{query 'CREATE TABLE IF NOT EXISTS check_hive_db.check_server2_tb(col1 STRING, col2 INT);'}
-      #{query 'SELECT SUM(col2) FROM check_hive_db.check_server2_tb;'}
-      #{query 'DROP TABLE check_hive_db.check_server2_tb; DROP DATABASE check_hive_db;'}
+      #{query "CREATE DATABASE IF NOT EXISTS check_#{host}_db  LOCATION '/user/test/hive_#{ctx.config.host}'"}
+      #{query 'CREATE TABLE IF NOT EXISTS check_#{host}_db.check_server2_tb(col1 STRING, col2 INT);'}
+      #{query 'SELECT SUM(col2) FROM check_#{host}_db.check_server2_tb;'}
+      #{query 'DROP TABLE check_#{host}_db.check_server2_tb; DROP DATABASE check_#{host}_db;'}
       hdfs dfs -mkdir -p /user/test/hive_#{ctx.config.host}/check_server2_tb
       """
       code_skipped: 2