Remove excessive var

Remove excessive var

--- library/nucleus/routing.coffee
+++ library/nucleus/routing.coffee
@@ -63,7 +63,7 @@
             @emit "recognized", recognized, signature...
             matching = "Request %s matches %s service"
             logger.debug matching.grey, incoming, identify
-            return results = recognized.process signature...
+            return recognized.process signature...
             next() unless response.headerSent

     # Try registering a new routable object. The method checks for


stylistic changes in the router

stylistic changes in the router

--- library/nucleus/routing.coffee
+++ library/nucleus/routing.coffee
@@ -90,16 +90,16 @@
     # If something is wrong, this method will throw an exception.
     # The method is idempotent, ergo no duplication of routables.
     register: (routable, callback) ->
-        identify = routable?.constructor?.identify()
-        inspected = identify.toString().underline
+        assert identify = routable.constructor.identify()
+        assert inspected = try identify.toString().underline
         [matches, process] = [routable.matches, routable.process]
         goneMatches = "The #{identify} has no valid matches method"
         goneProcess = "The #{identify} has no valid process method"
         passMatches = _.isFunction(matches) and matches.length is 3
         passProcess = _.isFunction(process) and process.length is 3
-        throw new Error goneMatches unless passMatches
-        throw new Error goneProcess unless passProcess
-        duplicate = "the #{inspected} service already there"
+        throw new Error goneMatches.toString() unless passMatches
+        throw new Error goneProcess.toString() unless passProcess
+        duplicate = "the #{inspected} service already registered"
         assert not (routable in (@registry or [])), duplicate
         register = routable.upstreamAsync "register", =>
             attaching = "Attaching %s service instance"
@@ -122,8 +122,8 @@
         inspected = identify.toString().underline
         noRegistry = "Could not access the registry"
         removing = "Removing %s service instance"
-        assert _.isArray @registry, noRegistry
-        index = _.indexOf @registry, routable
+        assert _.isArray(@registry or 0), noRegistry
+        index = try _.indexOf @registry, routable
         assert index >= 0, "missing service: #{inspected}"
         unregister = routable.upstreamAsync "unregister", =>
             @emit "unregister", @routable, @kernel


Hide box which covers subscribe button in LevelLoadingView

Fixes #4204

--- app/views/play/level/LevelLoadingView.coffee
+++ app/views/play/level/LevelLoadingView.coffee
@@ -206,19 +206,19 @@
     @resize()

   onSubscriptionRequired: (e) ->
-    @$el.find('.level-loading-goals, .tip, .load-progress').hide()
+    @$el.find('.level-loading-goals, .tip, .progress-or-start-container').hide()
     @$el.find('.subscription-required').show()

   onCourseMembershipRequired: (e) ->
-    @$el.find('.level-loading-goals, .tip, .load-progress').hide()
+    @$el.find('.level-loading-goals, .tip, .progress-or-start-container').hide()
     @$el.find('.course-membership-required').show()

   onLicenseRequired: (e) ->
-    @$el.find('.level-loading-goals, .tip, .load-progress').hide()
+    @$el.find('.level-loading-goals, .tip, .progress-or-start-container').hide()
     @$el.find('.license-required').show()

   onLoadError: (resource) ->
-    @$el.find('.level-loading-goals, .tip, .load-progress').hide()
+    @$el.find('.level-loading-goals, .tip, .progress-or-start-container').hide()
     @$el.find('.could-not-load').show()

   onClickStartSubscription: (e) ->


Remove logspam

Remove logspam

--- lib/acp-python-jedi.coffee
+++ lib/acp-python-jedi.coffee
@@ -8,7 +8,6 @@
   provider: null

   activate: (state) ->
-    console.log "Activated"

   deactivate: ->
     @provider = null


fix warnning

fix warnning

--- port_scan/coffee/web.coffee
+++ port_scan/coffee/web.coffee
@@ -4,7 +4,8 @@
 EventProxy = require 'eventproxy'
 db = mongojs 'test', ['ips']
 app = express()
-app.use express.bodyParser()
+app.use express.json()
+app.use express.urlencoded()

 ip2num = (ipstr) ->
   ip = 0


Fixed a bug that _loadGlobalConfig refers to a undefined variable localConf.

--- lib/config-resolver.coffee
+++ lib/config-resolver.coffee
@@ -28,7 +28,8 @@
       stepListView:
         stepListViewHeight: atom.config.get 'impress.stepListViewHeight'
     for projPath of @resolvedConfigs
-      @resolvedConfigs[projPath] = $.extend true, {}, @globalConfig, localConf
+      @resolvedConfigs[projPath] =
+        $.extend true, {}, @globalConfig, @localConfigs[projPath]

   _deleteUnneededConfigs: (currentProjPaths) ->
     removedProjPaths = []


fix modes in history

fix modes in history

--- lib/console/console.coffee
+++ lib/console/console.coffee
@@ -169,6 +169,7 @@
       return mode if mode.prefix is prefix or mode.prefix is prefix

   setMode: (item, mode = @defaultMode()) ->
+    mode = @getMode mode
     item.mode = mode
     item.icon = mode.icon or 'chevron-right'
     item.grammar = mode.grammar
@@ -196,26 +197,24 @@
   # History

   logInput: ->
-    ed = @getInput().view.getModel()
-    input = ed.getText()
-    mode = ed.inkConsoleMode
+    {editor, mode} = @getInput()
     @history.push
-      input: input
+      input: editor.getText()
       mode: mode?.name

   moveHistory: (up) ->
-    ed = @getInput().view.getModel()
-    if ed.getText() or not @prefix?
-      pos = ed.getCursorBufferPosition()
-      text = ed.getTextInRange [[0,0], pos]
+    {editor} = @getInput()
+    if editor.getText() or not @prefix?
+      pos = editor.getCursorBufferPosition()
+      text = editor.getTextInRange [[0,0], pos]
       @prefix = {pos, text}
     next = if up
       @history.getPrevious @prefix.text
     else
       @history.getNext @prefix.text
-    ed.setText next.input
-    # @setMode @view.getInput(), next.mode
-    ed.setCursorBufferPosition @prefix.pos or [0, 0]
+    editor.setText next.input
+    @setMode @getInput(), next.mode
+    editor.setCursorBufferPosition @prefix.pos or [0, 0]

   previous: -> @moveHistory true
   next: -> @moveHistory false


remove check for multiple callbacks

remove check for multiple callbacks

--- types/button.coffee
+++ types/button.coffee
@@ -4,12 +4,6 @@
     tooltip: button.tooltip
     iconset: button.iconset
     priority: button.priority or 45
-
-  if Array.isArray button.callback
-    options.callback = (_, target) ->
-      for callback in button.callback
-        atom.commands.dispatch target, callback
-  else
-    options.callback = button.callback
+    callback: button.callback

   return toolBar.addButton options


:lipstick:

:lipstick:

--- lib/operation-stack.coffee
+++ lib/operation-stack.coffee
@@ -55,7 +55,7 @@
     for cursor in @vimState.editor.getCursors()
       @vimState.ensureCursorIsWithinLine(cursor)

-  inspectStack: ->
+  inspect: ->
     debug "  [@stack] size: #{@stack.length}"
     for op, i in @stack
       debug "  <idx: #{i}>"
@@ -74,12 +74,12 @@

     unless @peekTop().isComplete()
       if @vimState.isNormalMode() and @peekTop().isOperator?()
-        @inspectStack()
-        debug "-> @process(): return. activate: operator-pending-mode"
+        @inspect()
+        debug "-> @process(): return. activating: operator-pending-mode"
         @vimState.activateOperatorPendingMode()
       return

-    @inspectStack()
+    @inspect()
     debug "-> @pop()"
     operation = @pop()
     debug "  - popped = <#{operation.getKind()}>"
@@ -90,20 +90,20 @@
         @peekTop().compose(operation)
         debug "-> @process(): recursive"
         @process()
-      catch e
-        if e.isOperatorError?() or e.isMotionError?()
+      catch error
+        if error.isOperatorError?() or error.isMotionError?()
           @vimState.resetNormalMode()
         else
-          throw e
+          throw error
     else
       @vimState.history.unshift(operation) if operation.isRecordable()
-      unless operation.isPure()
+      if operation.isPure()
+        null # Something new way of execution.
+      else
         debug " -> <#{operation.getKind()}>.execute()"
         operation.execute()
         @vimState.counter.reset()
         debug "#=== Finish at #{new Date().toISOString()}\n"
-      else
-        null # Something new way of execution.

   # Private: Fetches the last operation.
   #


UI-related Refactor

UI-related Refactor

- Just change `@dom.style` when updating the module
- Return back `Disposable` to `status-bar` package
- Tweak `priority`

--- lib/runtime/modules.coffee
+++ lib/runtime/modules.coffee
@@ -1,6 +1,6 @@
 # TODO: this code is awful, refactor

-{CompositeDisposable, Emitter} = require 'atom'
+{CompositeDisposable, Disposable, Emitter} = require 'atom'
 {debounce} = require 'underscore-plus'

 {client} = require '../connection'
@@ -18,8 +18,6 @@
     @subs.add atom.workspace.observeActivePaneItem (item) => @updateForItem item
     @subs.add client.onAttached => @updateForItem()
     @subs.add client.onDetached => @updateForItem()
-
-    @activateView()

   deactivate: ->
     @subs.dispose()
@@ -132,15 +130,24 @@
     atom.tooltips.add @dom,
       title: => "Currently working in module #{@current()}"

+    # @NOTE: Grammar selector has `priority` 10 and thus set the it to a bit lower
+    #        than that to avoid collision that may cause unexpected result.
+    @tile = @statusBar.addRightTile item: @dom, priority: 5
+    disposable = new Disposable(=>
+      @tile.destroy()
+      delete @tile)
+    @subs.add(disposable)
+    disposable
+
   updateView: (m) ->
+    return unless @tile?
     if not m?
-      @tile?.destroy()
-      delete @tile
+      @dom.style.display = 'none'
     else
       {main, sub, inactive, subInactive} = m
       if main is @follow
         return @updateView @lastEditorModule
-      @tile ?= @statusBar?.addRightTile item: @dom, priority: 10
+      @dom.style.display = ''
       @mainView.innerText = main or 'Main'
       if sub
         @subView.innerText = sub
@@ -159,4 +166,6 @@

   consumeStatusBar: (bar) ->
     @statusBar = bar
+    disposable = @activateView()
     @updateView @_current
+    disposable


Refactors:

Refactors:

- Rename `getEditorModule` -> `setEditorModule`
- Make `getEditorModule` function so that it accepts `bufferPosition`
optional argument

--- lib/runtime/modules.coffee
+++ lib/runtime/modules.coffee
@@ -89,25 +89,32 @@

   updateForEditor: (editor) ->
     @setCurrent main: editor.juliaModule or 'Main', true
-    @getEditorModule editor
+    @setEditorModule editor
     @itemSubs.add editor.onDidChangeCursorPosition =>
-      @getEditorModuleLazy editor
+      @setEditorModuleLazy editor

-  getEditorModule: (ed) ->
+  getEditorModule: (ed, bufferPosition = null) ->
     return unless client.isActive()
-    sels = ed.getSelections()
-    {row, column} = sels[sels.length - 1].getBufferRange().end
+    if bufferPosition
+      {row, column} = bufferPosition
+    else
+      sels = ed.getSelections()
+      {row, column} = sels[sels.length - 1].getBufferRange().end
     data =
       path: client.editorPath(ed)
       code: ed.getText()
       row: row+1, column: column+1
       module: ed.juliaModule
+    getmodule(data)

-    getmodule(data).then (mod) =>
+  setEditorModule: (ed) ->
+    modulePromise = @getEditorModule ed
+    return unless modulePromise
+    modulePromise.then (mod) =>
       if atom.workspace.getActivePaneItem() is ed
         @setCurrent mod, true

-  getEditorModuleLazy: debounce ((ed) -> @getEditorModule(ed)), 100
+  setEditorModuleLazy: debounce ((ed) -> @setEditorModule(ed)), 100

   # The View


AppDetails: use master as a default branch if last commitId is not provided

--- client/Social/Apps/Views/appdetailsview.coffee
+++ client/Social/Apps/Views/appdetailsview.coffee
@@ -114,7 +114,7 @@
       {repository} = app.manifest
       repoUrl   = repository.replace /^git\:\/\//, 'https://'
       proxyUrl  = repository.replace /^git\:\/\/github.com/, KD.config.appsUri
-      baseUrl   = "#{proxyUrl}/#{app.manifest.commitId}"
+      baseUrl   = "#{proxyUrl}/#{app.manifest.commitId or 'master'}"
       readmeUrl = "#{baseUrl}/README.md"

       @githubMenu = new KDButtonViewWithMenu
@@ -124,7 +124,7 @@
         menu           :
           Repository   : link : repoUrl
           Issues       : link : "#{repoUrl}/issues"
-          Commits      : link : "#{repoUrl}/commits/#{app.manifest.commitId}"
+          Commits      : link : "#{repoUrl}/commits/#{app.manifest.commitId or 'master'}"
           Wiki         : link : "#{repoUrl}/wiki"

       # TODO: Implement clone app ~ GG


video: don't listen participant dom destroy event

--- client/app/lib/videocollaboration/model.coffee
+++ client/app/lib/videocollaboration/model.coffee
@@ -115,12 +115,9 @@
       nick       = stream.name
       element    = @getView().getElement()

+      { connectionId } = stream.connection
+
       subscriber = session.subscribe stream, element, options
-      subscriber.on 'destroyed', =>
-        @unregisterSubscriber connectionId
-        @emit 'ParticipantLeft', { nick }
-
-      { connectionId } = stream.connection
       participant = @registerSubscriber nick, connectionId, subscriber

       @emit 'ParticipantJoined', participant


remove log

remove log

--- app/server/server.coffee
+++ app/server/server.coffee
@@ -19,7 +19,6 @@
 app.use express.cookieParser("34ycn278gybvjnxszewufnv40ty9yghvhzpkdoqwjeimox")
 app.use express.session()
 app.use app.router
-console.log(path.join(__dirname, "../../public"))
 app.use require("less-middleware")(src: path.join(root, "public"))
 app.use express.static(path.join(root, "public"))

@@ -38,4 +37,4 @@
     console.log(data)

 server.listen app.get("port"), ->
-  console.log "Express server listening on port " + app.get("port")+  console.log "Express server listening on port " + app.get("port")


act cache wip

act cache wip

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -79,30 +79,22 @@

     if @getFilter() isnt activityTypes

-      options       =
-        limit       : 20
-        to          : options.to or Date.now()
-        facets      : @getFilter()
-        sort        :
-          createdAt : -1
-
-      log "ever here", options
-      KD.remote.api.CActivity.fetchFacets options, (err, activities) =>
+      options = to : options.to or Date.now()
+
+      @fetchActivity options, (err, teasers)=>
         if err then warn err
         else
-          activities = clearQuotes activities
-          KD.remote.reviveFromSnapshots activities, (err, teasers)=>
-            isLoading = no
-            @listController.listActivities teasers
-            @listController.hideLazyLoader()
+          isLoading = no
+          @listController.listActivities teasers
+          @listController.hideLazyLoader()

     else
       @fetchCachedActivity options, (err, cache)=>
         if err then warn err
         else
           @sanitizeCache cache, (err, cache)=>
+            @listController.listActivitiesFromCache cache
             isLoading = no
-            @listController.listActivitiesFromCache cache
             @listController.hideLazyLoader()

@@ -112,6 +104,18 @@
       activity.snapshot = activity.snapshot?.replace /"/g, '"'
       activity

+  isExempt = (callback)->
+
+    appManager.fetchStorage 'Activity', '1.0', (err, storage) =>
+      if err
+        log 'error fetching app storage', err
+        callback no
+      else
+        flags = KD.whoami().globalFlags
+        exempt = flags?.indexOf 'exempt'
+        exempt = (exempt? and ~exempt) or storage.getAt 'bucket.showLowQualityContent'
+        callback exempt
+
   sanitizeCache:(cache, callback)->

     activities = clearQuotes cache.activities
@@ -124,7 +128,26 @@

       callback null, cache

-
+  fetchActivity:(options = {}, callback)->
+
+    isLoading = yes
+    @listController.showLazyLoader()
+    @listController.noActivityItem.hide()
+
+    isExempt (exempt)=>
+      options       =
+        limit       : options.limit  or 20
+        to          : options.to     or Date.now()
+        facets      : options.facets or @getFilter()
+        lowQuality  : exempt
+        sort        :
+          createdAt : -1
+
+      KD.remote.api.CActivity.fetchFacets options, (err, activities) =>
+        if err then callback err
+        else
+          activities = clearQuotes activities
+          KD.remote.reviveFromSnapshots activities, callback

   fetchCachedActivity:(options = {}, callback)->
@@ -141,6 +164,7 @@
         @listController.hideLazyLoader()
         if cache?.length is 0
           @listController.noActivityItem.show()
+          isLoading = no
           return

         cache.overview.reverse()


tweak

tweak

--- client/views/questions/questions_answer.coffee
+++ client/views/questions/questions_answer.coffee
@@ -291,12 +291,11 @@
 	options = { questionId: QuestionList.currentId() }
 	Meteor.call 'viewQuestion', options

-	wait 1500, =>
-		$(window).resize =>
-			$iframe = $(@find('iframe'))
-			width = $(@find('#embed-html')).innerWidth()
-			resizeIframe($iframe, width)
-		$(window).resize()
+	$(window).resize =>
+		$iframe = $(@find('iframe'))
+		width = $(@find('#embed-html')).innerWidth()
+		resizeIframe($iframe, width)
+	$(window).resize()

 	if not Meteor.userId() or currentUserHasAnswered(QuestionList.currentId())
 		# Append D3 graph


thatをthisに置き換え

thatをthisに置き換え

--- public/coffee/gdrive.coffee
+++ public/coffee/gdrive.coffee
@@ -88,30 +88,29 @@
     this.set("client_id", this.gdrive.CLIENT_ID)

   authorize: ()->
-    that = this
-    return new Promise((resolve, reject) ->
+    return new Promise((resolve, reject) =>
       reject(null) unless gapi.auth

       gapi.auth.authorize({
-        'client_id': that.gdrive.CLIENT_ID,
-        'scope': that.gdrive.SCOPES,
+        'client_id': this.gdrive.CLIENT_ID,
+        'scope': this.gdrive.SCOPES,
         'immediate': true },
-        (authResult)->
+        (authResult) =>
           # immediate: trueが失敗したときはflaseで再チャレンジ
           # 今度はダイアログが開く
           if (authResult && !authResult.error)
             console.log("immediate true")
-            that.set("access_token", authResult.access_token)
+            this.set("access_token", authResult.access_token)
             resolve(authResult)
           else
             console.log("immediate false")
             gapi.auth.authorize({
-              'client_id': that.gdrive.CLIENT_ID,
-              'scope': that.gdrive.SCOPES,
+              'client_id': this.gdrive.CLIENT_ID,
+              'scope': this.gdrive.SCOPES,
               'immediate': false },
-              (authResult)->
+              (authResult) =>
                 if (authResult && !authResult.error)
-                  that.set("access_token", authResult.access_token)
+                  this.set("access_token", authResult.access_token)
                   resolve(authResult)
                 else
                   console.log("authorize failed")
@@ -121,19 +120,18 @@
     )

   fetchFile: (fileId) ->
-    that = this
-    return new Promise((resolve, reject) ->
-      that.gdrive.get(fileId)
-        .then (file) ->
-          that.set("file", file)
-          that.set('title', file.title)
-
-          that.gdrive.getFileResource(
+    return new Promise((resolve, reject) =>
+      this.gdrive.get(fileId)
+        .then (file) =>
+          this.set("file", file)
+          this.set('title', file.title)
+
+          this.gdrive.getFileResource(
             file.downloadUrl,
-            that.get('access_token')
+            this.get('access_token')
           )
-        .then (fileContent) ->
-          that.set('content', fileContent)
+        .then (fileContent) =>
+          this.set('content', fileContent)
           resolve(fileContent)
       )

@@ -148,25 +146,23 @@
       return Promise.resolve('insert')

   insert: (title, content) ->
-    that = this
     gapi.client.load('drive', 'v2')
-      .then () -> that.gdrive.insert(title, content)
-      .then (response) ->
+      .then () => this.gdrive.insert(title, content)
+      .then (response) =>
         console.log("insert file")
         console.log(response.result)
-        that.set("file", response.result)
+        this.set("file", response.result)

         Promise.resolve(response.result)

   update: (title, content) ->
-    that = this
-    fileId = that.get('file').id
+    fileId = this.get('file').id
     gapi.client.load('drive', 'v2')
-      .then () -> that.gdrive.update(fileId, title, content)
-      .then (response) ->
+      .then () => this.gdrive.update(fileId, title, content)
+      .then (response) =>
         console.log("update file")
         console.log(response.result)
-        that.set("file", response.result)
+        this.set("file", response.result)

         Promise.resolve(response.result)
 })
@@ -211,9 +207,8 @@
       documentLink.removeClass("text-muted").addClass("text-primary")

   showPicker: ()->
-    that = this
-    client_id = that.model.get('client_id')
-    access_token = that.model.get("access_token")
+    client_id = this.model.get('client_id')
+    access_token = this.model.get("access_token")
     if access_token
       view = new google.picker.View(google.picker.ViewId.DOCS)
       # 現状何かエラー出ているけど一応使えるのでとりあえず放置


Add mean time to results

Add mean time to results

--- assets/inspector/benchmark_panel_view.coffee
+++ assets/inspector/benchmark_panel_view.coffee
@@ -28,8 +28,10 @@
       input.disabled = true for input in @getInputElements()

     suite.on "cycle", (event) =>
-      element = @getBenchmarkElement(event.target.name)
-      element.querySelector(".results").textContent = "↳ #{event.target.toString()}"
+      benchmark = event.target
+      mean = (benchmark.stats.mean * 1000).toFixed(3)
+      element = @getBenchmarkElement(benchmark.name)
+      element.querySelector(".results").textContent = "↳ Mean: #{mean}ms; #{benchmark}"

     suite.on "complete", =>
       input.disabled = false for input in @getInputElements()


input: better resize notch redraw handling

--- input/index.coffee
+++ input/index.coffee
@@ -70,13 +70,11 @@

   # https://github.com/material-components/material-components-web/blob/master/packages/mdc-notched-outline/foundation.js
   setNotchWidth: (notchWidth) =>
+    unless @$$el?
+      return
+
     prevNotchWidth = @notchWidth
     @notchWidth = notchWidth
-    if prevNotchWidth is notchWidth and @d isnt ''
-      return
-
-    unless @$$el?
-      throw new Error 'Component not yet mounted'

     $$large = @$$el.querySelector '.zp-input_notched-outline > svg > .large'
     $$small = @$$el.querySelector '.zp-input_notched-outline > svg > .small'


Bookmark traversal fixes. Changes:   - use natural order for bookmark traversal   - eliminate use of O(N^2) `shift`

--- background_scripts/completion.coffee
+++ background_scripts/completion.coffee
@@ -112,11 +112,11 @@
   # Traverses the bookmark hierarchy, and retuns a flattened list of all bookmarks in the tree.
   traverseBookmarks: (bookmarks) ->
     results = []
-    toVisit = bookmarks
+    toVisit = bookmarks.reverse()
     while toVisit.length > 0
-      bookmark = toVisit.shift()
+      bookmark = toVisit.pop()
       results.push(bookmark)
-      toVisit.push.apply(toVisit, bookmark.children) if (bookmark.children)
+      toVisit.push.apply(toVisit, bookmark.children.reverse()) if (bookmark.children)
     results

   computeRelevancy: (suggestion) ->


Add comment explaining why we use try/catch.

--- background_scripts/completion.coffee
+++ background_scripts/completion.coffee
@@ -235,13 +235,14 @@
           []
       onComplete results.map (entry) =>
         # If this history URL starts with the search URL, we reconstruct the original search terms, and insert
-        # them into the vomnibar when this suggestion is selected.
+        # them into the vomnibar when this suggestion is selected.  We use try/catch because
+        # decodeURIComponent() throw an error.
         insertText =
-          if entry.url.startsWith searchUrl
-            try
+          try
+            if entry.url.startsWith searchUrl
               entry.url[searchUrl.length..].split(searchUrlTerminator)[0].split("+").map(decodeURIComponent).join " "
-            catch
-              null
+          catch
+            null

         new Suggestion
           queryTerms: queryTerms


minor formatting

minor formatting

--- library/membrane/remote.coffee
+++ library/membrane/remote.coffee
@@ -69,10 +69,11 @@
     wrongCompiled = "using external with classes"
     assert.ok _.isFunction(compiled), notFunction
     assert not compiled.__super__?, wrongCompiled
+    assert _.isFunction fm = _.sprintf # shortcut
     pn = (df) -> ("#{glb} = #{v};" for glb, v of df)
     pv = (df) -> ("var #{k} = #{v};" for k, v of df)
     ds = (long, short) -> pn(long).concat(pv(short))
-    tabled = (f) -> (s) -> _.sprintf wrap, ds(f,s).join ";"
+    tabled = (f) -> (s) -> fm wrap, ds(f,s).join ";"
     wrap = "function() { %s \n\treturn #{compiled}}"
     assert compiled.remote = Object.create {}
     assert compiled.remote.compiled = compiled


more flexible signature

more flexible signature

--- library/nucleus/restful.coffee
+++ library/nucleus/restful.coffee
@@ -107,7 +107,7 @@
     # under the shadow of the real service instance. The process is
     # idempotent. Please refer to the implementation of this method
     # and to the implementation of the `Duplex` for the information.
-    @spinoff: (implement) -> (req, res, rs, dm) ->
+    @spinoff: (implement) -> (req, res, trailings...) ->
         message = "Spinned off HTTP request at %s"
         noImplement = "no valid implementation body"
         assert _.isFunction(implement), noImplement
@@ -118,7 +118,6 @@
         assert _.isObject request.shadow = shadow
         _.extend shadow, response: weak(res) or res
         _.extend shadow, request: weak(req) or req
-        _.extend shadow, resources: rs, domains: dm
         s = get: -> try request.session or undefined
         e = get: -> try request.entity or undefined
         logger.debug message.grey, req.url.toString()


fixes

fixes

--- app/client/kanban.coffee
+++ app/client/kanban.coffee
@@ -6,7 +6,7 @@
 	return '' if not user

 	key = 'fogbugz-users'
-	users = UserSession.get key || []
+	users = UserSession.get(key) || []

 	if not users.length
 		Meteor.call 'fetch_users', Meteor.userId(), (err, res) ->
@@ -16,4 +16,4 @@
 	found = _.find users, (it) ->
 		it.id == user.id or it.name == user.name

-	found.email || ''
+	if found then found.email || '' else ''


Improved logging.

Improved logging.

--- src/EntityImporter.coffee
+++ src/EntityImporter.coffee
@@ -63,7 +63,7 @@
     return if isImportCancelled(importId)
     c3mls = args.c3mls
     unless Types.isArray(c3mls)
-      return Q.reject('C3ML not defined as an array.')
+      return Q.reject('"c3mls" must be an array.')

     Logger.info 'Importing entities from', c3mls.length, 'c3mls...'
     if Meteor.isServer then FileLogger.log(args)
@@ -439,7 +439,7 @@
             if entityStr.length > CONSOLE_LOG_SIZE_LIMIT && Meteor.isServer
               FileLogger.log(entityStr)
             else
-              Logger.debug('Failed entity', entityStr)
+              Logger.debug('Failed entity insert', entityStr.slice(0, 100) + '...')
           catch e
             Logger.error('Failed to log entity insert failure', e)
           modelDf.reject(err)


Add more tests

Add more tests

--- spec/parser.spec.coffee
+++ spec/parser.spec.coffee
@@ -76,6 +76,14 @@
     expect(parser.replaceFromToBlocks text).
       toEqual "On 01/01/2015, a@b.com wrote:\n\n"

+    text = "From: a@b.com\nTo: b@c.com\nDate: 01/01/2015\nSubject: Something\nHi there,"
+    expect(parser.replaceFromToBlocks text).
+      toEqual "On 01/01/2015, a@b.com wrote:\n\nHi there,"
+
+    text = "From: a@b.com\nTo: b@c.com\nSubject: Something\nDate: 01/01/2015\n Hi there,"
+    expect(parser.replaceFromToBlocks text).
+      toEqual "On 01/01/2015, a@b.com wrote:\n\n Hi there,"
+
     text = "From: a@b.com\nTo: b@c.com\nSubject: Something\nDate: 01/01/2015\nCc: c@d.com\n"
     expect(parser.replaceFromToBlocks text).
       toEqual "On 01/01/2015, a@b.com wrote:\n\n"


Atom tweaking config formatting

Atom tweaking config formatting

Former-commit-id: ede83f4b2a9982f65d7417041e6f806f58ec7725

--- Libraries/Atom/Config/config.cson
+++ Libraries/Atom/Config/config.cson
@@ -4,8 +4,7 @@
     showInvisibles: true
     showIndentGuide: true
     tabLength: 4
-    invisibles:
-      {}
+    invisibles: {}
     zoomFontWhenCtrlScrolling: false
   core:
     excludeVcsIgnoredPaths: false
@@ -39,10 +38,8 @@
     userId: "0392dc6d-c14b-47e0-91c5-f2afa5f389bd"
   welcome:
     showOnStartup: false
-  "spell-check":
-    {}
-  "markdown-preview":
-    {}
+  "spell-check": {}
+  "markdown-preview": {}
   "autocomplete-plus":
     confirmCompletion: "tab and enter"
   "file-icons":
@@ -53,8 +50,7 @@
     bytesPerLine: 32
   "filetype-color":
     enabled: "true"
-  "bracket-matcher":
-    {}
+  "bracket-matcher": {}
   "fuzzy-finder":
     searchAllPanes: true
   "git-diff":
@@ -62,12 +58,10 @@
   tabs:
     tabScrolling: true
     usePreviewTabs: true
-  "one-dark-ui":
-    {}
+  "one-dark-ui": {}
   "view-tail-large-files":
     fontFamily: "Consolas"
   minimap:
     displayPluginsControls: false
     displayCodeHighlights: false
-  "status-bar":
-    {}
+  "status-bar": {}


cs-field types have been ordered alphabetically

--- src/components/cs-field/cs-field.js.coffee
+++ src/components/cs-field/cs-field.js.coffee
@@ -34,25 +34,21 @@

     # ===== COMPILE DOM WITH APPROPRIATE DIRECTIVE ========

-    $scope.csFieldOptions.layout =
-      alignment : 'horizontal'
-      fieldType : 'view'
-
     if override = getDirectiveOverride($scope)
       directiveName = override
     else
       type = $scope.field.type

       directiveName = switch
+        when type == 'boolean'  then 'cs-checkbox'
+        when type == 'date'     then 'cs-date'
+        when type == 'datetime' then 'cs-datetime'
+        when type == 'enum'     then 'cs-enum'
+        when type == 'integer'  then 'cs-number'
+        when type == 'float'    then 'cs-number'
         when type == 'resource' then 'cs-resource-input'
         when type == 'string'   then 'cs-textfield'
-        when type == 'date'     then 'cs-date'
         when type == 'time'     then 'cs-time'
-        when type == 'datetime' then 'cs-datetime'
-        when type == 'integer'  then 'cs-number'
-        when type == 'float'    then 'cs-number'
-        when type == 'enum'     then 'cs-enum'
-        when type == 'boolean'  then 'cs-checkbox'

     wrapperName = ".cs-input-wrapper"
     inputTemplate = "<#{directiveName} form-item='formItem'
@@ -62,8 +58,6 @@
                                        create-resources='createResources()'
                                        options='csFieldOptions'>
                      </#{directiveName}>"
-
-

     innerElement = angular.element(element[0].querySelector(wrapperName))
     innerElement.append($compile(inputTemplate)($scope))
@@ -100,6 +94,12 @@
           star : "hidden",
           container : "container-horizontal",
           field1 : "field-1-horizontal",
+          field2 : "field-2-horizontal"
+      when "tableView"
+      	styleMap =
+          star : "hidden",
+          container : "container-horizontal",
+          field1 : "hidden",
           field2 : "field-2-horizontal"

     $scope.styleMap = styleMap


Fix styling, update comments, localhost remapping

--- js/ZeroChat.coffee
+++ js/ZeroChat.coffee
@@ -79,19 +79,19 @@

     replaceURLs: (body) ->
         # // REGEXES
-        replacePattern0 = /(http:\/\/127.0.0.1:43110\/)/gi
+        replacePattern0 = /(https?:\/\/(127.0.0.1|localhost):43110\/)/gi
         replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim
         replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim
         replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim
         replacePattern4 = /0net:\/\/([-a-zA-Z0-9+&.,:+_\/=?]*)/g
-        replacePattern5 = /(([a-zA-Z0-9\-\_\.])+)\/\/0mail/gim;
+        replacePattern5 = /(([a-zA-Z0-9\-\_\.])+)\/\/0mail/gim

-        # // url rewriting 127.0.0.1:43110 to 0net:// so other replacements don't break
+        # // url rewriting 127.0.0.1:43110 to 0net:// so other replacements don't break and localhost:43110 to 0net:// so they aren't scheme://ip:port dependent
         replacedText = body.replace(replacePattern0, '0net://')
         replacedText = replacedText.replace('@zeroid.bit', '//0mail')

         # // URLs starting with http://, https://, or ftp://
-        replacedText = replacedText.replace(replacePattern1, '$1');
+        replacedText = replacedText.replace(replacePattern1, '$1')

         # // URLs starting with "www." (without // before it, or it'd re-link the ones done above).
         replacedText = replacedText.replace(replacePattern2, '$1$2')
@@ -99,10 +99,10 @@
         # // Change email addresses to mailto:: links.
         replacedText = replacedText.replace(replacePattern3, '$1')

-        # // replace 0net:// URL href back to http://127.0.0.1:43110
+        # // remove 0net:// prefix in URL href
         replacedText = replacedText.replace(replacePattern4, '0net://$1')

-        # // rewrite link href and replace //0mail with @zeroid.bit
+        # // rewrite 0net:// prefix in URL href and replace //0mail with @zeroid.bit
         replacedText = replacedText.replace(replacePattern5, '$1@zeroid.bit')

         return replacedText
@@ -139,7 +139,7 @@
                 body = @replaceURLs(body)

                 # // REPLACE IRC
-                if body.substr(0,3) == "/me"
+                if body.substr(0, 3) == "/me"
                     action = body.replace("/me","")
                     username = username+' '+action
                     body = ''


some instrumentation for solver

some instrumentation for solver

--- bokehjs/src/coffee/core/layout/solver.coffee
+++ bokehjs/src/coffee/core/layout/solver.coffee
@@ -14,7 +14,10 @@
 class Solver

   constructor: () ->
+    @num_constraints = 0
     @solver = new kiwi.Solver()
+
+  toString: () -> "Solver[num_constraints=#{@num_constraints}]"

   update_variables: (trigger=true) ->
     @solver.updateVariables()
@@ -22,13 +25,20 @@
       @trigger('layout_update')

   add_constraint: (constraint) ->
+    @num_constraints += 1
     @solver.addConstraint(constraint)

   remove_constraint: (constraint) ->
+    @num_constraints -= 1
     @solver.removeConstraint(constraint)

   add_edit_variable: (variable, strength=Strength.strong) ->
+    @num_constraints += 1
     @solver.addEditVariable(variable, strength)
+
+  remove_edit_variable: (variable) ->
+    @num_constraints -= 1
+    @solver.removeEditVariable(variable, strength)

   suggest_value: (variable, value) ->
     @solver.suggestValue(variable, value)


Updated menu cson for atom update

Updated menu cson for atom update

--- menus/atom-copy-on-select.cson
+++ menus/atom-copy-on-select.cson
@@ -1,7 +1,10 @@
 # # See https://atom.io/docs/latest/creating-a-package#menus for more details
 'context-menu':
   '.overlayer':
-      'Enable atom-copy-on-select': 'atom-copy-on-select:toggle'
+    [{
+      label: 'Enable atom-copy-on-select',
+      command: 'atom-copy-on-select:toggle'
+    }]

 'menu': [
   {


renamed method to make more exclusive

renamed method to make more exclusive

--- core/app/backbone/factlink/popover_view.coffee
+++ core/app/backbone/factlink/popover_view.coffee
@@ -6,7 +6,7 @@
       throw "PopoverView needs a popover property"

     @bindPopover()
-    @on "render", @realOnRender, this
+    @on "render", @popoverOnRender, this

   bindPopover: ->
     @$el.on "click.popover", @popover.selector, =>
@@ -14,7 +14,7 @@
     @$el.on "click.popover_menu", @popover.popoverSelector, (e) ->
       e.stopPropagation()

-  realOnRender: ->
+  popoverOnRender: ->
     if @$(@popover.popoverSelector).children("li").length <= 0
       @$(@popover.selector).hide()


defined on view when a fact is visible

defined on view when a fact is visible

Previously we used when one of it's parts was visible, which is less accurate.

--- app/js/views/fact.coffee
+++ app/js/views/fact.coffee
@@ -63,13 +63,16 @@
     @show_button.destroy()

 class FactPromotion
-  constructor: (elements) ->
-    @highlighter = new Highlighter $(elements), 'fl-highlight'
+  constructor: (@fact) ->
+    @highlighter = new Highlighter $(fact.elements), 'fl-highlight'

     @highlight_temporary highlight_time_on_load_and_creation

-    $(elements).on 'inview', (event, isInView, visiblePart) =>
-      @highlight_temporary(highlight_time_on_in_view) if ( isInView && visiblePart == 'both' )
+    $(fact.elements).on 'inview', @onVisibilityChanged
+
+  onVisibilityChanged: =>
+    if @fact.isInView()
+      @highlight_temporary(highlight_time_on_in_view)

   highlight_temporary: (duration) ->
     @highlighter.highlight()
@@ -79,8 +82,13 @@
   constructor: (@id, @elements) ->
     @fact_interaction = new FactInteraction @elements, @id,
       on_click: @openFactlinkModal
-    @fact_promotion = new FactPromotion(@elements)
+    @fact_promotion = new FactPromotion(this)

+  isInView: ->
+    all = true
+    $(@elements).each ->
+      all = all & ($(this).data('inview') == 'both')
+    all

   openFactlinkModal: (options={})=>
     Factlink.showInfo @id, => options.success?()


Reuse git instance unless editor path changes

--- src/app/status-bar.coffee
+++ src/app/status-bar.coffee
@@ -29,6 +29,8 @@
           @span class: 'branch-label', outlet: 'branchLabel'
         @span outlet: 'cursorPosition'

+  git: null
+
   initialize: (@rootView, @editor) ->
     @updatePathText()
     @editor.on 'editor-path-change', =>
@@ -43,6 +45,8 @@
   subscribeToBuffer: ->
     @buffer?.off '.status-bar'
     @buffer = @editor.getBuffer()
+    if path = @editor.getPath()
+      @git = new Git(path)
     @buffer.on 'change.status-bar', => _.delay (=> @updateBufferModifiedText()), 50
     @buffer.on 'after-save.status-bar', => _.delay (=> @updateStatusBar()), 50
     @updateStatusBar()
@@ -63,7 +67,7 @@
     @branchArea.hide()
     return unless path

-    head = new Git(path).getShortHead()
+    head = @git.getShortHead()
     @branchLabel.text(head)
     @branchArea.show() if head

@@ -72,10 +76,9 @@
     @gitStatusIcon.empty()
     return unless path

-    git = new Git(path)
-    if git.isPathModified(path)
+    if @git.isPathModified(path)
       @gitStatusIcon.append $$ -> @span '\uf26d', class: 'modified-status-icon'
-    else if git.isPathNew(path)
+    else if @git.isPathNew(path)
       @gitStatusIcon.append $$ -> @span '\uf26b', class: 'new-status-icon'


items should always exist

items should always exist

--- src/collectionView.coffee
+++ src/collectionView.coffee
@@ -13,7 +13,9 @@
             model: m
             key: m.id
       @forceUpdate()
+
     componentWillMount: ->
+      @items ?= []
       unless @collection?
         ctor = createCollection config.model
         @collection = new ctor


add error event for copy

add error event for copy

--- src/compilers/copy.coffee
+++ src/compilers/copy.coffee
@@ -37,6 +37,7 @@
                 readable = fs.createReadStream src
                 writable = fs.createWriteStream dst
                 readable.pipe writable
+                writable.on 'error', done
                 writable.on 'finish', done
                 return
             return


Fix active panel's z-index

Fix active panel's z-index

--- src/components/panel.cjsx
+++ src/components/panel.cjsx
@@ -41,7 +41,7 @@
       zIndex: -1

     if @state.selected
-      style.zIndex = 0
+      style.zIndex = "auto"

     style


Remove exceptions related to unassigned lineHeight

These exceptions break specs when simulateDomAttachment is used. They
were only present to ensure correct sequencing during development of the
react editor, so it's safe to remove them for now.

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -228,8 +228,7 @@
     @charWidthsByScope = {}

   getScrollHeight: ->
-    unless @getLineHeightInPixels() > 0
-      throw new Error("You must assign lineHeightInPixels before calling ::getScrollHeight()")
+    return 0 unless @getLineHeightInPixels() > 0

     @getLineCount() * @getLineHeightInPixels()

@@ -237,8 +236,7 @@
     (@getMaxLineLength() * @getDefaultCharWidth()) + @getCursorWidth()

   getVisibleRowRange: ->
-    unless @getLineHeightInPixels() > 0
-      throw new Error("You must assign a non-zero lineHeightInPixels before calling ::getVisibleRowRange()")
+    return [0, 0] unless @getLineHeightInPixels() > 0

     heightInLines = Math.ceil(@getHeight() / @getLineHeightInPixels()) + 1
     startRow = Math.floor(@getScrollTop() / @getLineHeightInPixels())


JDomain: cleanup

JDomain: cleanup

--- workers/social/lib/social/models/domain.coffee
+++ workers/social/lib/social/models/domain.coffee
@@ -109,6 +109,7 @@
       isGroupAlias      = re.test domain
       not isVmAlias and not isKodingSubdomain and isGroupAlias

+
   @fetchDomains: secure (client, callback)->

     {group} = client.context
@@ -119,6 +120,7 @@
       return callback null unless domains
       callback null, filterDomains domains, delegate, group

+
   parseDomain = (domain)->

     # Custom error
@@ -148,9 +150,10 @@
     # Return type as internal and slug and domain
     return {type: 'internal', slug, prefix, domain}

-  resolveDomain = (domainData, callback)->
-
-    return callback null  unless domainData.domainType
+
+  resolveDomain = (domainData, callback, check)->
+
+    return callback null  unless check

     {domain} = domainData

@@ -170,7 +173,9 @@
         if (intersection baseIps, remoteIps).length > 0
           return callback null

-        callback new KodingError "CNAME or A record for #{domain} is not matching with #{baseDomain}", "CNAMEMISMATCH"
+        callback new KodingError \
+          """CNAME or A record for #{domain} is not
+             matching with #{baseDomain}""", "CNAMEMISMATCH"

   createDomain = (options, callback)->


removing unused method

removing unused method

--- methods/incidentReports.coffee
+++ methods/incidentReports.coffee
@@ -68,9 +68,6 @@

 Meteor.methods
-  getIncidentReport: (incidentId) ->
-    Incidents.findOne({_id: incidentId})
-
   addIncidentReport: (incident, updateEvent=true) ->
     incidentReportSchema.validate(incident)
     user = Meteor.user()


Logging enabled by default.

Logging enabled by default.

--- emulator/frontend/emulator.coffee
+++ emulator/frontend/emulator.coffee
@@ -1,14 +1,8 @@
 Injector = require "../core/utils/injector"
 Logger   = require "../core/utils/logger"

-isLocalhost = ->
-    url = document.URL or ""
-    for pattern in [ "file://", "localhost", "127.0.0.1" ]
-        return true if url.indexOf pattern >= 0
-    return false
-
 logger = Logger.get()
-logger.attach Logger.console() if isLocalhost()
+logger.attach Logger.console()

 ###########################################################
 # Emulator API


tests

tests

--- test/basic_usage.coffee
+++ test/basic_usage.coffee
@@ -8,7 +8,7 @@

 describe 'hbase', () ->
-	before ->
+	before () ->
 		matchesBlanket = (path) -> path.match /node_modules\/blanket/
 		runningTestCoverage = Object.keys(require.cache).filter(matchesBlanket).length > 0
 		if runningTestCoverage
@@ -16,11 +16,6 @@

 	@_timeout = config.timeout

-	tCf = 'cf1'
-	tRow = '1'
-	tCol = 'col'
-	tVal = 'val'
-

 	# create pre-splitted table with versions
 	# hbase org.apache.hadoop.hbase.util.RegionSplitter node-hbase-test-table HexStringSplit -c 10 -f cf1
@@ -29,26 +24,32 @@

 	testTable = config.testTable
 	testRows = [
-			row: '111111'
-			cf: tCf
+			row: '1'
+			cf: 'cf1'
 			col: 'col1'
 			val: 'val1'
 		,
-			row: '555555'
-			cf: tCf
+			row: '5'
+			cf: 'cf1'
 			col: 'col2'
 			val: 'val2'
 		,
-			row: '999999'
-			cf: tCf
+			row: '9'
+			cf: 'cf1'
 			col: 'col3'
 			val: 'val3'
 		,
-			row: 'aaaaaa'
-			cf: tCf
+			row: 'a'
+			cf: 'cf1'
 			col: 'col4'
 			val: 'val4'
 	]
+
+	tCf = testRows[0].cf
+	tRow = testRows[0].row
+	tCol = testRows[0].col
+	tVal = testRows[0].val
+
 	randomValue = 'lkjhgfdsa'
 	hbase = require '../index.coffee'

@@ -66,8 +67,8 @@
 		put.add cf, col, val, ts

 		client.put testTable, put, (err, res) ->
-			assert.equal err, null
-			assert.equal res.processed, yes
+			assert.equal err, null, "put returned an error: #{err}"
+			assert.equal res.processed, yes, "put wasn't processed"
 			getRow row, cf, col, val, ts, cb

 	getRow = (row, cf, col, val, ts, cb) ->
@@ -79,16 +80,16 @@
 		get.addColumn cf, col

 		client.get testTable, get, (err, res) ->
-			assert.equal err, null
-			assert.equal res.row, row
-			assert.equal res.columns[0].family.toString(), cf
-			assert.equal res.columns[0].qualifier.toString(), col
-			assert.equal res.columns[0].timestamp.toString(), ts.toString() if ts
+			assert.equal err, null, "get returned an error: #{err}"
+			assert.equal res.row, row, "rowKey doesn't match"
+			assert.equal res.columns[0].family.toString(), cf, "columnFamily doesn't match"
+			assert.equal res.columns[0].qualifier.toString(), col, "qualifier doesn't match"
+			assert.equal res.columns[0].timestamp.toString(), ts.toString(), "timestamp doesn't match" if ts

 			if typeof val is 'object'
-				assert.equal res.columns[0].value.toString(), val.toString()
+				assert.equal res.columns[0].value.toString(), val.toString(), "value doesn't match"
 			else
-				assert.equal res.columns[0].value, val
+				assert.equal res.columns[0].value, val, "value doesn't match"

 			cb null, res

@@ -96,8 +97,8 @@
 		del = new hbase.Delete row

 		client.delete testTable, del, (err, res) ->
-			assert.equal err, null
-			assert.equal res.processed, yes
+			assert.equal err, null, "delete returned an error: #{err}"
+			assert.equal res.processed, yes, "delete wasn't processed"

 			rowDoesNotExist row, cb

@@ -105,457 +106,474 @@
 		get = new hbase.Get row

 		client.get testTable, get, (err, res) ->
-			assert.equal err, null
-			assert.equal res, null
+			assert.equal err, null, "get returned an error: #{err}"
+			assert.equal res, null, "row #{row} exists"
 			cb()

-	it 'should put single row', (done) ->
-		putRow testRows[0].row, testRows[0].cf, testRows[0].col, testRows[0].val, done
-
-	it 'should get single row', (done) ->
-		getRow testRows[0].row, testRows[0].cf, testRows[0].col, testRows[0].val, done
-
-	it 'should get single row with invalid maxVersions', (done) ->
-		get = new hbase.Get testRows[0].row
-		get.setMaxVersions 0
-
-		client.get testTable, get, (err, res) ->
-			assert.equal err, null
-			assert.equal res.row, testRows[0].row
-			done()
-
-	it 'should delete row', (done) ->
-		deleteRow testRows[0].row, done
-
-	it 'should get multiple versions', (done) ->
-		tests = [
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal, () ->
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '1', () ->
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '2', () ->
-					cb()
-		,
-			(cb) ->
-				get = new hbase.Get tRow
-				get.setMaxVersions 3
-
-				client.get testTable, get, (err, row) ->
-					assert.equal err, null
-					assert.equal row.cols["#{tCf}:#{tCol}"][0].value.toString(), tVal + '2'
-					assert.equal row.cols["#{tCf}:#{tCol}"][1].value.toString(), tVal + '1'
-					assert.equal row.cols["#{tCf}:#{tCol}"][2].value.toString(), tVal
-					cb()
-		,
-			(cb) ->
+	describe 'put & mput', () ->
+		afterEach () ->
+			rows = testRows.map (row) ->
+				row.row
+
+			client.mdelete testTable, rows, () ->
+
+		it 'should put single row', (done) ->
+			putRow tRow, tCf, tCol, tVal, done
+
+		it 'should put multiple rows via simple array', (done) ->
+			puts = []
+			puts = testRows.map (row) ->
+				o =
+					row: row.row
+				o["#{row.cf}:#{row.col}"] = row.val
+				o
+
+			client.mput testTable, puts, (err, res) ->
+				assert.equal err, null, "mput returned an error: #{err}"
+				done()
+
+		it 'should put multiple rows via array of Put objects', (done) ->
+			puts = testRows.map (row) ->
+				put = new hbase.Put row.row
+				put.add row.cf, row.col, row.val
+				put
+
+			client.mput testTable, puts, (err, res) ->
+				assert.equal err, null, "mput returned an error: #{err}"
+				done()
+
+		it 'should checkAndPut', (done) ->
+			putRow tRow, tCf, tCol, tVal, () ->
+				put = new hbase.Put tRow
+				put.add tCf, tCol, randomValue
+
+				client.checkAndPut testTable, tRow, tCf, tCol, tVal, put, (err, res) ->
+					assert.equal err, null, "checkAndPut returned an error: #{err}"
+					assert.equal res.processed, yes, "checkAndPut wasn't processed"
+					getRow tRow, tCf, tCol, randomValue, done
+
+	describe 'get & mget', () ->
+		before () ->
+			puts = testRows.map (row) ->
+				put = new hbase.Put row.row
+				put.add row.cf, row.col, row.val
+				put
+
+			client.mput testTable, puts, (err, res) ->
+
+		after () ->
+			rows = testRows.map (row) ->
+				row.row
+
+			client.mdelete testTable, rows, () ->
+
+		it 'should get single row', (done) ->
+			getRow tRow, tCf, tCol, tVal, done
+
+		it 'should get single row with invalid maxVersions', (done) ->
+			get = new hbase.Get tRow
+			get.setMaxVersions 0
+
+			client.get testTable, get, (err, res) ->
+				assert.equal err, null, "get returned an error: #{err}"
+				assert.equal res.row, tRow, "rowKey doesn't match"
+				done()
+
+		it 'should get multiple rows via simple array', (done) ->
+			gets = testRows.map (row) ->
+				row.row
+
+			client.mget testTable, gets, (err, res) ->
+				assert.equal err, null, "mget returned an error: #{err}"
+				assert.equal res.length, testRows.length, "mget didn't return expected number of rows"
+				done()
+
+		it 'should get multiple rows via array of Get objects', (done) ->
+			gets = testRows.map (row) ->
+				new hbase.Get row.row
+
+			client.mget testTable, gets, (err, res) ->
+				assert.equal err, null, "mget returned an error: #{err}"
+				assert.equal res.length, testRows.length, "mget didn't return expected number of rows"
+				done()
+
+		it 'should get multiple versions', (done) ->
+			tests = [
+				(cb) ->
+					putRow tRow, tCf, tCol, tVal, cb
+				(r, cb) ->
+					putRow tRow, tCf, tCol, tVal + '1', cb
+				(r, cb) ->
+					putRow tRow, tCf, tCol, tVal + '2', cb
+				(r, cb) ->
+					get = new hbase.Get tRow
+					get.setMaxVersions 3
+
+					client.get testTable, get, (err, row) ->
+						assert.equal err, null, "get returned an error: #{err}"
+						assert.equal row.cols["#{tCf}:#{tCol}"][0].value.toString(), tVal + '2', "latest version value doesn't match"
+						assert.equal row.cols["#{tCf}:#{tCol}"][1].value.toString(), tVal + '1', "2nd latest version value doesn't match"
+						assert.equal row.cols["#{tCf}:#{tCol}"][2].value.toString(), tVal, "oldest version value doesn't match"
+						cb()
+				(cb) ->
+					del = new hbase.Delete tRow
+					del.deleteColumns tCf, tCol
+
+					client.delete testTable, del, (err, res) ->
+						assert.equal err, null, "delete returned an error: #{err}"
+						assert.equal res.processed, yes, "delete wasn't processed"
+						cb()
+				(cb) ->
+					rowDoesNotExist tRow, cb
+			]
+
+			async.waterfall tests, done
+
+		it 'should get with timeRange', (done) ->
+			ts = null
+			tests = [
+				(cb) ->
+					putRow tRow, tCf, tCol, tVal, (err, row) ->
+						ts = row.cols["#{tCf}:#{tCol}"].timestamp
+						cb()
+				(cb) ->
+					putRow tRow, tCf, tCol, tVal + '1', cb
+				(r, cb) ->
+					ts1 = ts2 = ts
+					ts1--
+					ts2++
+
+					get = new hbase.Get tRow
+					get.setTimeRange ts1, ts2
+
+					client.get testTable, get, (err, row) ->
+						assert.equal err, null, "get returned an error: #{err}"
+						assert.equal row.row, tRow, "rowKey doesn't match"
+						assert.equal row.cols["#{tCf}:#{tCol}"].value, tVal, "value doesn't match"
+						cb()
+				(cb) ->
+					deleteRow tRow, cb
+			]
+
+			async.waterfall tests, done
+
+	describe 'delete & mdelete', () ->
+		beforeEach () ->
+			puts = testRows.map (row) ->
+				put = new hbase.Put row.row
+				put.add row.cf, row.col, row.val
+				put
+
+			client.mput testTable, puts, (err, res) ->
+
+		after () ->
+			rows = testRows.map (row) ->
+				row.row
+
+			client.mdelete testTable, rows, () ->
+
+		it 'should delete row', (done) ->
+			deleteRow testRows[1].row, done
+
+		it 'should checkAndDelete row', (done) ->
+			putRow tRow, tCf, tCol, randomValue, () ->
 				del = new hbase.Delete tRow
-				del.deleteColumns tCf, tCol
-
-				client.delete testTable, del, (err, res) ->
-					assert.equal err, null
-					assert.equal res.processed, yes
-					cb()
-		,
-			(cb) ->
-				rowDoesNotExist tRow, cb
-		]
-
-		async.waterfall tests, done
-
-	it 'should get with timeRange', (done) ->
-		ts = null
-		tests = [
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal, (err, row) ->
-					ts = row.cols["#{tCf}:#{tCol}"].timestamp
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '1', () ->
-					cb()
-		,
-			(cb) ->
-				ts1 = ts
-				ts1--
-				ts2 = ts
-				ts2++
-
-				get = new hbase.Get tRow
-				get.setTimeRange ts1, ts2
-
-				client.get testTable, get, (err, row) ->
-					assert.equal err, null
-					assert.equal row.row, tRow
-					assert.equal row.cols["#{tCf}:#{tCol}"].value, tVal
-					cb()
-		,
-			(cb) ->
-				deleteRow tRow, cb
-		]
-
-		async.waterfall tests, done
-
-	it 'should deleteColumn & deleteColumns', (done) ->
-		tests = [
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal, () ->
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '1', () ->
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '2', () ->
-					cb()
-		,
-			(cb) ->
-				del = new hbase.Delete tRow
-				del.deleteColumn tCf, tCol
-
-				client.delete testTable, del, (err, res) ->
-					assert.equal err, null
-					assert.equal res.processed, yes
-					cb()
-		,
-			(cb) ->
-				getRow tRow, tCf, tCol, tVal + '1', () ->
-					cb()
-		,
-			(cb) ->
-				del = new hbase.Delete tRow
-				del.deleteColumns tCf, tCol
-
-				client.delete testTable, del, (err, res) ->
-					assert.equal err, null
-					assert.equal res.processed, yes
-					cb()
-		,
-			(cb) ->
-				rowDoesNotExist tRow, cb
-		]
-
-		async.waterfall tests, done
-
-	it 'should deleteFamily & deleteFamilies', (done) ->
-		ts = null
-		tests = [
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal, (err, row) ->
-					ts = row.cols["#{tCf}:#{tCol}"].timestamp
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '1', (++ts).toString(), () ->
-					cb()
-		,
-			(cb) ->
-				putRow tRow, tCf, tCol, tVal + '2', (++ts).toString(), () ->
-					cb()
-		,
-			(cb) ->
-				del = new hbase.Delete tRow
-				del.deleteFamilyVersion tCf, ts
-
-				client.delete testTable, del, (err, res) ->
-					assert.equal err, null
-					assert.equal res.processed, yes
-					cb()
-		,
-			(cb) ->
-				getRow tRow, tCf, tCol, tVal + '1', (--ts).toString(), () ->
-					cb()
-		,
-			(cb) ->
-				del = new hbase.Delete tRow
-				del.deleteFamily tCf
-
-				client.delete testTable, del, (err, res) ->
-					assert.equal err, null
-					assert.equal res.processed, yes
-					cb()
-		,
-			(cb) ->
-				rowDoesNotExist tRow, cb
-		]
-
-		async.waterfall tests, done
-
-	it 'should put multiple rows via array of Put objects', (done) ->
-		puts = testRows.map (row) ->
-			put = new hbase.Put row.row
-			put.add row.cf, row.col, row.val
-			put
-
-		client.mput testTable, puts, (err, res) ->
-			assert.equal err, null
-			done()
-
-	it 'should get multiple rows via array of Get objects', (done) ->
-		gets = testRows.map (row) ->
-			new hbase.Get row.row
-
-		client.mget testTable, gets, (err, res) ->
-			assert.equal err, null
-			assert.equal res.length, testRows.length
-			done()
-
-	it 'should delete multiple rows via array of Delete objects', (done) ->
-		rows = testRows.map (row) ->
-			row.row
-
-		dels = testRows.map (row) ->
-			new hbase.Delete row.row
-
-		client.mdelete testTable, dels, (err, res) ->
-			assert.equal err, null
-			assert.equal res.length, 0
-
-			client.mget testTable, rows, (err, res) ->
-				assert.equal err, null
-				assert.equal res.length, 0
-				done()
-
-	it 'should put multiple rows via simple array', (done) ->
-		puts = []
-		puts = testRows.map (row) ->
-			o =
-				row: row.row
-			o["#{row.cf}:#{row.col}"] = row.val
-			o
-
-		client.mput testTable, puts, (err, res) ->
-			assert.equal err, null
-			done()
-
-	it 'should get multiple rows via simple array', (done) ->
-		gets = testRows.map (row) ->
-			row.row
-
-		client.mget testTable, gets, (err, res) ->
-			assert.equal err, null
-			assert.equal res.length, testRows.length
-			done()
-
-	it 'should scan the table', (done) ->
-		scan = client.getScanner testTable
-
-		async.eachSeries [0..testRows.length], (i, cb) ->
-			if i is testRows.length
+
+				client.checkAndDelete testTable, tRow, tCf, tCol, randomValue, del, (err, res) ->
+					assert.equal err, null, "checkAndDelete returned an error: #{err}"
+					assert.equal res.processed, yes, "checkAndDelete wasn't processed"
+
+					get = new hbase.Get tRow
+
+					client.get testTable, get, (err, res) ->
+						assert.equal err, null, "get returned an error: #{err}"
+						assert.equal res, null, "row #{tRow} exists"
+						done()
+
+		it 'should deleteColumn & deleteColumns', (done) ->
+			tests = [
+				(cb) ->
+					putRow tRow, tCf, tCol, tVal, cb
+				(r, cb) ->
+					putRow tRow, tCf, tCol, tVal + '1', cb
+				(r, cb) ->
+					putRow tRow, tCf, tCol, tVal + '2', cb
+				(r, cb) ->
+					del = new hbase.Delete tRow
+					del.deleteColumn tCf, tCol
+
+					client.delete testTable, del, (err, res) ->
+						assert.equal err, null, "delete returned an error: #{err}"
+						assert.equal res.processed, yes, "delete wasn't processed"
+						cb()
+				(cb) ->
+					getRow tRow, tCf, tCol, tVal + '1', cb
+				(r, cb) ->
+					del = new hbase.Delete tRow
+					del.deleteColumns tCf, tCol
+
+					client.delete testTable, del, (err, res) ->
+						assert.equal err, null, "delete returned an error: #{err}"
+						assert.equal res.processed, yes, "delete wasn't processed"
+						cb()
+				(cb) ->
+					rowDoesNotExist tRow, cb
+			]
+
+			async.waterfall tests, done
+
+		it 'should deleteFamily & deleteFamilies', (done) ->
+			ts = null
+			tests = [
+				(cb) ->
+					putRow tRow, tCf, tCol, tVal, (err, row) ->
+						ts = row.cols["#{tCf}:#{tCol}"].timestamp
+						cb()
+				(cb) ->
+					putRow tRow, tCf, tCol, tVal + '1', (++ts).toString(), cb
+				(r, cb) ->
+					putRow tRow, tCf, tCol, tVal + '2', (++ts).toString(), cb
+				(r, cb) ->
+					del = new hbase.Delete tRow
+					del.deleteFamilyVersion tCf, ts
+
+					client.delete testTable, del, (err, res) ->
+						assert.equal err, null, "delete returned an error: #{err}"
+						assert.equal res.processed, yes, "delete wasn't processed"
+						cb()
+				(cb) ->
+					getRow tRow, tCf, tCol, tVal + '1', (--ts).toString(), cb
+				(r, cb) ->
+					del = new hbase.Delete tRow
+					del.deleteFamily tCf
+
+					client.delete testTable, del, (err, res) ->
+						assert.equal err, null, "delete returned an error: #{err}"
+						assert.equal res.processed, yes, "delete wasn't processed"
+						cb()
+				(cb) ->
+					rowDoesNotExist tRow, cb
+			]
+
+			async.waterfall tests, done
+
+		it 'should delete multiple rows via simple array', (done) ->
+			rows = testRows.map (row) ->
+				row.row
+
+			client.mdelete testTable, rows, (err, res) ->
+				assert.equal err, null, "mdelete returned an error: #{err}"
+				assert.equal res.length, 0, "mdelete should return empty row"
+
+				client.mget testTable, rows, (err, res) ->
+					assert.equal err, null, "mget returned an error: #{err}"
+					assert.equal res.length, 0, "not all rows were deleted"
+					done()
+
+		it 'should delete multiple rows via array of Delete objects', (done) ->
+			rows = testRows.map (row) ->
+				row.row
+
+			dels = testRows.map (row) ->
+				new hbase.Delete row.row
+
+			client.mdelete testTable, dels, (err, res) ->
+				assert.equal err, null, "mdelete returned an error: #{err}"
+				assert.equal res.length, 0, "mdelete should return empty row"
+
+				client.mget testTable, rows, (err, res) ->
+					assert.equal err, null, "mget returned an error: #{err}"
+					assert.equal res.length, 0, "not all rows were deleted"
+					done()
+
+	describe 'scanner', () ->
+		before () ->
+			puts = testRows.map (row) ->
+				put = new hbase.Put row.row
+				put.add row.cf, row.col, row.val
+				put
+
+			client.mput testTable, puts, (err, res) ->
+
+		after () ->
+			rows = testRows.map (row) ->
+				row.row
+
+			client.mdelete testTable, rows, () ->
+
+		it 'should scan the table', (done) ->
+			scan = client.getScanner testTable
+
+			async.eachSeries [0..testRows.length], (i, cb) ->
+				if i is testRows.length
+					scan.next (err, row) ->
+						assert.equal err, null, "scan.next returned an error: #{err}"
+						assert.equal Object.keys(row), 0, "last scan should return empty object"
+						cb()
+				else
+					scan.next (err, row) ->
+						assert.equal err, null, "scan.next returned an error: #{err}"
+						assert.equal row.row, testRows[i].row, "rowKey doesn't match"
+						cb()
+			, done
+
+		it 'should stop scanning after closing the scanner', (done) ->
+			scan = client.getScanner testTable
+
+			scan.next (err, row) ->
+				assert.equal err, null, "scan.next returned an error: #{err}"
+				assert.equal row.row, tRow, "rowKey doesn't match"
+
+				scan.close()
+				scan.close()
 				scan.next (err, row) ->
-					assert.equal err, null
-					assert.equal Object.keys(row), 0
-					cb()
-			else
+					assert.equal err, null, "scan.next returned an error: #{err}"
+					assert.equal Object.keys(row), 0, "closed scanner should return empty object"
+					done()
+
+		it 'should scan the table with startRow and stopRow', (done) ->
+			scan = client.getScanner testTable, '5', '6'
+
+			scan.next (err, row) ->
+				assert.equal err, null, "scan.next returned an error: #{err}"
+				assert.equal row.row, testRows[1].row, "rowKey doesn't match"
+
 				scan.next (err, row) ->
-					assert.equal err, null
-					assert.equal row.row, testRows[i].row
-					cb()
-		, done
-
-	it 'should stop scanning after closing the scanner', (done) ->
-		scan = client.getScanner testTable
-
-		scan.next (err, row) ->
-			assert.equal err, null
-			assert.equal row.row, testRows[0].row
-
-			scan.close()
-			scan.close()
+					assert.equal err, null, "scan.next returned an error: #{err}"
+					assert.equal Object.keys(row), 0, "should return empty object"
+					done()
+
+		it 'should report invalid filter for scan', (done) ->
+			scan = client.getScanner testTable
+			try
+				scan.setFilter nonexistingFilter: yes
+				done 'did not detect invalid filter'
+			catch e
+				assert.equal e.message, 'Invalid filter NonexistingFilter', "invalid error message"
+				done()
+
+		it 'should scan the table with filter', (done) ->
+			scan = client.getScanner testTable
+			scan.setFilter columnPrefixFilter: prefix: testRows[2].col
+
 			scan.next (err, row) ->
-				assert.equal err, null
-				assert.equal Object.keys(row), 0
-				done()
-
-	it 'should scan the table with startRow and stopRow', (done) ->
-		scan = client.getScanner testTable, '5', '6'
-
-		scan.next (err, row) ->
-			assert.equal err, null
-			assert.equal row.row, testRows[1].row
+				assert.equal err, null, "scan.next returned an error: #{err}"
+				assert.equal row.row, testRows[2].row ,"rowKey doesn't match"
+				assert.equal row.cols["#{testRows[2].cf}:#{testRows[2].col}"].value, testRows[2].val, "value doesn't match"
+
+				scan.next (err, row) ->
+					assert.equal err, null, "scan.next returned an error: #{err}"
+					assert.equal Object.keys(row), 0, "scan.next should return empty object"
+					done()
+
+		it 'should scan the table with filterList', (done) ->
+			scan = client.getScanner testTable
+			fl = new hbase.FilterList 'MUST_PASS_ONE', columnPrefixFilter: prefix: testRows[2].col
+			scan.setFilter fl

 			scan.next (err, row) ->
-				assert.equal err, null
-				assert.equal Object.keys(row), 0
-				done()
-
-	it 'should report invalid filter for scan', (done) ->
-		scan = client.getScanner testTable
-		try
-			scan.setFilter nonexistingFilter: yes
-			done 'Did not detect invalid filter'
-		catch e
-			assert.equal e.message, 'Invalid filter NonexistingFilter'
-			done()
-
-	it 'should scan the table with filter', (done) ->
-		scan = client.getScanner testTable
-		scan.setFilter columnPrefixFilter: prefix: testRows[2].col
-
-		scan.next (err, row) ->
-			assert.equal err, null
-			assert.equal row.row, testRows[2].row
-			assert.equal row.cols["#{testRows[2].cf}:#{testRows[2].col}"].value, testRows[2].val
-
-			scan.next (err, row) ->
-				assert.equal err, null
-				assert.equal Object.keys(row), 0
-				done()
-
-	it 'should scan the table with filterList', (done) ->
-		scan = client.getScanner testTable
-		fl = new hbase.FilterList 'MUST_PASS_ONE', columnPrefixFilter: prefix: testRows[2].col
-		scan.setFilter fl
-
-		scan.next (err, row) ->
-			assert.equal err, null
-			assert.equal row.row, testRows[2].row
-			assert.equal row.cols["#{testRows[2].cf}:#{testRows[2].col}"].value, testRows[2].val
-
-			scan.next (err, row) ->
-				assert.equal err, null
-				assert.equal Object.keys(row), 0
-				done()
-
-	it 'should scan the table and convert result to array', (done) ->
-		scan = client.getScanner testTable
-
-		scan.toArray (err, res) ->
-			assert.equal err, null
-
-			for i, row of testRows
-				assert.equal res[i].row, testRows[i].row
-				assert.equal res[i].cols["#{testRows[i].cf}:#{testRows[i].col}"].value, testRows[i].val
-
-			done()
-
-	it 'should scan the table with filterList consisting of multiple filterLists', (done) ->
-		scan = client.getScanner testTable
-
-		f1 =
-			singleColumnValueFilter:
-				columnFamily: 'cf1'
-				columnQualifier: 'col2'
-				compareOp: 'EQUAL'
-				comparator:
-					substringComparator:
-						substr: '2'
-				filterIfMissing: yes
-				latestVersionOnly: yes
-
-		f2 =
-			singleColumnValueFilter:
-				columnFamily: 'cf1'
-				columnQualifier: 'col3'
-				compareOp: 'EQUAL'
-				comparator:
-					substringComparator:
-						substr: '3'
-				filterIfMissing: yes
-				latestVersionOnly: yes
-
-		fl1 = new hbase.FilterList
-		fl2 = new hbase.FilterList
-		fl3 = new hbase.FilterList 'MUST_PASS_ONE'
-
-		fl1.addFilter f1
-		fl2.addFilter f2
-
-		fl3.addFilter fl1
-		fl3.addFilter fl2
-
-		scan.setFilter fl3
-
-		scan.toArray (err, res) ->
-			assert.equal err, null
-
-			assert.equal res[0].row, testRows[1].row
-			assert.equal res[0].cols["#{testRows[1].cf}:#{testRows[1].col}"].value, testRows[1].val
-
-			assert.equal res[1].row, testRows[2].row
-			assert.equal res[1].cols["#{testRows[2].cf}:#{testRows[2].col}"].value, testRows[2].val
-			done()
-
-	it 'should delete multiple rows via simple array', (done) ->
-		rows = testRows.map (row) ->
-			row.row
-
-		client.mdelete testTable, rows, (err, res) ->
-			assert.equal err, null
-			assert.equal res.length, 0
-
-			client.mget testTable, rows, (err, res) ->
-				assert.equal err, null
-				assert.equal res.length, 0
-				done()
-
-	it 'should checkAndPut', (done) ->
-		putRow testRows[0].row, testRows[0].cf, testRows[0].col, testRows[0].val, () ->
-			put = new hbase.Put testRows[0].row
-			put.add testRows[0].cf, testRows[0].col, randomValue
-
-			client.checkAndPut testTable, testRows[0].row, testRows[0].cf, testRows[0].col, testRows[0].val, put, (err, res) ->
-				assert.equal err, null
-				assert.equal res.processed, yes
-				done()
-
-	it 'should checkAndDelete', (done) ->
-		del = new hbase.Delete testRows[0].row
-
-		client.checkAndDelete testTable, testRows[0].row, testRows[0].cf, testRows[0].col, randomValue, del, (err, res) ->
-			assert.equal err, null
-			assert.equal res.processed, yes
-
-			get = new hbase.Get testRows[0].row
-
-			client.get testTable, get, (err, res) ->
-				assert.equal err, null
-				assert.equal res, null
-				done()
-
-	it 'should increment & incrementColumnValue', (done) ->
-		inc = 4
-		b = new ByteBuffer 8
-		b.writeLong 65
-		b = b.toBuffer()
-
-		tests = [
-			(cb) ->
-				putRow tRow, tCf, tCol, b, () ->
-					cb()
-		,
-			(cb) ->
-				increment = new hbase.Increment tRow
-				assert.equal increment.getRow(), tRow
-				increment.add tCf, tCol, inc
-
-				client.increment testTable, increment, (err, res) ->
-					assert.equal err, null
-					val = res.result.cell[0].value.toBuffer()
-					assert.equal hbase.utils.bufferCompare(val, b), inc
-					cb()
-		,
-			(cb) ->
-				client.incrementColumnValue testTable, tRow, tCf, tCol, inc, (err, res) ->
-					assert.equal err, null
-					val = res.result.cell[0].value.toBuffer()
-					assert.equal hbase.utils.bufferCompare(val, b), inc * 2
-					cb()
-		,
-			(cb) ->
-				deleteRow tRow, cb
-		]
-
-		async.waterfall tests, done
-
-
-
-
-
-
-
+				assert.equal err, null, "scan.next returned an error: #{err}"
+				assert.equal row.row, testRows[2].row, "rowKey doesn't match"
+				assert.equal row.cols["#{testRows[2].cf}:#{testRows[2].col}"].value, testRows[2].val, "value doesn't match"
+
+				scan.next (err, row) ->
+					assert.equal err, null, "scan.next returned an error: #{err}"
+					assert.equal Object.keys(row), 0, "scan.next should return empty object"
+					done()
+
+		it 'should scan the table and convert result to array', (done) ->
+			scan = client.getScanner testTable
+
+			scan.toArray (err, res) ->
+				assert.equal err, null, "scan.toArray returned an error: #{err}"
+
+				for i, row of testRows
+					assert.equal res[i].row, testRows[i].row, "rowKey doesn't match"
+					assert.equal res[i].cols["#{testRows[i].cf}:#{testRows[i].col}"].value, testRows[i].val, "value doesn't match"
+
+				done()
+
+		it 'should scan the table with filterList consisting of multiple filterLists', (done) ->
+			scan = client.getScanner testTable
+
+			f1 =
+				singleColumnValueFilter:
+					columnFamily: 'cf1'
+					columnQualifier: 'col2'
+					compareOp: 'EQUAL'
+					comparator:
+						substringComparator:
+							substr: '2'
+					filterIfMissing: yes
+					latestVersionOnly: yes
+
+			f2 =
+				singleColumnValueFilter:
+					columnFamily: 'cf1'
+					columnQualifier: 'col3'
+					compareOp: 'EQUAL'
+					comparator:
+						substringComparator:
+							substr: '3'
+					filterIfMissing: yes
+					latestVersionOnly: yes
+
+			fl1 = new hbase.FilterList
+			fl2 = new hbase.FilterList
+			fl3 = new hbase.FilterList 'MUST_PASS_ONE'
+
+			fl1.addFilter f1
+			fl2.addFilter f2
+
+			fl3.addFilter fl1
+			fl3.addFilter fl2
+
+			scan.setFilter fl3
+
+			scan.toArray (err, res) ->
+				assert.equal err, null, "scan.toArray returned an error: #{err}"
+
+				assert.equal res[0].row, testRows[1].row, "rowKey doesn't match"
+				assert.equal res[0].cols["#{testRows[1].cf}:#{testRows[1].col}"].value, testRows[1].val, "value doesn't match"
+
+				assert.equal res[1].row, testRows[2].row, "rowKey doesn't match"
+				assert.equal res[1].cols["#{testRows[2].cf}:#{testRows[2].col}"].value, testRows[2].val, "value doesn't match"
+				done()
+
+	describe 'increment', () ->
+		it 'should increment & incrementColumnValue', (done) ->
+			inc = 4
+			b = new ByteBuffer 8
+			b.writeLong 65
+			b = b.toBuffer()
+
+			tests = [
+				(cb) ->
+					putRow tRow, tCf, tCol, b, cb
+				(r, cb) ->
+					increment = new hbase.Increment tRow
+					assert.equal increment.getRow(), tRow, "rowKey doesn't match"
+					increment.add tCf, tCol, inc
+
+					client.increment testTable, increment, (err, res) ->
+						assert.equal err, null, "increment returned an error: #{err}"
+						val = res.result.cell[0].value.toBuffer()
+						assert.equal hbase.utils.bufferCompare(val, b), inc, "value wasn't incremented"
+						cb()
+				(cb) ->
+					client.incrementColumnValue testTable, tRow, tCf, tCol, inc, (err, res) ->
+						assert.equal err, null, "incrementColumnValue returned an error: #{err}"
+						val = res.result.cell[0].value.toBuffer()
+						assert.equal hbase.utils.bufferCompare(val, b), inc * 2, "value wasn't incremented"
+						cb()
+				(cb) ->
+					deleteRow tRow, cb
+			]
+
+			async.waterfall tests, done
+
+
+
+
+
+


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/core_object.coffee
+++ test/core_object.coffee
@@ -36,7 +36,6 @@
   equal o.test("new_val"), o
   equal o.test(), "new_val"

-
 test "Core#attrReader", ->
   o = Core
     test: "my_val"


Add tools tab view

Add tools tab view

--- src/scripts/modules/media/tabs/tabs.coffee
+++ src/scripts/modules/media/tabs/tabs.coffee
@@ -3,6 +3,7 @@
   content = require('cs!models/content')
   BaseView = require('cs!helpers/backbone/views/base')
   TocTreeView = require('cs!./contents/tree')
+  ToolsView = require('cs!./tools/tools')
   template = require('hbs!./tabs-template')
   require('less!./tabs')

@@ -23,6 +24,7 @@

     onRender: () ->
       @regions.contents.show(new TocTreeView({model: @model}))
+      @regions.tools.show(new ToolsView({model: @model}))

     selectTab: (e) ->
       $tab = $(e.currentTarget)


Helpful error is helpful

Helpful error is helpful

--- src/ui.coffee
+++ src/ui.coffee
@@ -1,6 +1,6 @@
 window.WD = window.WD or {}

-_showUsernamePrompt = (callback) ->
+_showUsernamePrompt = (callback, isRepeat = false) ->
   $el = $("

       <form class='username-prompt'>
@@ -9,6 +9,8 @@
       </form>

   ".trim()).appendTo($('body'))
+  if isRepeat
+    $("
(The one you tried was taken)
").insertAfter($el.find('input'))
   $form = $el.find('form')
   $form.on 'submit', (e) ->
     value = $el.find('input').val()
@@ -19,7 +21,7 @@
     false

-WD.ensureUsername = (callback) ->
+WD.ensureUsername = (callback, isRepeat = false) ->
   if localStorage.getItem('username')
     fb.child(localStorage.getItem('username')).once 'value', (snapshot) ->
       unless snapshot.val()
@@ -32,10 +34,10 @@
           color: color
       callback(localStorage.getItem('username'))
   else
-    _showUsernamePrompt (username) =>
+    f = (username) =>
       fb.child(username).once 'value', (snapshot) ->
         if snapshot.val()
-          WD.ensureUsername(callback)
+          WD.ensureUsername(callback, true)
         else
           # win!
           color =
@@ -47,3 +49,4 @@
             color: color
           localStorage.setItem('username', username)
           callback(username)
+    _showUsernamePrompt(f, isRepeat)


Whitespace

Whitespace

--- app/router/uiview.coffee
+++ app/router/uiview.coffee
@@ -51,7 +51,5 @@

     return resolves

-
-
   onBeforeDestroy: ->
     @deregister?()


Made resolveUser() a public method.

Made resolveUser() a public method.

--- src/AccountsUtil.coffee
+++ src/AccountsUtil.coffee
@@ -42,13 +42,13 @@
           throw new Error('No author provided' + suffix)

   isOwner: (doc, user) ->
-    user = @_resolveUser(user)
+    user = @resolveUser(user)
     doc[@AUTHOR_FIELD] == user?.username

   isOwnerOrAdmin: (doc, user) -> @isOwner(doc, user) || @isAdmin(user)

   isAuthorized: (doc, user, predicate) ->
-    user = @_resolveUser(user)
+    user = @resolveUser(user)
     if predicate
       predicate(doc, user)
     else
@@ -59,10 +59,10 @@
       throw new Meteor.Error(403, 'Access denied')

   isAdmin: (user) ->
-    user = @_resolveUser(user)
+    user = @resolveUser(user)
     Roles.userIsInRole(user, 'admin')

-  _resolveUser: (user) ->
+  resolveUser: (user) ->
     if Types.isString(user)
       user = Meteor.users.findOne(user)
     else


Do not try to parse requests with content type

--- packages/rocketchat-cors/cors.coffee
+++ packages/rocketchat-cors/cors.coffee
@@ -6,6 +6,9 @@
 		return next()

 	if req.headers['transfer-encoding'] is undefined and isNaN(req.headers['content-length'])
+		return next()
+
+	if req.headers['content-type'] not in ['', undefined]
 		return next()

 	buf = ''
@@ -20,6 +23,7 @@
 		catch err
 			req.body = buf

+		req._body = true
 		next()


remove log

remove log

--- src/reactor/DrawPolygonReactor.coffee
+++ src/reactor/DrawPolygonReactor.coffee
@@ -45,7 +45,6 @@

 				guideLineEnd.setPoint1 guideLineEnd.points[1]
 				polygon.addPoint mousePos.clone()
-				console.log "polygon vertices: " + polygon.vertices.length
 			else if mouseButton == Bu.MOUSE_BUTTON_RIGHT
 				polygon.fill()
 				polygon = null
@@ -75,7 +74,4 @@

 				points = polygon.vertices
 				len = mousePos.distanceTo points[points.length - 1]
-#				console.log "len: " + len
-				console.log "mousePos: ", mousePos, "lastPoint: ", points[points.length - 1]
-				polygon.addPoint mousePos.clone() if len > Bu.POINT_RENDER_SIZE
-				console.log "polygon vertices: " + polygon.vertices.length+				polygon.addPoint mousePos.clone() if len > Bu.POINT_RENDER_SIZE


react/debug: keep at least one in the array, such that renderings[0] is always defined

--- src/smc-webapp/smc-react-debug.coffee
+++ src/smc-webapp/smc-react-debug.coffee
@@ -38,7 +38,7 @@
             return r if dt < mintime_s

             # … and only keep what's in the time_window
-            while renderings.length > 0
+            while renderings.length > 1
                 if renderings[0][0] < t1 - time_window_ms
                     renderings.shift()
                 else


tasks: themes and keybindings

tasks: themes and keybindings

--- src/smc-webapp/tasks/desc-editor.cjsx
+++ src/smc-webapp/tasks/desc-editor.cjsx
@@ -7,6 +7,8 @@
 {three_way_merge} = require('smc-util/syncstring')

 {debounce} = require('underscore')
+
+{cm_options} = require('../jupyter/cm_options')

 misc = require('smc-util/misc')

@@ -36,6 +38,10 @@
         is_current : rtypes.bool
         font_size  : rtypes.number  # used only to cause refresh

+    reduxProps :
+        account :
+            editor_settings : rtypes.immutable.Map
+
     shouldComponentUpdate: (next) ->
         return @props.task_id    != next.task_id    or \
                @props.desc       != next.desc       or \
@@ -52,7 +58,7 @@
             return
         if @props.font_size != next.font_size
             @cm_refresh()
-        if next.desc != @props.desc
+        if @props.desc != next.desc
             @_cm_merge_remote(next.desc)

     cm_refresh: ->
@@ -112,15 +118,22 @@
         node = $(ReactDOM.findDOMNode(@)).find("textarea")[0]
         if not node?
             return
-        options = misc.deep_copy(CM_OPTIONS)
+
+        if @props.editor_settings?
+            options = cm_options({name:'gfm2'}, @props.editor_settings.toJS())
+            misc.merge(options, CM_OPTIONS)
+        else
+            options = misc.deep_copy(CM_OPTIONS)
         save_to_disk = => @props.actions.save()
-        options.extraKeys =
+        keys =
             "Shift-Enter" : @stop_editing
             Esc           : @stop_editing
             Tab           : => @cm.tab_as_space()
             "Cmd-S"       : save_to_disk
             "Alt-S"       : save_to_disk
             "Ctrl-S"      : save_to_disk
+        options.extraKeys ?= {}
+        misc.merge(options.extraKeys, keys)

         @cm = CodeMirror.fromTextArea(node, options)
         $(@cm.getWrapperElement()).css(height:'auto')


código más limpio

código más limpio

--- app/assets/javascripts/comunes/calicatas.js.coffee
+++ app/assets/javascripts/comunes/calicatas.js.coffee
@@ -1,9 +1,28 @@
 jQuery ->

-  $('#calicata_fase_attributes_nombre').autocomplete({ source: "/fases/autocompletar/nombre", delay: 100 })
-  $('#calicata_grupo_attributes_descripcion').autocomplete({ source: "/grupos/autocompletar/descripcion", delay: 100 })
-  $('.munsell').autocomplete({ source: "/colores/autocompletar/hvc", delay: 100 })
+  nombre =
+    source:     "/fases/autocompletar/nombre"
+    delay:      100
+    autoFocus:  true
+    minLength:  2
+
+  descripcion =
+    source:     "/grupos/autocompletar/descripcion"
+    delay:      100
+    autoFocus:  true
+    minLength:  2
+
+  hvc =
+    source:     "/colores/autocompletar/hvc"
+    delay:      100
+    autoFocus:  true
+    minLength:  2
+
+  $('#calicata_fase_attributes_nombre').autocomplete(nombre)
+  $('#calicata_grupo_attributes_descripcion').autocomplete(descripcion)
+  $('.munsell').autocomplete(hvc)
+
   $('.completa').nestedFields({
     afterInsert: ->
-      $('.munsell').autocomplete({ source: "/colores/autocompletar/hvc", delay: 100 })
+      $('.munsell').autocomplete(hvc)
   })


improve animation and fix bugs in ajax pagination

--- app/assets/javascripts/jquery.ajax_paginate.coffee
+++ app/assets/javascripts/jquery.ajax_paginate.coffee
@@ -43,13 +43,15 @@
     $container.data('completed',false)

     # show loading indicator (hide buttons)
-    showLoading=() -> $buttons.fadeOut 'slow', () -> $spinner.show()
+    showLoading=() -> $buttons.stop().fadeOut 'fast', () -> $spinner.stop().show()
     # hide loading indicator and show buttons
-    hideLoading=() -> $spinner.hide(); unless $container.data('completed') then $buttons.fadeIn('slow')
+    hideLoading=() -> $spinner.stop().hide(); unless $container.data('completed') then $buttons.stop().fadeIn('fast')

     loadNext=(callback) ->
       # return if there is an ajax load running
-      return if loading
+      if loading
+        callback() if callback
+        return
       # if completed call callback and return
       if $container.data('completed')
         callback() if callback


fixes #187

fixes #187

--- app/assets/javascripts/modules/blaze/controllers/entity_controller.js.coffee
+++ app/assets/javascripts/modules/blaze/controllers/entity_controller.js.coffee
@@ -31,7 +31,7 @@

     scope.show_tags = ->
       if scope.entity
-        scope.entity.kind.settings.tagging &&
+        scope.entity.kind.tagging &&
         (
           (scope.entity.tags && scope.entity.tags.length > 0) ||
           scope.allowed_to('tagging', scope.entity.collection_id)


Tests: add wildcard event emitter tests

Tests: add wildcard event emitter tests

--- test/core/eventemitterwildcard.test.coffee
+++ test/core/eventemitterwildcard.test.coffee
@@ -1,7 +1,150 @@
-{assert} = require('chai')
+{assert} = require 'chai'
+sinon    = require 'sinon'
 KDEventEmitterWildcard = require('../../src/core/eventemitterwildcard')

 describe 'KDEventEmitterWildcard', ->

   it 'exists', ->
     assert.ok(KDEventEmitterWildcard)
+
+  describe 'constructor', ->
+
+    it 'defaults delimiter option', ->
+      emitter = new KDEventEmitterWildcard
+      assert.equal emitter._delim, '.'
+
+    it 'gets delim from options', ->
+      emitter = new KDEventEmitterWildcard delimiter: '~'
+      assert.equal emitter._delim, '~'
+
+  describe 'setMaxListeners', ->
+
+    it 'sets max listeners', ->
+      emitter = new KDEventEmitterWildcard
+      emitter.setMaxListeners 20
+      assert.equal emitter._maxListeners, 20
+
+  describe 'emit', ->
+
+    it "delimits eventName and calls delimited events", ->
+      array      = []
+      listener   = (num) -> array.push num
+      emitter    = new KDEventEmitterWildcard
+
+      emitter._e       =
+        namespace      :
+          '*'          :
+            _listeners : [ listener ]
+
+      emitter.emit 'namespace.first', 'first'
+      emitter.emit 'namespace.second', 'second'
+
+      assert.deepEqual array, ['first', 'second']
+
+    it 'returns itself for chaining', ->
+      emitter    = new KDEventEmitterWildcard
+      emitResult = emitter.emit 'dummy'
+
+      assert.equal emitResult, emitter
+
+  describe 'on', ->
+
+    context 'when listener is not a function', ->
+
+      it 'throws an error', ->
+        emitter = new KDEventEmitterWildcard
+        assert.throws (-> emitter.on()), /listener is not a function/
+        assert.throws (-> emitter.on('a', 'b')), /listener is not a function/
+        assert.throws (-> emitter.on('a', 1)), /listener is not a function/
+        assert.throws (-> emitter.on('a', {})), /listener is not a function/
+        assert.throws (-> emitter.on('a', [])), /listener is not a function/
+        assert.throws (-> emitter.on('a', yes)), /listener is not a function/
+
+    it 'emits an event with listener', ->
+      listener = -> yes
+      emitter  = new KDEventEmitterWildcard
+
+      sinon.spy emitter, 'emit'
+
+      emitter.on 'anEvent', listener
+
+      assert emitter.emit.calledWith 'newListener', 'anEvent', listener
+
+    it 'registers a normal event', ->
+      array    = []
+      listener = (num) -> array.push num
+      emitter  = new KDEventEmitterWildcard
+
+      emitter.on 'regularEvent', listener
+
+      emitter.emit 'regularEvent', 'first'
+      emitter.emit 'regularEvent', 'second'
+
+      assert.deepEqual array, ['first', 'second']
+
+    it 'registers a wildcard event', ->
+      array    = []
+      listener = (num) -> array.push num
+      emitter  = new KDEventEmitterWildcard
+
+      emitter.on '*', listener
+
+      emitter.emit 'randomEvent', 'first'
+      emitter.emit 'moreRandomEvent', 'second'
+
+      assert.deepEqual array, ['first', 'second']
+
+    it 'registers namespaced wildcard events', ->
+      array    = []
+      listener = (num) -> array.push num
+      emitter  = new KDEventEmitterWildcard delimiter: '/'
+
+      emitter.on 'namespace/*', listener
+
+      emitter.emit 'namespace/randomEvent', 'first'
+      emitter.emit 'namespace/moreRandomEvent', 'second'
+
+      assert.deepEqual array, ['first', 'second']
+
+    it 'returns itself for chaining', ->
+      emitter = new KDEventEmitterWildcard
+      onResult = emitter.on 'dummy', -> yes
+
+      assert.equal onResult, emitter
+
+  describe 'off', ->
+
+    it 'removes listener from regular event', ->
+      array    = []
+      listener = (num) -> array.push num
+      emitter  = new KDEventEmitterWildcard
+
+      emitter.on 'regularEvent', listener
+      emitter.emit 'regularEvent', 1
+
+      emitter.off 'regularEvent', listener
+      emitter.emit 'regularEvent', 2
+
+      assert.deepEqual array, [1]
+
+    it 'removes wildcard events', ->
+      array    = []
+      listener = (num) -> array.push num
+      emitter  = new KDEventEmitterWildcard delimiter: '/'
+
+      emitter.on 'namespace/*', listener
+      emitter.emit 'namespace/randomEvent', 'first'
+      emitter.emit 'namespace/mostRandomEvent', 'second'
+
+      emitter.off 'namespace/*', listener
+      emitter.emit 'namespace/coolEvent', 'third'
+
+      assert.deepEqual array, ['first', 'second']
+
+    it 'returns itself for chaining', ->
+      emitter = new KDEventEmitterWildcard
+      offResult = emitter.off '*', -> yes
+
+      assert.equal offResult, emitter
+
+


profile: fix avatar area pistachio

profile: fix avatar area pistachio

--- client/Account/views/username.coffee
+++ client/Account/views/username.coffee
@@ -279,13 +279,8 @@
     """

       {{> @avatar}}
-    #

-    #     {{> @uploadAvatarBtn}}
-    #     {{> @uploadAvatarInput}}
-    #     {{> @useGravatarBtn}}
-    #

-    #

-

-      {{> @emailForm}}
-

+

+        {{> @emailForm}}
+

+

     """


ForcedRegister: reload page after user login

--- client/Teamwork/AppController.coffee
+++ client/Teamwork/AppController.coffee
@@ -16,6 +16,17 @@

     super options, data

+
   handleQuery: (query) ->
+
+    search = location.search
+    if /guest-/.test search
+      search = ""
+
+    path = location.pathname + search
+    mainController = KD.getSingleton("mainController")
+    mainController.once "accountChanged.to.loggedIn", =>
+      location.replace path
+
     view = @getView()
     view.ready => view.handleQuery query


terminal: remove clear buffer command for now

--- client/Terminal/AppController.coffee
+++ client/Terminal/AppController.coffee
@@ -17,7 +17,6 @@
         {title: "customViewAdvancedSettings"}
       ]
     commands     :
-      'clear buffer'  : 'clearBuffer'
       'ring bell'     : 'ringBell'
       'noop'          : (->)
     keyBindings  : [


Client: mostRecentNames is populated correctly.

--- client/app/js/views/chat_view.coffee
+++ client/app/js/views/chat_view.coffee
@@ -134,14 +134,18 @@
     username = user?.getDisplayName() || username
     yourName = PokeBattle.username
     highlight = (new RegExp("\\b#{yourName}\\b", 'i').test(message))
-    username = "#{username}:"
-    @updateChat("#{@timestamp()} #{username} #{@sanitize(message)}", {highlight})
+
+    # Render the chat message
+    u = "#{username}:"
+    @updateChat("#{@timestamp()} #{u} #{@sanitize(message)}", {highlight})

     # We might want to run something based on the message, e.g. !pbv from a mod.
     @handleMessage(user, message)

     # Record last few usernames who chatted
-    @mostRecentNames.push(username)  if username not in @mostRecentNames
+    index = @mostRecentNames.indexOf(username)
+    @mostRecentNames.splice(index, 1)  if index != -1
+    @mostRecentNames.push(username)
     @mostRecentNames.shift()  if @mostRecentNames.length > MAX_USERNAME_HISTORY

   userColor: (username) =>


fsfile: read-only file check

fsfile: read-only file check

--- client/app/lib/util/fs/fsfile.coffee
+++ client/app/lib/util/fs/fsfile.coffee
@@ -234,3 +234,34 @@
         return response

+  checkIfReadOnly: (callback) ->
+
+    kite = @getKite()
+
+    writable = 'writable'
+    readOnly = 'read only'
+    path = @getPath()
+
+    kite.init()
+
+    .then =>
+
+      ###
+      Since touching file works without error if file is not writable but user is owner,
+      let's do 2 separate checks:
+      - user is owner and file is not writable
+      - user is not owner and touch throws an error
+      ###
+      command = "if [ -O #{path} ]; then [ -w #{path} ]
+        && echo '#{writable}' || echo '#{readOnly}';
+        else touch -a #{path} && echo '#{writable}' || echo '#{readOnly}'; fi"
+
+      kite.exec({command})
+
+    .nodeify (err, result) ->
+
+      return callback err  if err
+
+      { stdout, stderr } = result
+      readOnly = (stdout.indexOf writable) is -1
+      callback null, readOnly


StackEditor: destroy subviews after fetching data

--- client/stack-editor/lib/index.coffee
+++ client/stack-editor/lib/index.coffee
@@ -24,8 +24,6 @@
       mainController.tellChatlioWidget 'show', { expanded: no }

     { computeController } = kd.singletons
-
-    @mainView.destroySubViews()

     if stackTemplateId
       computeController.fetchStackTemplate stackTemplateId, (err, stackTemplate) =>
@@ -84,6 +82,9 @@

     options = { skipFullscreen: yes }
     data    = { stackTemplate, showHelpContent: not stackTemplate }
+
+    @mainView.destroySubViews()
+
     view    = new StackEditorView options, data
     view.on 'Cancel', -> kd.singletons.router.back()


Agent pie: start/end angle pie transition work

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -178,7 +178,7 @@
             #    b = i(t)
             #    return arc b
         #)
-        path.transition().duration(750).attrTween('d', (d) ->
+        path.transition().duration(750).attrTween('d', (d,i,a) ->
             `var i`
             i = d3.interpolate(this._current, a)
             this._current = i(0)


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -2,7 +2,7 @@

     @accessor 'data'

-    constructor: ({@oldPieData}) ->
+    ready: ->
         @oldPieData = ''

     onData: (data) ->


--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -205,12 +205,12 @@
             #    #console.log('b',b)
             #    return arc b
         #)
-        path.transition().duration(2000).attrTween('d', (d) ->
-            console.log('1. in tween - window.oldPieData[myInstanceDataId]: ',window.oldPieData[myInstanceDataId])
+        path.transition().duration(2000).attrTween('d', (d,i) ->
+            console.log('1. in tween - window.oldPieData[myInstanceDataId]: ',window.oldPieData[myInstanceDataId][i])
             console.log('1. in tween - d: ',d)
-            myInterpolater = d3.interpolate(window.oldPieData[myInstanceDataId], d)
+            myInterpolater = d3.interpolate(window.oldPieData[myInstanceDataId][i], d)
             window.oldPieData[myInstanceDataId] = myInterpolater(0)
-            console.log('2. in tween - window.oldPieData[myInstanceDataId]: ',window.oldPieData[myInstanceDataId])
+            console.log('2. in tween - window.oldPieData[myInstanceDataId]: ',window.oldPieData[myInstanceDataId][i])
             console.log('2. in tween - d: ',d)
             return (t) ->
                 return arc(myInterpolater(t))


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -36,7 +36,7 @@
         .attr("width", width)
         .attr("height", height)
       .append("svg:g")
-        .attr("transform", "translate(" + radius + "," + radius + ")")
+        .attr("transform", "translate(" + radius + "," + 100 + ")")

     arc = d3.svg.arc().outerRadius(radius)
     pie = d3.layout.pie().value((d) -> d.value)
@@ -51,7 +51,7 @@
     sum=0
     for val in data
       sum += val.value
-
+    textRadiusInc = Math.Round(sum / data.count)
     if !sum
       arcs.append("svg:text")
         .attr('fill', "#fff")
@@ -59,6 +59,7 @@
     else
       arcs.append("svg:text").attr("transform", (d, i) ->
         procent_val = Math.round(data[i].value/sum * 100)
+#        d.innerRadius = (radius * (100-procent_val)/100) - radius/2 #45  #45=max text size/2
         d.innerRadius = (radius * (100-procent_val)/100) - radius/2 #45  #45=max text size/2
         d.outerRadius = radius
         "translate(" + arc.centroid(d) + ")")


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -2,15 +2,6 @@

     @accessor 'data'

-    ready: ->
-        # Config values here
-        @width = 750                            # Width of the SVG area
-        @height = 400                           # Height of the SVG area
-        @radius = Math.min(width, height) / 2   # Calculated min dimension of the SVG area
-        @radiuso = 130                          # Outer radius of the pie
-        @radiusi = 65                           # Inner radius of the pie (zero = pie, non-zero = donut)
-        @color = d3.scale.category20()          # Color scale for pie slices
-
     onData: (data) ->
         #$(@node).fadeOut().fadeIn()
         @update(data.data)
@@ -25,28 +16,33 @@
         # Remove any previous svg
         $(@node).children("svg").remove();

-        width = @width
+        # Config values here
+        width = 750                            # Width of the SVG area
         height = 400                           # Height of the SVG area
         radius = Math.min(width, height) / 2   # Calculated min dimension of the SVG area
         radiuso = 130                          # Outer radius of the pie
         radiusi = 65                           # Inner radius of the pie (zero = pie, non-zero = donut)
         color = d3.scale.category20()          # Color scale for pie slices
+
+
         pie = d3.layout.pie().value((d) -> d.value)
         arc = d3.svg.arc().innerRadius(radiusi).outerRadius(radiuso)
         svg = d3.select(@node).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')')
-        console.log 'update pie', dataSet
-        #that = this
+        #console.log 'update pie', dataSet
+
         piedata = pie(dataSet)
-        # Remove zero values
+        # Remove zero values from our pie data
         piedata = piedata.filter (pd) -> pd.value isnt 0
-        console.log 'update pie', piedata
+        #console.log 'update pie', piedata
+
         #create a marker element if it doesn't already exist
         defs = svg.select('defs')
         if defs.empty()
           defs = svg.append('defs')
         marker = defs.select('marker#circ')
         if marker.empty()
-          defs.append('marker').attr('id', 'circ').attr('markerWidth', 6).attr('markerHeight', 6).attr('refX', 3).attr('refY', 3).append('circle').attr('cx', 3).attr('cy', 3).attr 'r', 3
+          defs.append('marker').attr('id', 'circ').attr('markerWidth', 12).attr('markerHeight', 12).attr('refX', 3).attr('refY', 3).append('circle').attr('cx', 3).attr('cy', 3).attr 'r', 3
+
         #Create/select <g> elements to hold the different types of graphics
         #and keep them in the correct drawing order
         pathGroup = svg.select('g.piePaths')


fullpieagent testing

fullpieagent testing

--- widgets/fullpie_agent/fullpie_agent.coffee
+++ widgets/fullpie_agent/fullpie_agent.coffee
@@ -278,7 +278,7 @@
         path.enter().append("path")
             .attr("class", "pie")
             .attr("fill",(d, i) -> return color i)
-            .data(piedata)
+            .data(piedata[i])
         #path.transition()
         #    .duration(1500)
         #    #.attrTween("d", pieTween)


Teamwork: Added url option to tabview preview factory.

--- client/Teamwork/Views/teamworktabview.coffee
+++ client/Teamwork/Views/teamworktabview.coffee
@@ -286,11 +286,11 @@

     @registerPaneRemoveListener_ pane

-  createPreview: (sessionKey, indexKey) ->
+  createPreview: (sessionKey, indexKey, url = null) ->
     indexKey = indexKey or @createSessionKey()
     pane     = new KDTabPaneView { title: "Browser", indexKey }
     delegate = @getDelegate()
-    browser  = new CollaborativePreviewPane { delegate, sessionKey }
+    browser  = new CollaborativePreviewPane { delegate, sessionKey, url }

     @appendPane_ pane, browser


Show plan type in "Buy Product" confirmation modal

--- client/app/CommonViews/paymentwidgets.coffee
+++ client/app/CommonViews/paymentwidgets.coffee
@@ -89,12 +89,19 @@
   confirmSubscription:(callback)->
     KD.remote.api.JRecurlyPlan.getPlanWithCode @planCode, (err,plan)=>

-      title = plan.title
-      price = plan.feeMonthly / 100
+      title     = plan.title
+      price     = plan.feeMonthly / 100
+      recurring = plan.feeInterval is 1

-      content = """
Are you sure you want to subscribe to this plan?

+      if recurring
+        description = "(Montly payment)"
+      else
+        description = "(Single payment)"
+
+      content = """
Are you sure you want to buy to this product?

-
#{title} - $#{price.toFixed(2)}

+
#{title} - $#{price.toFixed(2)} #{description}

+

                 """

       modal           = new KDModalView