Q = require 'q'

{Base} = require "#{__dirname}/base"
{Wrappers} = require "#{__dirname}/helpers/wrappers"
{BeanBuilder} = require "#{__dirname}/helpers/bean_builder"

class BaseTask extends Base

  app: null

  actions: null
  actionBuilder: null

  constructor: ->
    @actions = []
    @actionBuilder = new BeanBuilder basePath: "#{__dirname}/tasks/actions", suffix: 'action'

  configure: (@app, config) ->
    super @app.getEmitter()
    @_configureActions config.actions if config.actions?.length

  _configureActions: (actions) ->
    @actions = (@_buildAction action for action in actions)
    return

  initialize: ->
    for action in @actions
      action.initialize()
    return

  _buildAction: (config) ->
    action = @actionBuilder.build config
    action.configure @app, @, config
    return action

  run: (data)->
    promise = null
    scope = data: data
    for action in @actions
      if promise
        promise.then ((lastResult) ->
          scope.lastResult = lastResult
          Q.when action.run scope
        ), ((err) =>
          @log 'warn', 'task.base', "Action #{action} performed not well.", err
        )
      else
        promise = Q.when action.run scope
    return promise

exports.BaseTask = BaseTask

Q = require 'q'

{Base} = require "#{__dirname}/base"
{Wrappers} = require "#{__dirname}/helpers/wrappers"
{BeanBuilder} = require "#{__dirname}/helpers/bean_builder"

class BaseTask extends Base

  app: null

  actions: null
  actionBuilder: null

  constructor: ->
    @actions = []
    @actionBuilder = new BeanBuilder basePath: "#{__dirname}/tasks/actions", suffix: 'action'

  configure: (@app, config) ->
    super @app.getEmitter()
    @_configureActions config.actions if config.actions?.length

  _configureActions: (actions) ->
    @actions = (@_buildAction action for action in actions)
    return

  initialize: ->
    for action in @actions
      action.initialize()
    return

  _buildAction: (config) ->
    action = @actionBuilder.build config
    action.configure @app, @, config
    return action

  run: (data) ->
    promise = null
    scope = data: data
    for action in @actions
      if promise
        promise = promise.then ((lastResult) ->
          scope.lastResult = lastResult
          Q.when action.run scope
        ), ((err) =>
          @log 'warn', 'task.base', "Action #{action} performed not well.", err
        )
      else
        promise = Q.when action.run scope
    return promise

exports.BaseTask = BaseTask

Fix returned promise wasn't deep enough.


Model = require './model'

class RequestHistory extends Model

    url: -> "#{ env.SINGULARITY_BASE }/#{ constants.apiBase }/history/request/#{ @requestId }/requests"

    initialize: (models, { @requestId }) =>

    parse: (requestHistoryObjects) ->
        requestHistory = {}
        requestHistory.requestId = @requestId
        requestHistory.requestUpdates = requestHistoryObjects

        _.each requestHistory.requestUpdates, (requestUpdate, i) =>
            requestUpdate.userHuman = requestUpdate.user?.split('@')[0] ? '—'
            requestUpdate.createdAtHuman = utils.humanTimeAgo requestUpdate.createdAt
            requestUpdate.stateHuman = constants.requestStates[requestUpdate.state]

        requestHistory

module.exports = RequestHistory

Model = require './model'

class RequestHistory extends Model

    url: -> "#{ env.SINGULARITY_BASE }/#{ constants.apiBase }/history/request/#{ @requestId }/requests"

    initialize: (models, { @requestId }) =>

    parse: (requestHistoryObjects) ->
        requestHistory = {}
        requestHistory.requestId = @requestId
        requestHistory.requestUpdates = requestHistoryObjects

        _.each requestHistory.requestUpdates, (requestUpdate, i) =>
            requestUpdate.userHuman = requestUpdate.user?.split('@')[0] ? '—'
            requestUpdate.createdAtHuman = utils.humanTimeAgo requestUpdate.createdAt
            requestUpdate.stateHuman = constants.requestStates[requestUpdate.state]

        _.sortBy requestHistory.requestUpdates, (r) -> r.createdAt
        requestHistory.requestUpdates.reverse()

        requestHistory

module.exports = RequestHistory

Sort requestHistory requestUpdates by createdAt (so new items are at the top)


class @Autosave
  constructor: (field, key) ->
    @field = field

    key = key.join("/") if key.join?
    @key = "autosave/#{key}"

    @field.data "autosave", this

    @restore()

    @field.on "input", => @save()

  restore: ->
    return unless window.localStorage?

    try
      text = window.localStorage.getItem @key
    catch
      return

    @field.val text if text?.length > 0
    @field.trigger "input"

  save: ->
    return unless window.localStorage?

    text = @field.val()
    if text?.length > 0
      try
        window.localStorage.setItem @key, text
    else
      @reset()

  reset: ->
    return unless window.localStorage?

    try
      window.localStorage.removeItem @key

class @Autosave
  constructor: (field, key) ->
    @field = field

    key = key.join("/") if key.join?
    @key = "autosave/#{key}"

    @field.data "autosave", this

    @restore()

    @field.on "input", => @save()

  restore: ->
    return unless window.localStorage?

    try
      text = window.localStorage.getItem @key
    catch e
      return

    @field.val text if text?.length > 0
    @field.trigger "input"

  save: ->
    return unless window.localStorage?

    text = @field.val()
    if text?.length > 0
      try
        window.localStorage.setItem @key, text
    else
      @reset()

  reset: ->
    return unless window.localStorage?

    try
      window.localStorage.removeItem @key

Fix syntax error in autosave coffeescript.


JSONAPIClient = {Resource} = require 'json-api-client'
config = require './config'

apiClient = new JSONAPIClient config.host + '/api',
  'Content-Type': 'application/json'
  'Accept': 'application/vnd.api+json; version=1'

apiClient.type('classifications').Resource = require './classification'

apiClient.handleError = (request) ->
  response = try JSON.parse request.responseText
  if response?.error?
    errorMessage = response.error
    if response.error_description?
      errorMessage = "#{errorMessage} #{response.error_description}"
  else if response?.errors?[0].message?
    errorMessage = for {message} in response.errors
      if typeof message is 'string'
        message
      else
        ("#{key} #{error}" for key, error of message).join '\n'
    errorMessage = errorMessage.join '\n'

  errorMessage ?= request.responseText?.trim() || "#{request.status} #{request.statusText}"
  throw new Error errorMessage

module.exports = apiClient
window.zooAPI = apiClient

JSONAPIClient = {Resource} = require 'json-api-client'
config = require './config'

apiClient = new JSONAPIClient config.host + '/api',
  'Content-Type': 'application/json'
  'Accept': 'application/vnd.api+json; version=1'

apiClient.type('classifications').Resource = require './classification'

apiClient.handleError = (request) ->
  response = try JSON.parse request.responseText
  if response?.error?
    errorMessage = response.error
    if response.error_description?
      errorMessage = "#{errorMessage} #{response.error_description}"
  else if response?.errors?[0].message?
    errorMessage = for {message} in response.errors
      if typeof message is 'string'
        message
      else
        ("#{key} #{error}" for key, error of message).join '\n'
    errorMessage = errorMessage.join '\n'

  # Manually set a reasonable error when we get HTML back (currently 500s will do this).
  if request.responseText?.indexOf('<!DOCTYPE') isnt -1
    errorMessage ?= "There was a problem on the server. #{request.responseURL} → #{request.status}"

  errorMessage ?= request.responseText?.trim() || "#{request.status} #{request.statusText}"
  throw new Error errorMessage

module.exports = apiClient
window.zooAPI = apiClient

Set manual error message for 500 responses


'menu': [
  {
    'label': 'View'
    'submenu': [
      'label': 'Toggle Treeview'
      'command': 'tree-view:toggle'
    ]
  }
  {
    'label': 'Packages'
    'submenu': [
      'label': 'Tree View'
      'submenu': [
        { 'label': 'Focus', 'command': 'tree-view:toggle-focus' }
        { 'label': 'Toggle', 'command': 'tree-view:toggle' }
        { 'label': 'Reveal Active File', 'command': 'tree-view:reveal-active-file' }
      ]
    ]
  }
]

'context-menu':
  '.tree-view':
    'Add File': 'tree-view:add'
    'Add Folder': 'tree-view:add'
    'Rename': 'tree-view:move'
    'Delete': 'tree-view:remove'

'menu': [
  {
    'label': 'View'
    'submenu': [
      'label': 'Toggle Tree View'
      'command': 'tree-view:toggle'
    ]
  }
  {
    'label': 'Packages'
    'submenu': [
      'label': 'Tree View'
      'submenu': [
        { 'label': 'Focus', 'command': 'tree-view:toggle-focus' }
        { 'label': 'Toggle', 'command': 'tree-view:toggle' }
        { 'label': 'Reveal Active File', 'command': 'tree-view:reveal-active-file' }
      ]
    ]
  }
]

'context-menu':
  '.tree-view':
    'Add File': 'tree-view:add'
    'Add Folder': 'tree-view:add'
    'Rename': 'tree-view:move'
    'Delete': 'tree-view:remove'

Rename Treeview to Tree View in View menu

Synchronizes it to the same label used in the Packages menu.


define (require) ->
  Backbone = require('backbone')
  settings = require('settings')
  router = require('router')

  AUTHORING = "#{location.protocol}//#{settings.cnxauthoring.host}:#{settings.cnxauthoring.port}"

  return class RoleAcceptance extends Backbone.Model
    id = window.location.pathname.match(/\/[^\/]+$/)
    url: "#{AUTHORING}/contents#{id}@draft/acceptance"

    initialize: () =>
      @fetch
        reset: true,
        xhrFields: withCredentials: true
      .fail (response) =>
        router.appView.render('error', {code: response.status})

    save: (key, val, options) ->
      if not key? or typeof key is 'object'
        attrs = key
        options = val
      else
        attrs = {}
        attrs[key] = val

      options = _.extend(
        dataType: 'xml'
        xhrFields:
          withCredentials: true
      , options)

      return super(attrs, options)

Send cookie info on role updates

Send cookie info on role updates


MinimapSelectionView = require './minimap-selection-view'

module.exports =

  active: false
  views: {}

  activate: (state) ->
    try
      atom.packages.activatePackage('minimap').then (minimapPackage) =>
        @minimap = require minimapPackage.path
        return @deactivate() unless @minimap.versionMatch('3.x')

        @minimap.registerPlugin 'selection', this
    catch
      @deactivate

  deactivate: ->
    @minimap.unregisterPlugin 'selection'
    @minimap = null

  isActive: -> @active
  activatePlugin: ->
    return if @active
    @active = true

    @subscription = @minimap.eachMinimapView ({view}) =>
      selectionView = new MinimapSelectionView(view)
      selectionView.attach()

      @views[view.editor.id] = selectionView

  deactivatePlugin: ->
    view.destroy() for id,view of @views
    return unless @active
    @active = false
    @views = {}

    @subscription.off()

MinimapSelectionView = require './minimap-selection-view'

module.exports =

  active: false
  views: {}

  activate: (state) ->
    try
      atom.packages.activatePackage('minimap').then (minimapPackage) =>
        @minimap = require minimapPackage.path
        return @deactivate() unless @minimap.versionMatch('3.x')

        @minimap.registerPlugin 'selection', this
    catch
      @deactivate

  deactivate: ->
    @minimap.unregisterPlugin 'selection'
    @minimap = null

  isActive: -> @active
  activatePlugin: ->
    return if @active
    @active = true

    @subscription = @minimap.observeMinimaps ({view}) =>
      selectionView = new MinimapSelectionView(view)
      selectionView.attach()

      @views[view.editor.id] = selectionView

  deactivatePlugin: ->
    view.destroy() for id,view of @views
    return unless @active
    @active = false
    @views = {}

    @subscription.off()

Fix use of deprecated minimap API

:bug: Fix use of deprecated minimap API


angular.module 'ngtuvok'
  .factory "BlogService", (DataFactory) ->
    # $resource '/api/posts'

    posts = DataFactory.query ->
      console.log posts
      return

    getLastPost: ->
      # return $resource.query ->
      return posts

angular.module 'ngtuvok'
  .factory "BlogService", (DataFactory) ->
    # $resource '/api/posts'

    posts = DataFactory.query ->
      # console.log posts
      return

    getLastPost: ->
      # return $resource.query ->
      return posts

    getPostById: (id) ->
      post = DataFactory.get({ id: id }, ->
        console.log post
      )
      return post

    getPosts: (start, end) ->
      # return $resource.query ->
      return posts

Add methods to get posts

Add methods to get posts


Neighborly.Projects = {} if Neighborly.Projects is undefined

Neighborly.Projects.New =
  init: Backbone.View.extend
    el: '.new-project-page'

    initialize: ->
      _.bindAll(this, 'changeCategoryImage')
      this.$('#project_category_id').change this.changeCategoryImage

    changeCategoryImage: (event)->
      category = $(event.currentTarget).find(':selected').text().replace(/\s+/g, '-').toLowerCase()
      this.$el[0].className = this.$el[0].className.replace(/( category-.*)/, '')

      if category != 'select-an-option'
        this.$el.addClass("category-#{category}")

  modules: -> [Neighborly.SearchCities]

Neighborly.Projects ?= {}
Neighborly.Channels ?= {}
Neighborly.Channels.Projects ?= {}

Neighborly.Channels.Projects.New =
  modules: -> [Neighborly.Projects.New]

Neighborly.Projects.New =
  init: Backbone.View.extend
    el: '.new-project-page'

    initialize: ->
      _.bindAll(this, 'changeCategoryImage')
      this.$('#project_category_id').change this.changeCategoryImage

    changeCategoryImage: (event)->
      category = $(event.currentTarget).find(':selected').text().replace(/\s+/g, '-').toLowerCase()
      this.$el[0].className = this.$el[0].className.replace(/( category-.*)/, '')

      if category != 'select-an-option'
        this.$el.addClass("category-#{category}")

  modules: -> [Neighborly.SearchCities]

Make the javascript for new project work on channel new project


#
# Use this module to define all third-party dependencies
# that are used in Doubtfire
#
angular.module('doubtfire.config.vendor-dependencies', [
  # ng*
  'ngCookies'
  'ngCsv'
  'ngSanitize'

  # templates
  'templates-app'
  'templates-common'

  # ui.*
  'ui.router'
  'ui.bootstrap'
  'ui.codemirror'

  # other libraries
  'angularFileUpload'
  'angular.filter'
  'localization'
  'markdown'
  'nvd3'
  'xeditable'
  'LocalStorageModule'
  'angular-md5'

  # analytics
  'angulartics'
  'angulartics.google.analytics'
])

#
# Use this module to define all third-party dependencies
# that are used in Doubtfire
#
angular.module('doubtfire.config.vendor-dependencies', [
  # ng*
  'ngCookies'
  'ngCsv'
  'ngSanitize'

  # templates
  'templates-app'

  # ui.*
  'ui.router'
  'ui.bootstrap'
  'ui.codemirror'

  # other libraries
  'angularFileUpload'
  'angular.filter'
  'localization'
  'markdown'
  'nvd3'
  'xeditable'
  'LocalStorageModule'
  'angular-md5'

  # analytics
  'angulartics'
  'angulartics.google.analytics'
])

QUALITY: Remove import of empty templates-common.js


React             = require 'react/addons'
Editable          = require '../high_order/editable'

List              = require '../common/list'
Revision          = require './revision'
RevisionStore     = require '../../stores/revision_store'
ServerActions     = require '../../actions/server_actions'

getState = ->
  revisions: RevisionStore.getModels()

RevisionList = React.createClass(
  displayName: 'RevisionList'
  render: ->
    elements = @props.revisions.map (revision) =>
      <Revision revision={revision} key={revision.id} {...@props} />

    keys =
      'rating_num':
        'label': I18n.t('revision.class')
        'desktop_only': true
      'title':
        'label': I18n.t('revision.title')
        'desktop_only': false
      'edited_by':
        'label': I18n.t('revision.edited_by')
        'desktop_only': true
      'characters':
        'label': I18n.t('revision.chars_added')
        'desktop_only': true
      'date':
        'label': I18n.t('revision.date_time')
        'desktop_only': true
        'info_key': 'revisions.time_doc'

    <List
      elements={elements}
      keys={keys}
      table_key='revisions'
      store={RevisionStore}
    />
)

module.exports = Editable(RevisionList, [RevisionStore], ServerActions.saveRevisions, getState)

React             = require 'react/addons'
Editable          = require '../high_order/editable'

List              = require '../common/list'
Revision          = require './revision'
RevisionStore     = require '../../stores/revision_store'
ServerActions     = require '../../actions/server_actions'

getState = ->
  revisions: RevisionStore.getModels()

RevisionList = React.createClass(
  displayName: 'RevisionList'
  render: ->
    elements = @props.revisions.map (revision) =>
      <Revision revision={revision} key={revision.id} {...@props} />

    keys =
      'rating_num':
        'label': I18n.t('revisions.class')
        'desktop_only': true
      'title':
        'label': I18n.t('revisions.title')
        'desktop_only': false
      'edited_by':
        'label': I18n.t('revisions.edited_by')
        'desktop_only': true
      'characters':
        'label': I18n.t('revisions.chars_added')
        'desktop_only': true
      'date':
        'label': I18n.t('revisions.date_time')
        'desktop_only': true
        'info_key': 'revisions.time_doc'

    <List
      elements={elements}
      keys={keys}
      table_key='revisions'
      store={RevisionStore}
    />
)

module.exports = Editable(RevisionList, [RevisionStore], ServerActions.saveRevisions, getState)

Fix message keys in RevisionList

Fix message keys in RevisionList

Resolves #471


module.exports = (e, dataTransfer, iconAndSize) ->
  image = iconAndSize[0]
  if image instanceof Image && !image.complete
    # Early exit; not loaded image will not work and more importantly it craches Safari 6
    return

  if dataTransfer.setDragImage
    if image instanceof HTMLElement
      # Chrome hack; position the drag element where the UA are suppose to position it.
      # This since UA's requires it to be in the DOM and Chrome requires it to be in view…
      iconAndSize[0] = image = image.cloneNode true
      image.style.position = "absolute"
      image.style.left = "#{e.clientX - iconAndSize[1]}px"
      image.style.top = "#{e.clientY - iconAndSize[2]}px"
      document.body.appendChild image
      # Remove it from the DOM at the next run loop
      setTimeout(->
        document.body.removeChild image
      , 0)

    dataTransfer.setDragImage.apply dataTransfer, iconAndSize

module.exports = (e, dataTransfer, iconAndSize) ->
  image = iconAndSize[0]
  if image instanceof Image && !image.complete
    # Early exit; not loaded image will not work and more importantly it craches Safari 6
    return

  if dataTransfer.setDragImage
    if image instanceof HTMLElement
      # Chrome hack; position the drag element where the UA are suppose to position it.
      # This since UA's requires it to be in the DOM and Chrome requires it to be in view…
      iconAndSize[0] = image = image.cloneNode true
      image.style.position = "fixed"
      image.style.left = "#{e.clientX - iconAndSize[1]}px"
      image.style.top = "#{e.clientY - iconAndSize[2]}px"
      document.body.appendChild image
      # Remove it from the DOM at the next run loop
      setTimeout(->
        document.body.removeChild image
      , 0)

    dataTransfer.setDragImage.apply dataTransfer, iconAndSize

Update chrome hack to use position: fixed

For reasons unknown, we were experiencing UI bugginess with the drag image
after updating jQuery.

Chaging the position to fixed instead of absolute fixed the problem.


# Public: GrammarUtils.OperatingSystem - a module which exposes different
# platform related helper functions.
module.exports =
  isDarwin: ->
    @platform() is 'darwin'

  isWindows: ->
    @platform() is 'win32'

  isLinux: ->
    @platform() is 'linux'

  platform: ->
    process.platform

  release: ->
    process.release

Enable the reading of the OS release number


assert = require 'assert'
fs     = require 'fs'
path   = require 'path'

describe 'third-party module', ->
  fixtures = path.join __dirname, 'fixtures'

  xdescribe 'unzip', ->
    unzip = require 'unzip'

    it 'fires close event', (done) ->
      fs.createReadStream(path.join(fixtures, 'zip', 'a.zip'))
        .pipe(unzip.Parse())
        .on('close', done)

  describe 'runas', ->
    it 'can be required in renderer', ->
      require 'runas'

    it 'can be required in node binary', (done) ->
      runas = path.join fixtures, 'module', 'runas.js'
      child = require('child_process').fork runas
      child.on 'message', (msg) ->
        assert.equal msg, 'ok'
        done()

assert = require 'assert'
fs     = require 'fs'
path   = require 'path'

describe 'third-party module', ->
  fixtures = path.join __dirname, 'fixtures'

  describe 'runas', ->
    it 'can be required in renderer', ->
      require 'runas'

    it 'can be required in node binary', (done) ->
      runas = path.join fixtures, 'module', 'runas.js'
      child = require('child_process').fork runas
      child.on 'message', (msg) ->
        assert.equal msg, 'ok'
        done()

Remove the unzip spec completely.

Remove the unzip spec completely.


React = require 'react'

module.exports = React.PropTypes.shape(
  title:                    React.PropTypes.string
  children:                 React.PropTypes.array
  chapter_section:          React.PropTypes.array
  current_level:            React.PropTypes.number
  questions_answered_count: React.PropTypes.number
)

React = require 'react'

module.exports = React.PropTypes.shape(
  title:                    React.PropTypes.string
  children:                 React.PropTypes.array
  chapter_section:          React.PropTypes.array
  clue:                     React.PropTypes.object
  questions_answered_count: React.PropTypes.number
)

Add clue parameter to validation

Add clue parameter to validation


class Article
   constructor: ->

   set_title: (@title) ->

   set_content: (@content) ->

   set_date: (@date) ->

   set_section: (@section) ->

   parse: (html) ->
      page = $(html)
      @set_title page.find("#articleContent h1").text()
      raw_content = page.find("#masterContent .ArticleContent_Inner")
      @set_content _.chain(raw_content).map(
                                            (paragraph) -> $(paragraph).find("p").removeAttr("class").prop("outerHTML")
                                             ).reduce(
                                                (memo, obj) -> memo + obj
                                             ).value()

root = exports ? this
root.Article = Article

class Article
   constructor: ->

   set_title: (@title) ->

   set_content: (@content) ->

   set_date: (@date) ->

   set_section: (@section) ->

   parse: (html) ->
      page = $(html)
      @set_title page.find("#articleContent h1").text()
      raw_content = page.find("#masterContent .ArticleContent_Inner")
      @set_content _.chain(raw_content).map(
                                            (paragraph) -> $(paragraph).removeAttr("class").prop("outerHTML")
                                             ).reduce(
                                                (memo, obj) -> memo + obj
                                             ).value()

root = exports ? this
root.Article = Article

Insert subtitle to the content

Insert subtitle to the content

Signed-off-by: Lincoln Lee <46f1a0bd5592a2f9244ca321b129902a06b53e03@lincoln.hk>


$(document).ready ->

  $('#messages-kiitos li').on 'click', (event) ->
    event.preventDefault()
    id = $(@).data('id')
    $.get "messages/#{id}"

$(document).ready ->

  $('#messages-kiitos .list-group li').on 'click', (event) ->
    event.preventDefault()
    id = $(@).data('id')
    $.get "messages/#{id}"

Implement 'recent' link on messages section


#<< AppEngine/Helpers/Helpers

class StrictObject extends Backbone.Events
  @expectedParameters: []
  @applyParameters: []
  @isAbstract: -> @ == StrictObject

  constructor: (conf) ->
    #check that this is not an abstract class
    if @__proto__.constructor.isAbstract()
      throw new Error "Unable to create instance of Abstract class '#{@.__proto__.constructor.getName()}'"

    #Check that all config params were passed through correctly
    AppEngine.Helpers.assertParametersExist @.__proto__.constructor.expectedParameters, conf
    AppEngine.Helpers.applyToObject @__proto__.constructor.applyParameters, conf, @

#<< AppEngine/Helpers/Helpers

class StrictObject extends Backbone.Events
  @expectedParameters: []
  @applyParameters: []
  @isAbstract: -> @ == StrictObject

  constructor: (conf) ->
    #check that this is not an abstract class
    if @__proto__.constructor.isAbstract()
      throw new Error "Unable to create instance of Abstract class '#{@.__proto__.constructor.getName()}'"

    #Check that all config params were passed through correctly
    if @.__proto__.constructor.expectedParameters.length > 0
      if conf
        AppEngine.Helpers.assertParametersExist @.__proto__.constructor.expectedParameters, conf
      else
        throw new Error "StrictObject: There are required parameters but the options are not defined"

    AppEngine.Helpers.applyToObject @__proto__.constructor.applyParameters, conf, @ if conf

Fix parameter asserting when the options passed through are undefined


'menu': [
  {
    'label': 'Edit'
    'submenu': [
      'label': 'Lines'
      'submenu': [
        { 'label': 'Sort', 'command': 'sort-lines:sort' }
        { 'label': 'Reverse Sort', 'command': 'sort-lines:reverse-sort' }
        { 'label': 'Unique', 'command': 'sort-lines:unique' }
        { 'label': 'Case-insensitive Sort', 'command': 'sort-lines:case-insensitive-sort' }
      ]
    ]
  }
]

'menu': [
  {
    'label': 'Edit'
    'submenu': [
      'label': 'Lines'
      'submenu': [
        { 'label': 'Sort', 'command': 'sort-lines:sort' }
        { 'label': 'Reverse Sort', 'command': 'sort-lines:reverse-sort' }
        { 'label': 'Unique', 'command': 'sort-lines:unique' }
        { 'label': 'Sort (Case Insentivive)', 'command': 'sort-lines:case-insensitive-sort' }
      ]
    ]
  }
]

Tweak menu label for case insensitive sort


Decrease threads number in order to show threads working


#= require trix/views/text_view
#= require fixtures

module "Trix.TextView"

test "#createElementsForText", ->
  text = fixture("plain")
  elements = getElementsForText(text)
  equal elements.length, 1, "one element for plain string"

  el = elements[0]
  equal el.tagName.toLowerCase(), "span", "container element is a span"
  equal el.trixPosition, 0, "container element has a trixPosition"
  equal el.childNodes.length, 1, "container element has one child node"

  node = el.firstChild
  equal node.nodeType, Node.TEXT_NODE, "child node is a text node"
  equal node.data, text.toString(), "child node contains text string"
  equal node.trixPosition, 0, "child node has a trixPosition property"
  equal node.trixLength, text.getLength(), "child node has a trixLength property"

  text = Trix.Text.textForStringWithAttributes(text.toString() + "\n")
  elements = getElementsForText(text)
  equal elements.length, 2, "two elements for string ending with a newline"
  equal elements[0].lastChild.tagName.toLowerCase(), "br", "container element's last child is a BR"
  equal elements[1].tagName.toLowerCase(), "br", "last element is an extra BR"

# Helpers

getElementsForText = (text) ->
  element = document.createElement("div")
  textView = new Trix.TextView element, text
  textView.createElementsForText()

#= require trix/views/text_view
#= require fixtures

module "Trix.TextView"

test "#createElementsForText", ->
  text = fixture("plain")
  elements = getElementsForText(text)
  equal elements.length, 1, "one element for plain string"

  el = elements[0]
  equal el.tagName.toLowerCase(), "span", "container element is a span"
  equal el.trixPosition, 0, "container element has a trixPosition"
  equal el.childNodes.length, 1, "container element has one child node"

  node = el.firstChild
  equal node.nodeType, Node.TEXT_NODE, "child node is a text node"
  equal node.data, text.toString(), "child node contains text string"
  equal node.trixPosition, 0, "child node has a trixPosition property"
  equal node.trixLength, text.getLength(), "child node has a trixLength property"

  text = Trix.Text.textForStringWithAttributes(fixture("plain").toString() + "\n")
  elements = getElementsForText(text)
  equal elements.length, 2, "two elements for string ending with a newline"
  equal elements[0].lastChild.tagName.toLowerCase(), "br", "container element's last child is a BR"
  equal elements[1].tagName.toLowerCase(), "br", "last element is an extra BR"

# Helpers

getElementsForText = (text) ->
  element = document.createElement("div")
  textView = new Trix.TextView element, text
  textView.createElementsForText()

Load fixture instead of relying on exitisting var


'*':
  'editor':
    'fontFamily': 'Fira Mono OT'
    'showIndentGuide': true
    'tabLength': 4
    'softWrap': true
    'invisibles': {}
    'zoomFontWhenCtrlScrolling': false
  'core':
    'disabledPackages': [
      'language-objective-c'
      'archive-view'
      'autosave'
      'bookmarks'
      'language-clojure'
      'language-perl'
      'language-php'
      'language-toml'
      'snippets'
      'welcome'
      'spell-check'
    ]
    'themes': [
      'seti-ui'
      'seti-syntax'
    ]
    'projectHome': '/home/ai/Dev'
    'autoHideMenuBar': true
  'exception-reporting':
    'userId': '51ccaaae-04bc-1ed3-3445-f9bd1a2f3a71'
  'welcome':
    'showOnStartup': false
  'markdown-preview':
    'breakOnSingleNewline': true
  'spell-check': {}
'.ruby.source':
  'editor':
    'tabLength': 2
'.coffee.source':
  'editor':
    'tabLength': 2
'.sass.source':
  'editor':
    'tabLength': 2

Change tab size for Ruby, Coffee and Sass


# This is a manifest file that'll be compiled into application.js, which will include all the files
# listed below.
#
# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
#
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# compiled file.
#
# Read Sprockets README (https:#github.com/sstephenson/sprockets#sprockets-directives) for details
# about supported directives.
#
#= require jquery
#= require jquery_ujs
#= require rails-timeago
#= require ansi_up
#= require_tree .

$(document).on 'click', 'a.disabled', (event) ->
  event.preventDefault()

jQuery ->
  notificationNotice = $('.notifications')
  btn = notificationNotice.find('button')

  if $.notifyCheck() == $.NOTIFY_NOT_ALLOWED
    btn.click () =>
      $.notifyRequest()
      notificationNotice.hide()
  else
    notificationNotice.hide()

# This is a manifest file that'll be compiled into application.js, which will include all the files
# listed below.
#
# Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
# or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
#
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# compiled file.
#
# Read Sprockets README (https:#github.com/sstephenson/sprockets#sprockets-directives) for details
# about supported directives.
#
#= require jquery
#= require jquery_ujs
#= require rails-timeago
#= require jquery-notify
#= require ansi_up
#= require_tree .

$(document).on 'click', 'a.disabled', (event) ->
  event.preventDefault()

jQuery ->
  notificationNotice = $('.notifications')
  btn = notificationNotice.find('button')

  if $.notifyCheck() == $.NOTIFY_NOT_ALLOWED
    btn.click () =>
      $.notifyRequest()
      notificationNotice.hide()
  else
    notificationNotice.hide()

Add jQuery notify back in

Add jQuery notify back in


Meteor.methods
	setAvatarFromService: (dataURI, service) ->
		if not Meteor.userId()
			throw new Meteor.Error 203, '[methods] typingStatus -> Usuário não logado'

		user = Meteor.user()

		{image, contentType} = RocketFile.dataURIParse dataURI

		rs = RocketFile.bufferToStream new Buffer(image, 'base64')
		ws = RocketFileAvatarInstance.createWriteStream user.username, contentType
		ws.on 'end', Meteor.bindEnvironment ->
			Meteor.users.update {_id: user._id}, {$set: {avatarOrigin: service}}

		rs.pipe(ws)

	resetAvatar: (image, service) ->
		if not Meteor.userId()
			throw new Meteor.Error 203, '[methods] typingStatus -> Usuário não logado'

		user = Meteor.user()

		Avatars.remove {'copies.avatars.name': user.username}

		Meteor.users.update user._id, {$unset: {avatarOrigin: 1}}

Meteor.methods
	setAvatarFromService: (dataURI, service) ->
		if not Meteor.userId()
			throw new Meteor.Error 203, '[methods] typingStatus -> Usuário não logado'

		user = Meteor.user()

		{image, contentType} = RocketFile.dataURIParse dataURI

		rs = RocketFile.bufferToStream new Buffer(image, 'base64')
		ws = RocketFileAvatarInstance.createWriteStream user.username, contentType
		ws.on 'end', Meteor.bindEnvironment ->
			Meteor.users.update {_id: user._id}, {$set: {avatarOrigin: service}}

		rs.pipe(ws)

	resetAvatar: (image, service) ->
		if not Meteor.userId()
			throw new Meteor.Error 203, '[methods] typingStatus -> Usuário não logado'

		user = Meteor.user()

		RocketFileAvatarInstance.deleteFile user.username

		Meteor.users.update user._id, {$unset: {avatarOrigin: 1}}

Change method 'resetAvatar' to use RocketFile


$ ->
  $.rails.allowAction = (element) ->
    message = element.data('confirm')
    fire = $.rails.fire
    if message and fire(element, 'confirm')
      title = if $(document.body).hasClass('videos') then 'Delete this video' else 'Delete your account'
      dialog = new Dialog(title, message, confirmLabel: '<i class="icon-trash" role="presentation" aria-hidden="true"></i>Yes')
      dialog.onConfirm () ->
        callback = fire(element, 'confirm:complete', [true])
        if (callback)
          allowActionOrig = $.rails.allowAction
          $.rails.allowAction = () -> true
          element.trigger('click')
          $.rails.allowAction = allowActionOrig
      dialog.onClose () ->
        element.focus()
      dialog.show()
    not message or false

$ ->
  $.rails.allowAction = (element) ->
    message = element.data('confirm')
    fire = $.rails.fire
    if message and fire(element, 'confirm')
      title = if $(document.body).hasClass('videos') then 'Delete this video' else 'Delete your account'
      dialog = new Dialog(title, message, confirmLabel: '<i class="icon-trash" role="presentation" aria-hidden="true"></i>Yes')
      dialog.onConfirm () ->
        callback = fire(element, 'confirm:complete', [true])
        if (callback)
          allowActionOrig = $.rails.allowAction
          $.rails.allowAction = () -> true
          element.trigger('click')
          $.rails.allowAction = allowActionOrig
          dialog.destroy()
      dialog.onClose () ->
        element.focus()
      dialog.show()
    not message or false

Destroy confirm dialog when user has confirmed


_ = require 'underscore'
BufferedProcess = require 'buffered-process'
$ = require 'jquery'

module.exports =
class LoadPathsTask
  constructor: (@callback) ->

  start: ->
    rootPath = project.getPath()
    ignoredNames = config.get('fuzzyFinder.ignoredNames') ? []
    ignoredNames = ignoredNames.concat(config.get('core.ignoredNames') ? [])
    ignoreGitIgnoredFiles =  config.get('core.hideGitIgnoredFiles')

    command = require.resolve 'nak'
    args = ['-l', rootPath]
    args.unshift('--addVCSIgnores') if config.get('nak.addVCSIgnores')
    args.unshift('-d', ignoredNames.join(',')) if ignoredNames.length > 0

    paths = []
    deferred = $.Deferred()
    exit = (code) =>
      if code is -1
        deferred.reject({command, code})
      else
        @callback(paths)
        deferred.resolve()
    stdout = (data) ->
      paths.push.apply(paths, _.compact(data.split('\n')))

    @process = new BufferedProcess({command, args, stdout, exit})
    deferred

  abort: ->
    if @process?
      @process.kill()
      @process = null

_ = require 'underscore'
BufferedProcess = require 'buffered-process'
$ = require 'jquery'

module.exports =
class LoadPathsTask
  constructor: (@callback) ->

  start: ->
    rootPath = project.getPath()
    ignoredNames = config.get('fuzzyFinder.ignoredNames') ? []
    ignoredNames = ignoredNames.concat(config.get('core.ignoredNames') ? [])
    ignoreGitIgnoredFiles =  config.get('core.hideGitIgnoredFiles')

    command = require.resolve 'nak'
    args = ['-l', rootPath]
    args.unshift('--addVCSIgnores') if config.get('nak.addVCSIgnores')
    args.unshift('-d', ignoredNames.join(',')) if ignoredNames.length > 0

    paths = []
    deferred = $.Deferred()
    exit = (code) =>
      if code is -1
        deferred.reject({command, code})
      else
        @callback(paths)
        deferred.resolve()
    stdout = (data) ->
      paths.push(_.compact(data.split('\n'))...)

    @process = new BufferedProcess({command, args, stdout, exit})
    deferred

  abort: ->
    if @process?
      @process.kill()
      @process = null

Use splat instead of apply

Use splat instead of apply


ViewRegistry = require '../src/view-registry'
Panel = require '../src/panel'
PanelContainer = require '../src/panel-container'

describe "PanelContainer", ->
  [container] = []

  class TestPanelItem
    constructior: ->

  beforeEach ->
    viewRegistry = new ViewRegistry
    container = new PanelContainer({viewRegistry})

  describe "::addPanel(panel)", ->
    it 'emits an onDidAddPanel event with the index the panel was inserted at', ->
      container.onDidAddPanel addPanelSpy = jasmine.createSpy()

      panel1 = new Panel(item: new TestPanelItem(), location: 'left')
      container.addPanel(panel1)
      expect(addPanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})

      panel2 = new Panel(item: new TestPanelItem(), location: 'left')
      container.addPanel(panel2)
      expect(addPanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1})

  describe "when a panel is destroyed", ->
    it 'emits an onDidRemovePanel event with the index of the removed item', ->
      container.onDidRemovePanel removePanelSpy = jasmine.createSpy()

      panel1 = new Panel(item: new TestPanelItem(), location: 'left')
      container.addPanel(panel1)
      panel2 = new Panel(item: new TestPanelItem(), location: 'left')
      container.addPanel(panel2)

      expect(removePanelSpy).not.toHaveBeenCalled()

      panel2.destroy()
      expect(removePanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1})

      panel1.destroy()
      expect(removePanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})

ViewRegistry = require '../src/view-registry'
Panel = require '../src/panel'
PanelContainer = require '../src/panel-container'

describe "PanelContainer", ->
  [container] = []

  class TestPanelItem
    constructior: ->

  beforeEach ->
    viewRegistry = new ViewRegistry
    container = new PanelContainer({viewRegistry})

  describe "::addPanel(panel)", ->
    it 'emits an onDidAddPanel event with the index the panel was inserted at', ->
      container.onDidAddPanel addPanelSpy = jasmine.createSpy()

      panel1 = new Panel(item: new TestPanelItem())
      container.addPanel(panel1)
      expect(addPanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})

      panel2 = new Panel(item: new TestPanelItem())
      container.addPanel(panel2)
      expect(addPanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1})

  describe "when a panel is destroyed", ->
    it 'emits an onDidRemovePanel event with the index of the removed item', ->
      container.onDidRemovePanel removePanelSpy = jasmine.createSpy()

      panel1 = new Panel(item: new TestPanelItem())
      container.addPanel(panel1)
      panel2 = new Panel(item: new TestPanelItem())
      container.addPanel(panel2)

      expect(removePanelSpy).not.toHaveBeenCalled()

      panel2.destroy()
      expect(removePanelSpy).toHaveBeenCalledWith({panel: panel2, index: 1})

      panel1.destroy()
      expect(removePanelSpy).toHaveBeenCalledWith({panel: panel1, index: 0})

Remove location junk from panel creation


###
HTML Renderer

@namespace Atoms.Core
@class Attributes

@author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
###
"use strict"

Atoms.Core.Attributes =

  ###
  Set the parent instance to current instance.
  @method setParent
  ###
  scaffold: ->
    # Assign Parrent
    @parent = {}
    if @attributes?.parent?
      @parent = @attributes.parent
      delete @attributes.parent

    # Assign Container
    @container = @attributes.container or @parent.el or document.body
    delete @attributes.container

    # Assign Entity
    if @attributes?.entity?
      @entity = @attributes.entity
      delete @attributes.entity

  chemistry: (children) ->
    children = @attributes.children or @default.children
    for item, index in children
      for key of item when not @available or key in @available
        base = key.split(".")
        type = base[0]
        class_name = base[1]
        if Atoms[type][class_name]?
          attributes = item[key]
          if @default?.children?[index]?[key]?
            attributes = Atoms.Core.Helper.mix item[key], @default.children?[index]?[key]
          @children.push @instance type, class_name, attributes

  instance: (type, class_name, attributes) ->
    attributes.parent = @
    new Atoms[type][class_name] attributes

###
HTML Renderer

@namespace Atoms.Core
@class Attributes

@author Javier Jimenez Villar <javi@tapquo.com> || @soyjavi
###
"use strict"

Atoms.Core.Attributes =

  ###
  Set the parent instance to current instance.
  @method setParent
  ###
  scaffold: ->
    # Assign Parrent
    @parent = {}
    if @attributes?.parent?
      @parent = @attributes.parent
      delete @attributes.parent

    # Assign Container
    @container = @attributes.container or @parent.el or document.body
    delete @attributes.container

    # Assign Entity
    if @attributes?.entity?
      @entity = @attributes.entity
      delete @attributes.entity

  chemistry: (children) ->
    children = @attributes.children or @default.children
    for item, index in children
      for key of item when not @constructor.available or key in @constructor.available
        base = key.split(".")
        type = base[0]
        class_name = base[1]
        if Atoms[type][class_name]?
          attributes = item[key]
          if @default?.children?[index]?[key]?
            attributes = Atoms.Core.Helper.mix item[key], @default.children?[index]?[key]
          @children.push @instance type, class_name, attributes

  instance: (type, class_name, attributes={}) ->
    if @__available type, class_name
      attributes.parent = attributes.parent or @
      new Atoms[type][class_name] attributes
    else
      throw "Instance no available in current container."

  __available: (type, class_name) ->
    instance = Atoms[type][class_name]
    instance = instance.base or instance.name
    (not @constructor.available or "#{type}.#{instance}" in @constructor.available)

Check available when creates a new instance


path = require 'path'
Module = require 'module'
ModuleCache = require '../src/module-cache'

describe 'ModuleCache', ->
  beforeEach ->
    spyOn(Module, '_findPath').andCallThrough()

  it 'resolves atom shell module paths without hitting the filesystem', ->
    require.resolve('shell')
    expect(Module._findPath.callCount).toBe 0

  it 'resolves relative core paths without hitting the filesystem', ->
    ModuleCache.add atom.getLoadSettings().resourcePath, {
      _atomModuleCache:
        extensions:
          '.json': [
            path.join('spec', 'fixtures', 'module-cache', 'file.json')
          ]
    }
    expect(require('./fixtures/module-cache/file.json').foo).toBe 'bar'
    expect(Module._findPath.callCount).toBe 0

path = require 'path'
Module = require 'module'
fs = require 'fs-plus'
temp = require 'temp'
ModuleCache = require '../src/module-cache'

describe 'ModuleCache', ->
  beforeEach ->
    spyOn(Module, '_findPath').andCallThrough()

  it 'resolves atom shell module paths without hitting the filesystem', ->
    require.resolve('shell')
    expect(Module._findPath.callCount).toBe 0

  it 'resolves relative core paths without hitting the filesystem', ->
    ModuleCache.add atom.getLoadSettings().resourcePath, {
      _atomModuleCache:
        extensions:
          '.json': [
            path.join('spec', 'fixtures', 'module-cache', 'file.json')
          ]
    }
    expect(require('./fixtures/module-cache/file.json').foo).toBe 'bar'
    expect(Module._findPath.callCount).toBe 0

  it 'resolves module paths to a compatible version provided by core', ->
    packagePath = fs.realpathSync(temp.mkdirSync('atom-package'))
    ModuleCache.add packagePath, {
      _atomModuleCache:
        folders: [{
          paths: [
            ""
          ]
          dependencies:
            'underscore-plus': '*'
        }]
    }
    ModuleCache.add atom.getLoadSettings().resourcePath, {
      _atomModuleCache:
        dependencies: [{
          name: 'underscore-plus'
          version: require('underscore-plus/package.json').version
          path: path.join('node_modules', 'underscore-plus', 'lib', 'underscore-plus.js')
        }]
    }

    indexPath = path.join(packagePath, 'index.js')
    fs.writeFileSync indexPath, """
      exports.load = function() {require('underscore-plus');};
    """

    packageMain = require(indexPath)
    Module._findPath.reset()
    packageMain.load()
    expect(Module._findPath.callCount).toBe 0

Add spec for resolving compatible module paths


# Define the Configuration
docpadConfig = {
	templateData:
		site:
			title: "Dorian Patterson"

		getPreparedTitle: -> if @document.title then "#{@document.title} | #{@site.title}" else @site.title
}

# Export the Configuration
module.exports = docpadConfig

# Define the Configuration
docpadConfig = {
	templateData:
		site:
			title: "Curly Hair Coder"

		getPreparedTitle: -> if @document.title then "#{@document.title} | #{@site.title}" else @site.title
		collections:
			pages: ->
				@getCollection("html").findAllLive({isPage:true})
}

# Export the Configuration
module.exports = docpadConfig

Change site title and add collection function.


{Document, Point, Range, Site} = require 'telepath'
_ = require 'underscore-plus'

module.exports =
  _: _
  BufferedNodeProcess: require '../src/buffered-node-process'
  BufferedProcess: require '../src/buffered-process'
  Directory: require '../src/directory'
  Document: Document
  File: require '../src/file'
  fs: require '../src/fs-utils'
  Git: require '../src/git'
  Point: Point
  Range: Range
  Site: Site

# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
  {$, $$, $$$, View} = require '../src/space-pen-extensions'

  module.exports.$ = $
  module.exports.$$ = $$
  module.exports.$$$ = $$$
  module.exports.Editor = require '../src/editor'
  module.exports.pathForRepositoryUrl = require('../src/project').pathForRepositoryUrl
  module.exports.RootView = require '../src/root-view'
  module.exports.SelectList = require '../src/select-list'
  module.exports.ScrollView = require '../src/scroll-view'
  module.exports.Task = require '../src/task'
  module.exports.View = View

{Document, Point, Range, Site} = require 'telepath'
_ = require 'underscore-plus'

module.exports =
  _: _
  apm: require 'atom-package-manager'
  BufferedNodeProcess: require '../src/buffered-node-process'
  BufferedProcess: require '../src/buffered-process'
  Directory: require '../src/directory'
  Document: Document
  File: require '../src/file'
  fs: require '../src/fs-utils'
  Git: require '../src/git'
  Point: Point
  Range: Range
  Site: Site

# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
  {$, $$, $$$, View} = require '../src/space-pen-extensions'

  module.exports.$ = $
  module.exports.$$ = $$
  module.exports.$$$ = $$$
  module.exports.Editor = require '../src/editor'
  module.exports.pathForRepositoryUrl = require('../src/project').pathForRepositoryUrl
  module.exports.RootView = require '../src/root-view'
  module.exports.SelectList = require '../src/select-list'
  module.exports.ScrollView = require '../src/scroll-view'
  module.exports.Task = require '../src/task'
  module.exports.View = View

Add apm to public API

Add apm to public API


$ ->
  $(".js-emoji").each ->
    $(@).html(emojione.toImage($(@).text()))

window.emojify = ->
  $(".js-emoji").each ->
    $(@).html(emojione.toImage($(@).text()))

$ -> emojify()

Make an emojify global function

Make an emojify global function


class CallbackDataSource extends DataSource

  constructor: (form_field, source) ->
    super(form_field, source)
    @results = {}

  search: (chosen, response_cb) ->
    ds = this
    # Call @source function, setting this to the chosen object
    # @param request
    # @param response_cb
    @source.call chosen, chosen.get_search_request(), (data) ->
      ds.did_search(chosen, response_cb, data)

  did_search: (chosen, response_cb, data) ->
    results = {}

    # Keep only results that have been chosen
    for value in chosen.choices()
      results[value] = @results[value]
    @results = results

    # Merge with new results
    options = (this.add_option child for child in data)

    response_cb options

  add_option: (child) ->
    item = @results[child.value] || child

    item.array_index = item.value
    item.html = item.label || item if not item.html?
    item.selected = item.selected || false
    item.disabled = item.disabled || false

    @results[item.value] = item
    item

  get_option_element: (array_index) ->
    this.get_option_element_by_value(array_index)

  get_item: (array_index) ->
    @results[array_index]

class CallbackDataSource extends DataSource

  constructor: (form_field, source) ->
    super(form_field, source)
    @results = {}

  search: (chosen, response_cb) ->
    ds = this
    # Call @source function, setting this to the chosen object
    # @param request
    # @param response_cb
    @source.call chosen, chosen.get_search_request(), (data) ->
      ds.did_search(chosen, response_cb, data)

  did_search: (chosen, response_cb, data) ->
    results = {}

    # Keep only results that have been chosen
    for value in chosen.choices()
      results[value] = @results[value]
    @results = results

    # Merge with new results
    options = (this.add_option child for child in data)

    response_cb options

  add_option: (child) ->
    item = @results[child.value] || child

    item.array_index = item.value
    item.text = item.label || item if not item.text?
    item.html = item.text if not item.html?
    item.selected = item.selected || false
    item.disabled = item.disabled || false

    @results[item.value] = item
    item

  get_option_element: (array_index) ->
    this.get_option_element_by_value(array_index)

  get_item: (array_index) ->
    @results[array_index]

Fix issue where item.text is not defined as expected


class TourUserView extends ActionButtonView
  template: 'tour/interesting_user'
  className: 'tour-interesting-user'
  templateHelpers: =>
    disabled_label: Factlink.Global.t.follow_user.capitalize()
    disable_label:  Factlink.Global.t.unfollow.capitalize()
    enabled_label:  Factlink.Global.t.following.capitalize()

  templateHelpers: =>
    disabled_label: Factlink.Global.t.follow_user.capitalize()
    disable_label:  Factlink.Global.t.unfollow.capitalize()
    enabled_label:  Factlink.Global.t.following.capitalize()

  enableHoverState: ->
    return if @justClicked
    super
    @$el.addClass 'hover'

  disableHoverState: ->
    super
    @$el.removeClass 'hover'

  updateButton: ->
    super
    @$el.toggleClass 'secondary', @buttonEnabled()

  buttonEnabled: ->
    @model.followers.followed_by_me()

  primaryAction: ->
    @model.follow()
    # TODO: favourite
    @updateButton()

  secondaryAction: ->
    @model.unfollow()
    @updateButton()

class window.TourUsersListView extends Backbone.Marionette.CollectionView
  itemView: TourUserView
  className: 'tour-interesting-users-list'

class TourUserView extends ActionButtonView
  template: 'tour/interesting_user'
  className: 'tour-interesting-user'
  templateHelpers: =>
    disabled_label: Factlink.Global.t.follow_user.capitalize()
    disable_label:  Factlink.Global.t.unfollow.capitalize()
    enabled_label:  Factlink.Global.t.following.capitalize()

  enableHoverState: ->
    return if @justClicked
    super
    @$el.addClass 'hover'

  disableHoverState: ->
    super
    @$el.removeClass 'hover'

  updateButton: ->
    super
    @$el.toggleClass 'secondary', @buttonEnabled()

  buttonEnabled: ->
    @model.followers.followed_by_me()

  primaryAction: ->
    @model.follow()
    # TODO: favourite
    @$el.removeClass 'hover'
    @updateButton()

  secondaryAction: ->
    @model.unfollow()
    @$el.removeClass 'hover'
    @updateButton()

class window.TourUsersListView extends Backbone.Marionette.CollectionView
  itemView: TourUserView
  className: 'tour-interesting-users-list'

Fix button interaction logic: disable hoverstate on click.


define [
  "backbone"
  "sp-utils-middleware"
  "common"
  "view/page"
  "view/modal"
],(
  Backbone
  Middleware
  common
  Page
  Modal
)->

  showPage=(View,options={},callback)->
    common.app.content.show View, options, callback

  class MiddlewareRouter extends Middleware
    auth:(async,args)->
      async.resolve "auth"

  middleware = new MiddlewareRouter

  Router = Backbone.Router.extend

    routes:
      "":"index"
      "!/rooms(/:id)": "rooms"
      "!/roomadd/:token": "roomAdd"
      "!/404": "error404"
      "*default":"default_router"

    index: middleware.wrap ->
      view = showPage Page.IndexPage

    rooms: middleware.wrap (id)->
      auto_id = common.user.get 'active_room_id' unless id?
      if auto_id?
        @navigate "!/rooms/#{auto_id}", {trigger: true}
        return
      view = showPage Page.MainPage
      view.setRoom id if id?

    roomAdd: middleware.wrap (token)->
      common.api.post_rooms_join(token).done (data)->
        Backbone.trigger "rooms:needUpdate"
        common.router "!/rooms/#{data.id}", {trigger:true}

    error404: middleware.wrap ->
      showPage Page.Error404Page

    default_router:->
      @navigate "!/404", {trigger:true,replace:true}

define [
  "backbone"
  "sp-utils-middleware"
  "common"
  "view/page"
  "view/modal"
],(
  Backbone
  Middleware
  common
  Page
  Modal
)->

  showPage=(View,options={},callback)->
    common.app.content.show View, options, callback

  class MiddlewareRouter extends Middleware
    auth:(async,args)->
      async.resolve "auth"

  middleware = new MiddlewareRouter

  Router = Backbone.Router.extend

    routes:
      "":"index"
      "!/rooms(/:id)": "rooms"
      "!/roomadd/:token": "roomAdd"
      "!/404": "error404"
      "*default":"default_router"

    index: middleware.wrap ->
      view = showPage Page.IndexPage

    rooms: middleware.wrap (id)->
      auto_id = common.user.get 'active_room_id' unless id?
      if auto_id?
        @navigate "!/rooms/#{auto_id}", {trigger: true}
        return
      view = showPage Page.MainPage
      view.setRoom id if id?

    roomAdd: middleware.wrap (token)->
      common.api.post_rooms_join(token)
        .done (data)->
          Backbone.trigger "rooms:needUpdate"
          common.router.navigate "!/rooms/#{data.id}", {trigger:true}
        .fail -> common.router.navigate "#", {trigger: true}

    error404: middleware.wrap ->
      showPage Page.Error404Page

    default_router:->
      @navigate "!/404", {trigger:true,replace:true}

Fix add room route work

Fix add room route work


$(document).ready ->

  $('#query').autocompleter {
    source: '/autocomplete/keywords',
    offset: 'results',
    highlightMatches: true
  }

  $('#location').autocompleter {
    source: '/autocomplete/places',
    offset: 'results',
    minLength: 4,
    highlightMatches: true
  }

  $('#flash a.close').click(sweet_hide)

  fix_lang_menu()

sweet_hide = ->
  alert_box = $(this).parent()
  properties = {
    height: 'toggle',
    marginBottom: 'toggle',
    marginTop: 'toogle',
    opacity: 'toggle',
    paddingBottom: 'toggle',
    paddingTop: 'toogle'
  }
  alert_box.animate properties, 'fast', check_flash

check_flash = ->
  flash_area = $('#flash')
  flash_area.slideUp() if $('li', flash_area).length?

fix_lang_menu = ->
  lang_menu = $('li.lang').first()
  lang_submenu = $('ul', lang_menu).first()
  lang_menu_w = lang_menu.width()
  lang_submenu_w = lang_submenu.width()
  left_margin = lang_menu_w - (lang_submenu_w + 1)
  lang_submenu.css 'margin-left', left_margin + 'px'

$(document).ready ->

  $('#query').autocompleter {
    source: '/autocomplete/keywords',
    offset: 'results',
    highlightMatches: true
  }

  $('#location').autocompleter {
    source: '/autocomplete/places',
    offset: 'results',
    minLength: 4,
    highlightMatches: true
  }

  $('#flash a.close').click(sweet_hide)

  fix_lang_menu()

sweet_hide = ->
  alert_box = $(this).parent()
  properties = {
    height: 'toggle',
    marginBottom: 'toggle',
    marginTop: 'toogle',
    opacity: 'toggle',
    paddingBottom: 'toggle',
    paddingTop: 'toogle'
  }
  alert_box.animate properties, 'fast', check_flash

check_flash = ->
  flash_area = $('#flash')
  flash_area.slideUp() if not flash_area.find('li:visible').length

fix_lang_menu = ->
  lang_menu = $('li.lang').first()
  lang_submenu = $('ul', lang_menu).first()
  lang_menu_w = lang_menu.width()
  lang_submenu_w = lang_submenu.width()
  left_margin = lang_menu_w - (lang_submenu_w + 1)
  lang_submenu.css 'margin-left', left_margin + 'px'

Fix flash message dismiss bug

Fix flash message dismiss bug


{$$, BufferedProcess, SelectListView} = require 'atom'

git = require '../git'
StatusView = require './status-view'
CherryPickSelectCommits = require './cherry-pick-select-commits-view'

module.exports =
class CherryPickSelectBranch extends SelectListView

  initialize: (items, @currentHead) ->
    super
    @addClass 'overlay from-top'
    @setItems items

    atom.workspaceView.append this
    @focusFilterEditor()

  viewForItem: (item) ->
    $$ ->
      @li item

  confirmed: (item) ->
    @cancel()
    args = [
      'log'
      '--cherry-pick'
      '-z'
      '--format=%H%n%an%n%ar%n%s'
      "#{@currentHead}...#{item}"
    ]

    git.cmd
      args: args
      stdout: (data) ->
        @save ?= ''
        @save += data
      exit: (exit) ->
        if exit is 0 and @save?
          new CherryPickSelectCommits(@save.split('\0')[...-1])
          @save = null
        else
          new StatusView(type: 'warning', message: "No commits available to cherry-pick.")

{BufferedProcess} = require 'atom'
{$$, SelectListView} = require 'atom-space-pen-views'

git = require '../git'
StatusView = require './status-view'
CherryPickSelectCommits = require './cherry-pick-select-commits-view'

module.exports =
class CherryPickSelectBranch extends SelectListView

  initialize: (items, @currentHead) ->
    super
    @show()
    @setItems items

    @focusFilterEditor()

  show: ->
    @panel ?= atom.workspace.addModalPanel(item: this)
    @panel.show()

  cancelled: -> @hide()

  hide: ->
    @panel?.hide()

  viewForItem: (item) ->
    $$ ->
      @li item

  confirmed: (item) ->
    @cancel()
    args = [
      'log'
      '--cherry-pick'
      '-z'
      '--format=%H%n%an%n%ar%n%s'
      "#{@currentHead}...#{item}"
    ]

    git.cmd
      args: args
      stdout: (data) ->
        @save ?= ''
        @save += data
      exit: (exit) ->
        if exit is 0 and @save?
          new CherryPickSelectCommits(@save.split('\0')[...-1])
          @save = null
        else
          new StatusView(type: 'warning', message: "No commits available to cherry-pick.")

Upgrade cherry pick select branch

Upgrade cherry pick select branch


class TerminalPane extends Pane

  constructor: (options = {}, data) ->

    options.cssClass  = "terminal-pane terminal"
    options.delay    ?= 0

    super options, data

    @createWebTermView()
    @webterm.on "WebTermConnected", (@remote) =>
      @emit "WebtermCreated"
      @onWebTermConnected()

  createWebTermView: ->
    @webterm           = new WebTermView
      cssClass         : "webterm"
      advancedSettings : no
      delegate         : this
      mode             : @getMode()

    @webterm.connectToTerminal()
    # WebTermView.setTerminalTimeout null, 15000, handler, handler

  getMode: -> "create"

  onWebTermConnected: ->
    {command} = @getOptions()
    @runCommand command if command

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

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

  pistachio: ->
    """
      {{> @header}}
      {{> @webterm}}
    """

class TerminalPane extends Pane

  constructor: (options = {}, data) ->

    options.cssClass  = "terminal-pane terminal"
    options.delay    ?= 0

    super options, data

    @createWebTermView()

  createWebTermView: ->

    KD.singletons.vmController.fetchDefaultVm (err, vm)=>

      @webterm           = new WebTermView {
        cssClass         : "webterm"
        advancedSettings : no
        delegate         : this
        mode             : @getMode()
        vm
      }

      @addSubView @header
      @addSubView @webterm

      @webterm.connectToTerminal()

      @webterm.on "WebTermConnected", (@remote) =>
        @emit "WebtermCreated"
        @onWebTermConnected()

      # WebTermView.setTerminalTimeout null, 15000, handler, handler

  getMode: -> "create"

  onWebTermConnected: ->
    {command} = @getOptions()
    @runCommand command if command

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

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

  # pistachio: ->
  #   """
  #     {{> @header}}
  #     {{> @webterm}}
  #   """

Fix TerminalPane until we support for multiple vms


#= require ./top/navbar
#= require ./centre/main_area

###* @jsx React.DOM ###

window.App = React.createClass
  render: ->
    `<span>
      <Navbar/>
      <MainArea/>
    </span>`

#= require ../store
#= require ../statechart
#= require ./top/navbar
#= require ./centre/main_area

###* @jsx React.DOM ###

models = [
  'corpora'
]

states =
  start: {}
  results: {}

window.App = React.createClass
  getInitialState: ->
    store: new Store(models, (store) => @setState(store: store))
    statechart: new Statechart('Main', states, 'start', (sc) => @setState(statechart: sc))

  render: ->
    `<span>
      <Navbar />
      <MainArea statechart={this.state.statechart} />
    </span>`

Add store and statechart to the App component


SpellCheckView = null

module.exports =
  config:
    grammars:
      type: 'array'
      default: [
        'source.asciidoc'
        'source.gfm'
        'text.git-commit'
        'text.plain'
        'text.plain.null-grammar'
      ]

  activate: ->
    @disposable = atom.workspace.observeTextEditors(addViewToEditor)

  deactivate: ->
    @disposable.dispose()

addViewToEditor = (editor) ->
  SpellCheckView ?= require './spell-check-view'
  new SpellCheckView(editor)

SpellCheckView = null

module.exports =
  config:
    grammars:
      type: 'array'
      default: [
        'source.asciidoc'
        'source.gfm'
        'text.git-commit'
        'text.plain'
        'text.plain.null-grammar'
      ]
      description: 'List of scopes for languages which will be checked for misspellings. See [the README](https://github.com/atom/spell-check#spell-check-package-) for more information on finding the correct scope for a specific language.'

  activate: ->
    @disposable = atom.workspace.observeTextEditors(addViewToEditor)

  deactivate: ->
    @disposable.dispose()

addViewToEditor = (editor) ->
  SpellCheckView ?= require './spell-check-view'
  new SpellCheckView(editor)

Add description for config setting

Add description for config setting


class VirtualizationController extends KDController

  constructor:->
    super

    @kc = KD.singletons.kiteController

    @lastState =
      state    : 'STOPPED'

  run:(command, callback, emitStateChanged=yes)->
    @kc.run
      kiteName : 'os'
      method   : command
    , @_cbWrapper callback, emitStateChanged

  start:(callback)->
    @run 'vm.start', callback

  stop:(callback)->
    @run 'vm.stop', callback

  reinitialize:(callback)->
    @run 'vm.reinitialize', callback

  info:(callback)->
    @run 'vm.info', (err, info)=>
      unless err then @lastState = info
      else warn "[VM]", err

      @emit 'StateChanged', err, info
      callback? err, info
    , no

  _cbWrapper:(callback, emitStateChanged)->
    return callback  unless emitStateChanged
    return (rest...)=>
      @info callback? rest...

  askToTurnOn:(appName='', callback)->

    content = """To #{if appName then 'run' else 'do this'} #{appName}
                 you need to turn on your VM first, you can do that by
                 clicking 'Turn ON VM' button below."""

    modal = new KDModalView
      title          : "Your VM is turned off"
      content        : "

#{content}

"
      height         : "auto"
      overlay        : yes
      buttons        :
        'Turn ON VM' :
          style      : "modal-clean-green"
          callback   : =>
            @start =>
              modal.destroy()
              if appName
                @once 'StateChanged', ->
                  appManager.open appName
        Cancel       :
          style      : "modal-clean-gray"
          callback   : ->
            modal.destroy()
            callback?()

    modal.once 'KDModalViewDestroyed', -> callback?()

Add askToTurnOn helper method to turn VM on globally


_ = require 'underscore'

View = require 'lib/view'
tpl = require 'templates/users/edit'

mediator = require('chaplin').mediator

module.exports = class EditUserView extends View
  template: tpl
  autoRender: yes

  events:
    'submit form': 'submitForm'
    'click [href="#remove"]': 'clickRemove'

  getTemplateData: ->
    _.extend super,
      currentUser: mediator.user?.toJSON()

  submitForm: (e) ->
    e.preventDefault()

    data = @$el.formParams(no)
    @model.save(data, wait: yes).fail(@renderServerErrors).done =>
      @dispose()

  clickRemove: (e) ->
    e.preventDefault()
    @model.destroy(wait: yes).done =>
      toastr.success 'User has been removed.'
      @dispose()

_ = require 'underscore'

View = require 'lib/view'
tpl = require 'templates/users/edit'

mediator = require('chaplin').mediator

module.exports = class EditUserView extends View
  template: tpl
  autoRender: yes

  events:
    'submit form': 'submitForm'
    'click [href="#remove"]': 'clickRemove'

  getTemplateData: ->
    _.extend super,
      currentUser: mediator.user?.toJSON()

  submitForm: (e) ->
    e.preventDefault()

    data = @$el.formParams(no)
    @model.save(data, wait: yes).fail(@renderServerErrors).done =>
      @dispose()

  clickRemove: (e) ->
    e.preventDefault()
    if confirm 'Are you sure?'
      @model.destroy(wait: yes).done =>
        toastr.success 'User has been removed.'
        @dispose()

Add confirm to user delete

Add confirm to user delete


###
Requires https://github.com/andialbrecht/sqlparse
###
getCmd = (inputPath, outputPath, options) ->
  path = options.sqlformat_path
  optionsStr = " --indent_width={0} --keywords={1} --identifiers={2} --reindent"
  optionsStr = optionsStr.replace("{0}", options.indent_size)
		                     .replace("{1}", options.keywords)
      					         .replace("{2}", options.identifiers)
  if path
    # Use absolute path
    "python \"" + path + "\" \"" + inputPath + "\" " + optionsStr
  else
    # Use command available in $PATH
    "sqlformat \"" + inputPath + "\" " + optionsStr

"use strict"
cliBeautify = require("./cli-beautify")
isStdout = true
module.exports = cliBeautify(getCmd, isStdout)

###
Requires https://github.com/andialbrecht/sqlparse
###
getCmd = (inputPath, outputPath, options) ->
  path = options.sqlformat_path

  optionsStr = "--reindent"
  if options.indent_size?
    optionsStr += " --indent_width=#{options.indent_size}"
  if options.keywords?
    optionsStr += " --keywords=#{options.keywords}"
  if options.identifiers
    optionsStr += " --identifiers=#{options.identifiers}"

  if path
    # Use absolute path
    "python \"" + path + "\" \"" + inputPath + "\" " + optionsStr
  else
    # Use command available in $PATH
    "sqlformat \"" + inputPath + "\" " + optionsStr

"use strict"
cliBeautify = require("./cli-beautify")
isStdout = true
module.exports = cliBeautify(getCmd, isStdout)

Improve SQL Beautifier to support missing config options.

Fixes #67.


Helper = require('hubot-test-helper')
chai = require 'chai'

expect = chai.expect

helper = new Helper('../scripts/hello.coffee')

describe 'Training 1', ->
  beforeEach ->
    @room = helper.createRoom()

  afterEach ->
    @room.destroy()

  it 'start Training 1', ->
    @room.user.say('miura', '@customer 三浦と申します。監視ソフトウェアの構築をしていました。').then =>
      expect(@room.messages).to.eql [
        ['miura', '@customer 三浦と申します。監視ソフトウェアの構築をしていました。']
        ['hubot', '@miura はじめまして、三浦さん。これからよろしくお願いします。']
      ]

Helper = require('hubot-test-helper')
chai = require 'chai'

expect = chai.expect

helper = new Helper('../scripts/training1st.coffee')

describe 'The 1st day of Training', ->
  beforeEach ->
    @room = helper.createRoom()

  afterEach ->
    @room.destroy()

  it 'should reply greeting to trainee', ->
    @room.user.say('miura', '@hubot 三浦と申します。監視ソフトウェアの構築をしていました。').then =>
      expect(@room.messages).to.eql [
        ['miura', '@hubot 三浦と申します。監視ソフトウェアの構築をしていました。']
        ['hubot', '@miura はじめまして、三浦さん。これからよろしくお願いします。']
      ]

Change description on tests of training.


os = require("os")

module.exports.monitor = (logger) ->
	return (req, res, next) ->
		Metrics = require("./metrics")
		startTime = new Date()
		end = res.end
		res.end = () ->
			end.apply(this, arguments)
			responseTime = new Date() - startTime
			routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1)
			key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}"

			Metrics.timing(key, responseTime)
			logger.log
				req:
					url: req.originalUrl || req.url
					method: req.method
					referrer: req.headers['referer'] || req.headers['referrer']
					"remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress
					"user-agent": req.headers["user-agent"]
					"content-length": req.headers["content-length"]
				res:
					"content-length": res._headers?["content-length"]
					statusCode: res.statusCode
				"response-time": responseTime
				"http request"
		next()

os = require("os")

module.exports.monitor = (logger) ->
	return (req, res, next) ->
		Metrics = require("./metrics")
		startTime = new Date()
		end = res.end
		res.end = () ->
			end.apply(this, arguments)
			responseTime = new Date() - startTime
			if req.route?.path?
				routePath = req.route.path.toString().replace(/\//g, '_').replace(/\:/g, '').slice(1)
				key = "http-requests.#{routePath}.#{req.method}.#{res.statusCode}"

				Metrics.timing(key, responseTime)
				logger.log
					req:
						url: req.originalUrl || req.url
						method: req.method
						referrer: req.headers['referer'] || req.headers['referrer']
						"remote-addr": req.ip || req.socket?.socket?.remoteAddress || req.socket?.remoteAddress
						"user-agent": req.headers["user-agent"]
						"content-length": req.headers["content-length"]
					res:
						"content-length": res._headers?["content-length"]
						statusCode: res.statusCode
					"response-time": responseTime
					"http request"

		next()

Check that req.route.path is set

Check that req.route.path is set


BaseModel = require './base'
crypto = require 'crypto'
uuid = require 'uuid'
_ = require 'underscore'

class UserCredential extends BaseModel
  constructor: (options) ->
    super options

    @required = ['userid', 'secret']

    if not @secret
      @genSecret()

  genSecret: () ->
    sha = crypto.createHash 'sha256'
    sha.update "#{uuid.v1()}"
    @secret = sha.digest 'hex'

module.exports = UserCredential

BaseModel = require './base'
crypto = require 'crypto'
uuid = require 'uuid'
_ = require 'underscore'

class UserCredential extends BaseModel
  constructor: (options) ->
    super options

    @required = ['userid', 'secret', 'user_identifier']

    if not @secret
      @genSecret()

    if not @user_identifier
      @genIdentifier()

  genSecret: () ->
    sha = crypto.createHash 'sha256'
    sha.update "#{uuid.v1()}"
    @secret = sha.digest 'hex'

  genIdentifier: () ->
    @user_identifier = uuid.v1()

module.exports = UserCredential

Add user_identifier to UserCredential Model


Reflux = require 'reflux'
{api} = require '../api/client'
classifierActions = require '../actions/classifier-actions'
workflowStore = require './workflow-store'

module.exports = Reflux.createStore
  subjects: []
  subject: null

  init: ->
    @listenTo workflowStore, @changeWorkflow
    @listenTo classifierActions.moveToNextSubject, @next

  getInitialState: ->
    @subjects
    @subject

  next: ->
    if @subjects.length == 0
      query =
        workflow_id: workflowStore.data.id
        sort: 'queued'

      api.type('subjects').get query
        .then (subjects) =>
          return unless subjects.length > 0
          @subjects = subjects
        .then =>
          @loadSubjectImage()
    else
      @loadSubjectImage()

  loadSubjectImage: ->
    @subject = @subjects.shift()
    @generateHttpsUrl()
    image = new Image()
    image.src = @subject.locations[0]['image/jpeg']
    image.onload = =>
      @subject.srcWidth = image.naturalWidth
      @trigger @subject

  generateHttpsUrl: ->
    # If it's not an https url, we replace the s3 domain name with a secure one
    url = @subject.locations[0]['image/jpeg']
    if url.substr(0, 5) != 'https'
      filename = url.replace /https?:\/\/[^\/]+/i, ''
      @subject.locations[0]['image/jpeg'] = 'https://zooniverse-export.s3.amazonaws.com' + filename

  changeWorkflow: ->
    @subject = null
    @subjects.length = 0
    @trigger @subject
    @next()

Reflux = require 'reflux'
{api} = require '../api/client'
classifierActions = require '../actions/classifier-actions'
workflowStore = require './workflow-store'

module.exports = Reflux.createStore
  subjects: []
  subject: null

  init: ->
    @listenTo workflowStore, @changeWorkflow
    @listenTo classifierActions.moveToNextSubject, @next

  getInitialState: ->
    @subjects
    @subject

  next: ->
    if @subjects.length == 0
      query =
        workflow_id: workflowStore.data.id

      api.get('/subjects/queued', query)
        .then (subjects) =>
          return unless subjects.length > 0
          @subjects = subjects
        .then =>
          @loadSubjectImage()
    else
      @loadSubjectImage()

  loadSubjectImage: ->
    @subject = @subjects.shift()
    @generateHttpsUrl()
    image = new Image()
    image.src = @subject.locations[0]['image/jpeg']
    image.onload = =>
      @subject.srcWidth = image.naturalWidth
      @trigger @subject

  generateHttpsUrl: ->
    # If it's not an https url, we replace the s3 domain name with a secure one
    url = @subject.locations[0]['image/jpeg']
    if url.substr(0, 5) != 'https'
      filename = url.replace /https?:\/\/[^\/]+/i, ''
      @subject.locations[0]['image/jpeg'] = 'https://zooniverse-export.s3.amazonaws.com' + filename

  changeWorkflow: ->
    @subject = null
    @subjects.length = 0
    @trigger @subject
    @next()

Switch to using new subject selection URL


FactlinkJailRoot.createFactFromSelection = (current_user_opinion) ->
  success = ->
    FactlinkJailRoot.createButton.hide()
    FactlinkJailRoot.off 'modalOpened', success

  selInfo =
    text: window.document.getSelection().toString()
    title: window.document.title

  text = selInfo.text
  siteUrl = FactlinkJailRoot.siteUrl()
  siteTitle = selInfo.title

  FactlinkJailRoot.on 'modalOpened', success
  FactlinkJailRoot.factlinkCoreEnvoy 'prepareNewFactlink',
    text, siteUrl, siteTitle, current_user_opinion

FactlinkJailRoot.textSelected = ->
  # At least 4 words of at least 2 characters
  /(\w{2,}[\s-_&\/#%.,;:!()]+){4}/.test window.document.getSelection().toString()

FactlinkJailRoot.createFactFromSelection = (current_user_opinion) ->
  success = ->
    window.document.getSelection().removeAllRanges()
    FactlinkJailRoot.createButton.hide()
    FactlinkJailRoot.off 'modalOpened', success

  selInfo =
    text: window.document.getSelection().toString()
    title: window.document.title

  text = selInfo.text
  siteUrl = FactlinkJailRoot.siteUrl()
  siteTitle = selInfo.title

  FactlinkJailRoot.on 'modalOpened', success
  FactlinkJailRoot.factlinkCoreEnvoy 'prepareNewFactlink',
    text, siteUrl, siteTitle, current_user_opinion

FactlinkJailRoot.textSelected = ->
  # At least 4 words of at least 2 characters
  /(\w{2,}[\s-_&\/#%.,;:!()]+){4}/.test window.document.getSelection().toString()

Remove selection when added a discussion


#= require jquery
#= require bootstrap-fix
#= require jquery_ujs
#= require jquery-ui.js
#= require jquery.cookie
#= require jquery.titlealert
#= require jquery.mousewheel
#= require jquery.expanding
#= require jquery.iframe-transport
#= require simply-scroll
# require jquery.purr
#= require hamlcoffee
#= require date
#= require faye
#= require twitter-text
#= require autolink
#= require select2
# require pjax
# require jquery.tokeninput
# require jquery.daterangepicker
# require best_in_place
# require rails.validations
# require rails.validations.custom
# require rails.validations.formbuilder
# require farbtastic
# require showdown
# require highcharts
#
# require underscore
#= require underscore-1.3.3
#= require backbone
#= require backbone.getset
#
#= require cloudsdale
#
#= require_tree ../templates/
#= require_tree ./models
#= require_tree ./collections
#= require_tree ./views
#= require_tree ./routers
#= require_tree ./modules

#= require jquery
#= require bootstrap
#= require jquery_ujs
#= require jquery-ui.js
#= require jquery.cookie
#= require jquery.titlealert
#= require jquery.mousewheel
#= require jquery.expanding
#= require jquery.iframe-transport
#= require simply-scroll
# require jquery.purr
#= require hamlcoffee
#= require date
#= require faye
#= require twitter-text
#= require autolink
#= require select2
# require pjax
# require jquery.tokeninput
# require jquery.daterangepicker
# require best_in_place
# require rails.validations
# require rails.validations.custom
# require rails.validations.formbuilder
# require farbtastic
# require showdown
# require highcharts
#
# require underscore
#= require underscore-1.3.3
#= require backbone
#= require backbone.getset
#
#= require cloudsdale
#
#= require_tree ../templates/
#= require_tree ./models
#= require_tree ./collections
#= require_tree ./views
#= require_tree ./routers
#= require_tree ./modules

Use actual bootstrap javascript, not some weird homebrew version? :3


# Copyright 2013 Square Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

root = exports ? this

# Formats a Bug's file name, taking into account special files.
#
# @param [Object] bug The Bug.
# @return [String] The abbreviated file name.
#
root.formatBugFile = (bug) ->
  #TODO don't guess, record this information
  if bug.file =~ /^\[S\] /
    "<simple blamer>"
  else
    parts = bug.file.split('/')
    parts[parts.length  - 1]

# Copyright 2013 Square Inc.
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

root = exports ? this

# Formats a Bug's file name, taking into account special files.
#
# @param [Object] bug The Bug.
# @return [String] The abbreviated file name.
#
root.formatBugFile = (bug) ->
  #TODO don't guess, record this information
  if bug.file.match(/^\[S\] /)
    "<simple blamer>"
  else
    parts = bug.file.split('/')
    parts[parts.length  - 1]

Fix bug list display issue

Fix bug list display issue


#= require dashboard
#= require mock-ajax

describe "Dashboard - getData()", ->
  beforeEach ->
    jasmine.Ajax.useMock()
    @dashboard = Dashboard

  describe "when the report is ready on the first iteration", ->
    it "should return the dashboard data", ->
      that = this

      @dashboard.getData 'lesson_leaders', {}, (data) ->
        that.data = data

      request = mostRecentAjaxRequest()
      expect(request.url).toBe('/dashboard/queries')
      expect(request.method).toBe('POST')
      request.response { status: 200, responseText: '{"id": "REPORT_ID" }' }

      waits(1000)

      runs ->
        request = mostRecentAjaxRequest()
        expect(request.url).toBe('/dashboard/queries/REPORT_ID/ready')
        expect(request.method).toBe('GET')
        request.response { status: 200, responseText: '{"is_ready": true, "data":"DATA" }' }

        expect(that.data).toEqual 'DATA'

#= require lib/dashboard_poller
#= require mock-ajax

describe "Dashboard - getData()", ->
  beforeEach ->
    jasmine.Ajax.useMock()
    @dashboard = ttm.lib.DashboardPoller.build()

  describe "when the report is ready on the first iteration", ->
    it "should return the dashboard data", ->
      that = this

      @dashboard.getData 'lesson_leaders', {}, (data) ->
        that.data = data

      request = mostRecentAjaxRequest()
      expect(request.url).toBe('/dashboard/queries')
      expect(request.method).toBe('POST')
      request.response { status: 200, responseText: '{"id": "REPORT_ID" }' }

      waits(1000)

      runs ->
        request = mostRecentAjaxRequest()
        expect(request.url).toBe('/dashboard/queries/REPORT_ID/ready')
        expect(request.method).toBe('GET')
        request.response { status: 200, responseText: '{"is_ready": true, "data":"DATA" }' }

        expect(that.data).toEqual 'DATA'

Move the poller into the lib and mix it with the other classmixer stuffs. Update the test.


React = require 'react'
ReactRedux = require 'react-redux'
moment = require 'moment'

createFactory = require '../create-factory.coffee'
Elements = require '../elements.coffee'
selectors = require '../selectors/app-selectors.coffee'
userActions = require '../actions/user-actions.coffee'
URL = require '../url.coffee'

{ nav, ul, li } = Elements

Link = createFactory ReactRedux.connect(selectors.linkSelector)(
	require './link.coffee'
)
LangPicker = createFactory ReactRedux.connect(selectors.langPickerSelector)(
	require './lang-picker.coffee'
)

module.exports = React.createClass
	displayName: 'SiteMenu'
	handleLogout: ->
		@props.dispatch userActions.logout()
	render: ->
		{ home, admin, newArticle, logout } = @props.localeStrings
		newUrl = '/' + moment().format('YYYY/MM/DD') + '/untitled/new'
		ulArgs = [
			className: 'list-inline'
			li Link href: '/', home
			li Link href: '/login', admin
		]
		if @props.login.isLoggedIn
			logoutUrl = URL.getUserPath(@props.login.user._id) + '/logout'
			ulArgs.push(
				li key: 'new-article', Link href: newUrl, newArticle
				li key: 'logout', Link(
					href: logoutUrl
					onClick: @handleLogout
					logout
				)
			)
		nav(
			{ className: 'site-menu' }
			LangPicker className: 'site-menu__lang-picker'
			ul ulArgs
		)

React = require 'react'
ReactRedux = require 'react-redux'
moment = require 'moment'

createFactory = require '../create-factory.coffee'
Elements = require '../elements.coffee'
selectors = require '../selectors/app-selectors.coffee'
userActions = require '../actions/user-actions.coffee'
URL = require '../url.coffee'

{ nav, ul, li } = Elements

Link = createFactory ReactRedux.connect(selectors.linkSelector)(
	require './link.coffee'
)
LangPicker = createFactory ReactRedux.connect(selectors.langPickerSelector)(
	require './lang-picker.coffee'
)

module.exports = React.createClass
	displayName: 'SiteMenu'
	handleLogout: ->
		@props.dispatch userActions.logout()
	render: ->
		{ home, admin, newArticle, logout } = @props.localeStrings
		newUrl = '/' + moment().format('YYYY/MM/DD') + '/untitled/new'
		ulArgs = [
			className: 'list-inline'
			li Link href: '/', home
			li Link href: '/login', admin
		]
		if @props.login.isLoggedIn
			ulArgs.push(
				li key: 'new-article', Link href: newUrl, newArticle
				li key: 'logout', Link(
					href: '/logout'
					onClick: @handleLogout
					logout
				)
			)
		nav(
			{ className: 'site-menu' }
			LangPicker className: 'site-menu__lang-picker'
			ul ulArgs
		)

Remove duplicate user path from logout link.


window.TimeAgo = React.createClass
  mixins: [SetIntervalMixin]

  getInitialState: ->
    now: Date.now()

  componentDidMount: ->
    @setInterval(@update_time, 1000)

  update_time: ->
    @setState now: Date.now()

  seconds_lapsed: ->
    (@state.now - Date.parse(@props.time)) / 1000

  showNr: (nr, unit) ->
    "#{Math.round(nr)}#{unit}"

  displayTime: (time) ->
    seconds = 1
    minutes = 60
    hours   = 60 * minutes
    days    = 24 * hours
    months  = 30* days
    years   = 365 * days
    if not time
      '?'
    else if time < 1 * minutes
      "now"
    else if time < 1*hours
      @showNr(time / minutes, 'm')
    else if time < 1*days
      @showNr(time / hours, 'h')
    else if time < 1*months
      @showNr(time / days , 'd')
    else if time < 1*years
      @showNr(time / months, 'm')
    else
      @showNr(time / years, 'y')

  render: ->
    span = _span {}, @displayTime(@seconds_lapsed())
    @transferPropsTo span

window.TimeAgo = React.createClass
  mixins: [SetIntervalMixin]

  getInitialState: ->
    now: Date.now()

  componentDidMount: ->
    @setInterval(@update_time, 1000)

  update_time: ->
    @setState now: Date.now()

  seconds_lapsed: ->
    (@state.now - Date.parse(@props.time)) / 1000

  showNr: (nr, unit) ->
    "#{Math.round(nr)}#{unit}"

  displayTime: (time) ->
    seconds = 1
    minutes = 60
    hours   = 60 * minutes
    days    = 24 * hours
    months  = 30* days
    years   = 365 * days
    if not time
      '?'
    else if time < 1 * minutes
      "now"
    else if time < 1*hours
      @showNr(time / minutes, 'min')
    else if time < 1*days
      @showNr(time / hours, 'h')
    else if time < 1*months
      @showNr(time / days , 'd')
    else if time < 1*years
      @showNr(time / months, 'm')
    else
      @showNr(time / years, 'y')

  render: ->
    span = _span {}, @displayTime(@seconds_lapsed())
    @transferPropsTo span

Make a difference between minutes and months. They both used to have an "m" as indicator


should   = require 'should'
fixtures = require './fixtures'
git      = require '../src'
Blob     = require '../src/blob'

describe "Blob", ->
  describe "constructor", ->
    repo = fixtures.branched
    blob = new Blob repo, {name: "X", mode: "Y", id: "abc"}
    it "assigns @name", ->
      blob.name.should.eql "X"
    it "assigns @mode", ->
      blob.mode.should.eql "Y"
    it "assigns @id", ->
      blob.id.should.eql "abc"

  describe "#data", ->
    describe "of a file off the root", ->
      repo = git "#{__dirname}/fixtures/branched"
      data = null
      before (done) ->
        repo.tree().blobs (err, blobs) ->
          blobs[0].data (err, _data) ->
            data = _data
            done err

      it "is a string", ->
        data.should.be.a "string"
        data.should.include "Bla"

    describe "of a file in a subdir", ->
      repo = git "#{__dirname}/fixtures/branched"
      data = null
      before (done) ->
        repo.tree().trees (err, trees) ->
          trees[0].blobs (err, blobs) ->
            blobs[0].data (err, _data) ->
              data = _data
              done err

      it "is a string", ->
        data.should.be.a "string"
        data.should.include "!!!"

should   = require 'should'
fixtures = require './fixtures'
git      = require '../src'
Blob     = require '../src/blob'

describe "Blob", ->
  describe "constructor", ->
    repo = fixtures.branched
    blob = new Blob repo, {name: "X", mode: "Y", id: "abc"}
    it "assigns @name", ->
      blob.name.should.eql "X"
    it "assigns @mode", ->
      blob.mode.should.eql "Y"
    it "assigns @id", ->
      blob.id.should.eql "abc"

  describe "#data", ->
    describe "of a file off the root", ->
      repo = git "#{__dirname}/fixtures/branched"
      data = null
      before (done) ->
        repo.tree().blobs (err, blobs) ->
          blobs[0].data (err, _data) ->
            data = _data
            done err

      it "is a string", ->
        data.should.be.type "string"
        data.should.include "Bla"

    describe "of a file in a subdir", ->
      repo = git "#{__dirname}/fixtures/branched"
      data = null
      before (done) ->
        repo.tree().trees (err, trees) ->
          trees[0].blobs (err, blobs) ->
            blobs[0].data (err, _data) ->
              data = _data
              done err

      it "is a string", ->
        data.should.be.type "string"
        data.should.include "!!!"

Test fix: corrected use of should to assert typeof


ThemeWatcher = require './theme-watcher'
BaseThemeWatcher = require './base-theme-watcher'

module.exports =
class UIWatcher
  constructor: ({@themeManager}) ->
    @baseTheme = new BaseThemeWatcher()
    for theme in @themeManager.getActiveThemes()
      @createThemeWatcher(theme)
    @themeManager.on 'theme-activated', (theme) =>
      @createThemeWatcher(theme)

  createThemeWatcher: (theme) ->
    watcher = new ThemeWatcher(theme)
    watcher.on 'globals-changed', @reloadAll
    watcher

  reloadAll: =>
    @baseTheme.reloadStylesheet()
    theme.load() for theme in atom.themes.getThemes()

BaseThemeWatcher = require './base-theme-watcher'
ThemeWatcher = require './theme-watcher'
PackageWatcher = require './package-watcher'

module.exports =
class UIWatcher
  constructor: ({@themeManager}) ->
    @watchers = []
    @baseTheme = @createWatcher(BaseThemeWatcher)
    @watchThemes()
    @watchPackages()

  watchThemes: ->
    for theme in @themeManager.getActiveThemes()
      @createWatcher(ThemeWatcher, theme)

    @themeManager.on 'theme-activated', (theme) =>
      @createWatcher(ThemeWatcher, theme)

  watchPackages: ->
    for pack in atom.getActivePackages()
      console.log pack
      @createWatcher(PackageWatcher, pack) if PackageWatcher.supportsPackage(pack)

  createWatcher: (type, object) ->
    watcher = new type(object)
    watcher.on 'globals-changed', @reloadAll
    watcher.on 'destroyed', =>
      @watchers = _.without(@watchers, watcher)
    @watchers.push(watcher)
    watcher

  reloadAll: =>
    @baseTheme.reloadStylesheet()
    theme.load() for theme in atom.themes.getActiveThemes()
    pack.reloadStylesheets() for pack in atom.getActivePackages() when PackageWatcher.supportsPackage(pack)

Refactor ui watcher to use packageWatcher


# Your keymap
#
# Atom keymaps work similarly to style sheets. Just as style sheets use
# selectors to apply styles to elements, Atom keymaps use selectors to associate
# keystrokes with events in specific contexts. Unlike style sheets however,
# each selector can only be declared once.
#
# You can create a new keybinding in this file by typing "key" and then hitting
# tab.
#
# Here's an example taken from Atom's built-in keymap:
#
# 'atom-text-editor':
#   'enter': 'editor:newline'
#
# 'atom-workspace':
#   'ctrl-shift-p': 'core:move-up'
#   'ctrl-p': 'core:move-down'
#
# You can find more information about keymaps in these guides:
# * https://atom.io/docs/latest/using-atom-basic-customization#customizing-key-bindings
# * https://atom.io/docs/latest/behind-atom-keymaps-in-depth
#
# This file uses CoffeeScript Object Notation (CSON).
# If you are unfamiliar with CSON, you can read more about it in the
# Atom Flight Manual:
# https://atom.io/docs/latest/using-atom-basic-customization#cson

# Your keymap
#
# Atom keymaps work similarly to style sheets. Just as style sheets use
# selectors to apply styles to elements, Atom keymaps use selectors to associate
# keystrokes with events in specific contexts. Unlike style sheets however,
# each selector can only be declared once.
#
# You can create a new keybinding in this file by typing "key" and then hitting
# tab.
#
# Here's an example taken from Atom's built-in keymap:
#
# 'atom-text-editor':
#   'enter': 'editor:newline'
#
# 'atom-workspace':
#   'ctrl-shift-p': 'core:move-up'
#   'ctrl-p': 'core:move-down'
#
# You can find more information about keymaps in these guides:
# * http://flight-manual.atom.io/using-atom/sections/basic-customization/#_customizing_keybindings
# * http://flight-manual.atom.io/behind-atom/sections/keymaps-in-depth/
#
# If you're having trouble with your keybindings not working, try the
# Keybinding Resolver: `Cmd+.` on macOS and `Ctrl+.` on other platforms. See the
# Debugging Guide for more information:
# * http://flight-manual.atom.io/hacking-atom/sections/debugging/#check-the-keybindings
#
# This file uses CoffeeScript Object Notation (CSON).
# If you are unfamiliar with CSON, you can read more about it in the
# Atom Flight Manual:
# http://flight-manual.atom.io/using-atom/sections/basic-customization/#_cson

Update to Atom 1.15.0 default

Update to Atom 1.15.0 default


Polymer
  is: 'league-controller'
  properties:
    league: Object
    leagueId:
      type: String,
      observer: '_leagueIdChanged'
    leagueAttrs: Object
    players:
      type: Object
      observer: '_onPlayersChange'
    playerModels: Array

  newPlayer: ->
    event.preventDefault()
    league = @league
    errorsEl = Polymer.dom(this).node.querySelector("#errors")
    playerInput = Polymer.dom(this).node.querySelector("#playerName")
    opts =
      name: playerInput.value
      LeagueId: league.id
    player = new Player(opts)
    player.setApiClient(@$.api)
    player.save player.attributes,
      success: (model) ->
        league.get('Players').add(model)
        playerInput.value = ""
        errorsEl.errors = []
      error: (data, response) ->
        errorsEl.errors = [response.responseJSON.error.errors[0]]

  playerEditClick: (event) ->
    event.preventDefault()
    console.log "TODO"

  playerRemoveClick: (event) ->
    event.preventDefault()
    playerId = event.target.getAttribute("data-player")
    player = @league.get('Players').get(playerId)
    player.setApiClient(@$.api)
    player.destroy(wait: true)

  _leagueIdChanged: ->
    if @leagueId
      @$.api.findOrFetchModel(League, @leagueId)
        .then (league) =>
          @league = league
          @fire('iron-signal', {name: "league", data: league})

Polymer
  is: 'league-controller'
  properties:
    league: Object
    leagueId:
      type: String,
      observer: '_leagueIdChanged'
    leagueAttrs: Object
    players:
      type: Object
      observer: '_onPlayersChange'
    playerModels: Array

  newPlayer: ->
    event.preventDefault()
    league = @league
    errorsEl = Polymer.dom(this).node.querySelector("#errors")
    playerInput = Polymer.dom(this).node.querySelector("#playerName")
    opts =
      name: playerInput.value
      LeagueId: league.id
    player = new Player(opts)
    player.setApiClient(@$.api)
    player.save player.attributes,
      success: (model) ->
        league.get('Players').add(model)
        playerInput.value = ""
        errorsEl.errors = []
      error: (data, response) ->
        errorsEl.errors = [response.responseJSON.error.errors[0]]

  playerEditClick: (event) ->
    event.preventDefault()
    console.log "TODO"

  playerRemoveClick: (event) ->
    event.preventDefault()
    playerId = event.target.getAttribute("data-player")
    player = @league.get('Players').get(playerId)
    if window.confirm("Deleting player #{player.get('name')}. Are you sure?")
      player.setApiClient(@$.api)
      player.destroy(wait: true)

  _leagueIdChanged: ->
    if @leagueId
      @$.api.findOrFetchModel(League, @leagueId)
        .then (league) =>
          @league = league
          @fire('iron-signal', {name: "league", data: league})

Add confirmation to player delete

Add confirmation to player delete


Marionette  = require "marionette"

CommentCollectionView   = require "./comment/collectionView"
PlayingNotifierView     = require "./nowPlaying/nowPlayingView"

module.exports =
class NcoMainLayout extends Marionette.LayoutView
    template    : require "./view.jade"

    regions     :
        comment     : "#nco-comments"
        notify      : ".NcoNotifier"

    ui          : null

    events      : null

    onShow      : ->
        @comment.show new CommentCollectionView
        @notify.show new PlayingNotifierView

Marionette  = require "marionette"

CommentCollectionView   = require "./comment/collectionView"
NotifyView = require "./notify/NotifyView"

module.exports =
class NcoMainLayout extends Marionette.LayoutView
    template    : require "./view.jade"

    regions     :
        comment     : "#nco-comments"
        notify      : ".NcoNotifier"

    ui          : null

    events      : null

    onShow      : ->
        @comment.show new CommentCollectionView
        @notify.show new NotifyView

Replace notify view to NotifyView

[Dev] Replace notify view to NotifyView