module.exports =
  isLoggedIn: (req, res, next) ->
    if req.user
      next()
    else
      req.flash 'error', 'You must be logged in!'
      res.redirect '/login'

  isNotLoggedIn: (req, res, next) ->
    if req.user
      req.flash 'error', 'You are already logged in!'
      res.redirect '/'
    else
      next()

module.exports =
  isLoggedIn: (req, res, next) ->
    if req.isAuthenticated()
      next()
    else
      req.flash 'error', 'You must be logged in!'
      res.redirect '/login'

  isNotLoggedIn: (req, res, next) ->
    if req.isAuthenticated()
      req.flash 'error', 'You are already logged in!'
      res.redirect '/'
    else
      next()

Replace property with method to improve intelligibility


{_, $, $$, View} = require 'atom'

module.exports =
class StatusBarView extends View
  @content: ->
    @div class: 'status-bar tool-panel panel-bottom', =>
      @div outlet: 'rightPanel', class: 'status-bar-right pull-right'
      @div outlet: 'leftPanel', class: 'status-bar-left'

  initialize: ->
    @bufferSubscriptions = []
    @subscribe atom.rootView, 'pane-container:active-pane-item-changed', =>
      @unsubscribeAllFromBuffer()
      @storeActiveBuffer()
      @subscribeAllToBuffer()

      @trigger('active-buffer-changed')

    @storeActiveBuffer()

  attach: ->
    atom.rootView.vertical.append(this) unless @hasParent()

  appendLeft: (item) ->
    @leftPanel.append(item)

  appendRight: (item) ->
    @rightPanel.append(item)

  getActiveBuffer: ->
    @buffer

  getActiveItem: ->
    atom.rootView.getActivePaneItem()

  storeActiveBuffer: ->
    @buffer = @getActiveItem()?.getBuffer?()

  subscribeToBuffer: (event, callback) ->
    @bufferSubscriptions.push([event, callback])
    @buffer.on(event, callback) if @buffer

  subscribeAllToBuffer: ->
    return unless @buffer
    for [event, callback] in @bufferSubscriptions
      @buffer.on(event, callback)

  unsubscribeAllFromBuffer: ->
    return unless @buffer
    for [event, callback] in @bufferSubscriptions
      @buffer.off(event, callback)

{_, $, $$, View} = require 'atom'

module.exports =
class StatusBarView extends View
  @content: ->
    @div class: 'status-bar tool-panel panel-bottom', =>
      @div outlet: 'rightPanel', class: 'status-bar-right pull-right'
      @div outlet: 'leftPanel', class: 'status-bar-left'

  initialize: ->
    atom.rootView.statusBar = this

    @bufferSubscriptions = []
    @subscribe atom.rootView, 'pane-container:active-pane-item-changed', =>
      @unsubscribeAllFromBuffer()
      @storeActiveBuffer()
      @subscribeAllToBuffer()

      @trigger('active-buffer-changed')

    @storeActiveBuffer()

  attach: ->
    atom.rootView.vertical.append(this) unless @hasParent()

  appendLeft: (item) ->
    @leftPanel.append(item)

  appendRight: (item) ->
    @rightPanel.append(item)

  getActiveBuffer: ->
    @buffer

  getActiveItem: ->
    atom.rootView.getActivePaneItem()

  storeActiveBuffer: ->
    @buffer = @getActiveItem()?.getBuffer?()

  subscribeToBuffer: (event, callback) ->
    @bufferSubscriptions.push([event, callback])
    @buffer.on(event, callback) if @buffer

  subscribeAllToBuffer: ->
    return unless @buffer
    for [event, callback] in @bufferSubscriptions
      @buffer.on(event, callback)

  unsubscribeAllFromBuffer: ->
    return unless @buffer
    for [event, callback] in @bufferSubscriptions
      @buffer.off(event, callback)

Add itself as a global on rootView

Add itself as a global on rootView


Template.chart.helpers
  nonNumberDataColumnSpec: ->
    for spec in @header.slice(1)
      if spec.chartType isnt "number"
        return spec
  reactivityHack: ->
    _.defer =>
      $chart = $(".chart[data-id='" + @_id + "']")
      $chart.empty()
      $chartContainer = $("

")
      $chart.append($chartContainer)
      data = new google.visualization.DataTable()
      for spec in @header
#        if @output is "rwstats" and spec.isPercentage
#          continue
        data.addColumn(spec.chartType, i18n.t("rwcut.fields." + spec.name))
      data.addRows(@rows)
      chart = new google.visualization[@chartType]($chartContainer.get(0))
      chart.draw(data,
        curveType: "function"
        vAxis:
          logScale: true
      )

Template.chart.rendered = ->

Template.chart.events
#  "click .selector": (event, template) ->

Template.chart.helpers
  nonNumberDataColumnSpec: ->
    for spec in @header.slice(1)
      if spec.chartType isnt "number"
        return spec
  reactivityHack: ->
    _.defer =>
      $chart = $(".chart[data-id='" + @_id + "']")
      $chart.empty()
      $chartContainer = $("

")
      $chart.append($chartContainer)
      data = new google.visualization.DataTable()
      for spec in @header
        if @output is "rwstats" and (spec.isPercentage or spec.name is "cumul_%")
          continue
        data.addColumn(spec.chartType, i18n.t("rwcut.fields." + spec.name))
      for row in @rows
        values = []
        for value, index in row
          spec = @header[index]
          if @output is "rwstats" and (spec.isPercentage or spec.name is "cumul_%")
            continue
          values.push(value)
        data.addRow(values)
      chart = new google.visualization[@chartType]($chartContainer.get(0))
      chart.draw(data,
        curveType: "function"
        vAxis:
          logScale: true
      )

Template.chart.rendered = ->

Template.chart.events
#  "click .selector": (event, template) ->

Remove percentage values from chart output


AppConfig = require('../initializers/config')
Deploy = require('../lib/deploy')
range_check = require('range_check')

tagRefersToServer = (tag, serverName) ->
  return new RegExp("^#{serverName}").test(tag)

getIpFromRequest = (req) ->
  req.connection.remoteAddress

GITHUB_IP_RANGE = "192.30.252.0/22"

ipIsFromGithub = (ip) ->
  range_check.in_range(ip, GITHUB_IP_RANGE)

exports.index = (req, res) ->
  remoteIp = getIpFromRequest(req)
  envIsNotDevelopment = process.env.NODE_ENV isnt 'development'
  if !ipIsFromGithub(remoteIp) and envIsNotDevelopment
    return res.send 401

  parsedPayload = req.body

  console.log "Got deploy message from #{parsedPayload.ref}"

  serverName = AppConfig.get('server_name')
  tagName = parsedPayload.ref

  unless tagRefersToServer(tagName, serverName)
    errMessage = "Only deploys for this server (#{serverName}) are accepted"
    console.log errMessage
    return res.send 500, errMessage

  console.log "Updating code from #{tagName}..."
  Deploy.deploy(tagName).then(->
    console.log "Code update finished, restarting server"
    process.exit()
  ).catch((err)->
    console.log "Error updating code:"
    console.error err
  )

  res.send 200

AppConfig = require('../initializers/config')
Deploy = require('../lib/deploy')
range_check = require('range_check')

tagRefersToServer = (tag, serverName) ->
  return new RegExp("^#{serverName}").test(tag)

getIpFromRequest = (req) ->
  req.connection.remoteAddress

GITHUB_IP_RANGE = "192.30.252.0/22"

ipIsFromGithub = (ip) ->
  range_check.in_range(ip, GITHUB_IP_RANGE)

exports.index = (req, res) ->
  remoteIp = getIpFromRequest(req)

  env = process.env.NODE_ENV
  env ||= 'development'
  if env isnt 'development'
    return res.send 401 unless ipIsFromGithub(remoteIp)

  parsedPayload = req.body

  console.log "Got deploy message from #{parsedPayload.ref}"

  serverName = AppConfig.get('server_name')
  tagName = parsedPayload.ref

  unless tagRefersToServer(tagName, serverName)
    errMessage = "Only deploys for this server (#{serverName}) are accepted"
    console.log errMessage
    return res.send 500, errMessage

  console.log "Updating code from #{tagName}..."
  Deploy.deploy(tagName).then(->
    console.log "Code update finished, restarting server"
    process.exit()
  ).catch((err)->
    console.log "Error updating code:"
    console.error err
  )

  res.send 200

Make "don't check github ip in development" work


Hummingbird.TruncateTextComponent = Ember.Component.extend
  expanded: false

  isTruncated: (->
    @get('text').length > @get('length') + 10
  ).property('text', 'length')

  truncatedText: (->
    if @get('isTruncated') and not @get('expanded')
      jQuery.trim(@get('text')).substring(0, @get('length')).trim(this) + "..."
    else
      @get('text')
  ).property('text', 'length', 'expanded')

  actions:
    toggleExpansion: ->
      @toggleProperty 'expanded'

Hummingbird.TruncateTextComponent = Ember.Component.extend
  expanded: false

  isTruncated: (->
    @get('text').length > @get('length') + 10
  ).property('text', 'length')

  truncatedText: (->
    if @get('isTruncated') and not @get('expanded')
      jQuery.trim(@get('text')).substring(0, @get('length')).trim(this) + "…"
    else
      @get('text')
  ).property('text', 'length', 'expanded')

  actions:
    toggleExpansion: ->
      @toggleProperty 'expanded'

Use actual ellipsis unicode character for truncation.


path = require 'path'
fs = require 'fs-plus'
_  = require 'underscore-plus'

module.exports =
class PathFinder
  railsRootPathChildren: ['app', 'config', 'lib']
  ignores: /(?:\/.git\/|\.keep$|\.DS_Store$|\.eot$|\.otf$|\.ttf$|\.woff$|\.png$|\.svg$|\.jpg$|\.gif$|\.mp4$|\.eps$|\.psd$)/

  constructor: (currentPath) ->
    @railsRootPath = @getRailsRootPath(currentPath)

  getPathes: (key) ->
    return [] unless @railsRootPath

    pathes = []
    for relativeRootPath in atom.config.get("rails-finder.#{key}Pathes")
      rootPath = path.join(@railsRootPath, relativeRootPath)
      appendPathes = _.filter(fs.listTreeSync(rootPath), (candidatePath) =>
        fs.isFileSync(candidatePath) && !@ignores.test(candidatePath)
      )
      pathes = pathes.concat(appendPathes)

    return _.uniq(pathes)

  getRailsRootPath: (currentPath) ->
    candidatePath = path.dirname(currentPath)
    while candidatePath != '/'
      candidatePath = path.resolve(path.join(candidatePath, '..'))

      children = _.map(fs.listSync(candidatePath), (child) ->
        path.basename(child)
      )
      isRailsRootPath = _.all(@railsRootPathChildren, (railsRootPathChild)->
        _.contains(children, railsRootPathChild)
      )
      if isRailsRootPath
        return candidatePath
    return atom.project.rootDirectories[0].path

path = require 'path'
fs = require 'fs-plus'
_  = require 'underscore-plus'

module.exports =
class PathFinder
  railsRootPathChildren: ['app', 'config', 'lib']
  ignores: /(?:\/.git\/|\.(?:git)?keep$|\.DS_Store$|\.eot$|\.otf$|\.ttf$|\.woff$|\.png$|\.svg$|\.jpg$|\.gif$|\.mp4$|\.eps$|\.psd$)/

  constructor: (currentPath) ->
    @railsRootPath = @getRailsRootPath(currentPath)

  getPathes: (key) ->
    return [] unless @railsRootPath

    pathes = []
    for relativeRootPath in atom.config.get("rails-finder.#{key}Pathes")
      rootPath = path.join(@railsRootPath, relativeRootPath)
      appendPathes = _.filter(fs.listTreeSync(rootPath), (candidatePath) =>
        fs.isFileSync(candidatePath) && !@ignores.test(candidatePath)
      )
      pathes = pathes.concat(appendPathes)

    return _.uniq(pathes)

  getRailsRootPath: (currentPath) ->
    candidatePath = path.dirname(currentPath)
    while candidatePath != '/'
      candidatePath = path.resolve(path.join(candidatePath, '..'))

      children = _.map(fs.listSync(candidatePath), (child) ->
        path.basename(child)
      )
      isRailsRootPath = _.all(@railsRootPathChildren, (railsRootPathChild)->
        _.contains(children, railsRootPathChild)
      )
      if isRailsRootPath
        return candidatePath
    return atom.project.rootDirectories[0].path

Fix tiny bug in ignores

Fix tiny bug in ignores


`import Ember from 'ember'`

Location = Ember.HistoryLocation.extend
  init: ->
    @_super.apply this, arguments

    if auth = @get('auth')
      # location's getURL is first called before we even
      # get to routes, so autoSignIn won't be called in
      # such case
      auth.autoSignIn() unless auth.get('signedIn')

  getURL: ->
    url = this._super.apply(this, arguments)
    if location.pathname == '/'
      if @get('auth.signedIn')
        return '/repositories'
      else
        return '/home'

    url

  formatURL: (logicalPath) ->
    if logicalPath == '/repositories' || logicalPath == '/home'
      '/'
    else
      @_super.apply this, arguments

`export default Location`

`import Ember from 'ember'`
`import config from 'travis/config/environment'`

Location = Ember.HistoryLocation.extend
  init: ->
    @_super.apply this, arguments

    if auth = @get('auth')
      # location's getURL is first called before we even
      # get to routes, so autoSignIn won't be called in
      # such case
      auth.autoSignIn() unless auth.get('signedIn')

  getURL: ->
    url = this._super.apply(this, arguments)
    unless config.pro
      if location.pathname == '/'
        if @get('auth.signedIn')
          return '/repositories'
        else
          return '/home'

    url

  formatURL: (logicalPath) ->
    if logicalPath == '/repositories' || logicalPath == '/home'
      '/'
    else
      @_super.apply this, arguments

`export default Location`

Disable landing page on pro for now

Disable landing page on pro for now


jQuery ->
	myOptions =
		center: new google.maps.LatLng(-34.397, 150.644)
		zoom: 8
		mapTypeId: google.maps.MapTypeId.ROADMAP
	map = new google.maps.Map(document.getElementById("centermap"), myOptions)

$ ->
	myOptions =
		center: new google.maps.LatLng(-34.397, 150.644)
		zoom: 8
		disableDefaultUI: true
		mapTypeId: google.maps.MapTypeId.ROADMAP
	map = new google.maps.Map(document.getElementById("centermap"), myOptions)

Disable default Google Maps controls

Disable default Google Maps controls


RootView = require 'root-view'
Editor = require 'editor'
ChildProcess = require 'child_process'

describe "link package", ->
  [editor] = []

  beforeEach ->
    atom.activatePackage('javascript.tmbundle', sync: true)
    atom.activatePackage('hyperlink-helper.tmbundle', sync: true)
    window.rootView = new RootView
    rootView.open('sample.js')
    atom.activatePackage('link')
    rootView.attachToDom()
    editor = rootView.getActiveView()
    editor.insertText("// http://github.com\n")

  describe "when the cursor is on a link", ->
    it "opens the link using the 'open' command", ->
      spyOn(ChildProcess, 'spawn')
      editor.trigger('link:open')
      expect(ChildProcess.spawn).not.toHaveBeenCalled()

      editor.setCursorBufferPosition([0,5])
      editor.trigger('link:open')

      expect(ChildProcess.spawn).toHaveBeenCalled()
      expect(ChildProcess.spawn.argsForCall[0][1][0]).toBe "http://github.com"

RootView = require 'root-view'
Editor = require 'editor'
ChildProcess = require 'child_process'

describe "link package", ->
  [editor] = []

  beforeEach ->
    atom.activatePackage('javascript-tmbundle', sync: true)
    atom.activatePackage('hyperlink-helper-tmbundle', sync: true)
    window.rootView = new RootView
    rootView.open('sample.js')
    atom.activatePackage('link')
    rootView.attachToDom()
    editor = rootView.getActiveView()
    editor.insertText("// http://github.com\n")

  describe "when the cursor is on a link", ->
    it "opens the link using the 'open' command", ->
      spyOn(ChildProcess, 'spawn')
      editor.trigger('link:open')
      expect(ChildProcess.spawn).not.toHaveBeenCalled()

      editor.setCursorBufferPosition([0,5])
      editor.trigger('link:open')

      expect(ChildProcess.spawn).toHaveBeenCalled()
      expect(ChildProcess.spawn.argsForCall[0][1][0]).toBe "http://github.com"

Use correct textmate package names

Use correct textmate package names


ETahi.ChosenView = Ember.Select.extend
  multiple: false
  width: '200px'
  disableSearchThreshold: 0
  searchContains: true
  attributeBindings:['multiple', 'width', 'disableSearchThreshold', 'searchContains', 'data-placeholder']
  changeAction: null

  change: ->
    action = @get('changeAction')
    @get('controller').send(action, @get('value')) if action

  setup: (->
    options =
      multiple: @get('multiple')
      width: @get('width')
      disable_search_threshold: @get('disableSearchThreshold')
      search_contains: @get('searchContains')
      no_results_text: @get('noResultsText')
      max_selected_options: @get('maxSelectedOptions')
      allow_single_deselect: @get('allowSingleDeselect')
      inherit_select_classes: true

    options.clean_search_text = @cleanSearchText
    options.calling_context = @

    @.$().chosen(options)

    @addObserver @get("optionLabelPath").replace(/^content/, "content.@each"), =>
      @rerenderChosen()
  ).on('didInsertElement')

  teardown: (->
    @.$().chosen('destroy')
  ).on('willDestroyElement')

  cleanSearchText: (option, context) ->
    option.text

  rerenderChosen: ->
    # Don't trigger Chosen update until after DOM elements have finished rendering.
    Ember.run.scheduleOnce 'afterRender', @, ->
      if @.$()
        @.$().trigger('chosen:updated')

Ember.Handlebars.helper('chosen', ETahi.ChosenView)

ETahi.ChosenView = Ember.Select.extend
  multiple: false
  width: '200px'
  disableSearchThreshold: 0
  searchContains: true
  attributeBindings:['multiple', 'width', 'disableSearchThreshold', 'searchContains', 'data-placeholder']
  changeAction: null

  change: ->
    action = @get('changeAction')
    @get('controller').send(action, @get('value')) if action

  setup: (->
    options =
      multiple: @get('multiple')
      width: @get('width')
      disable_search_threshold: @get('disableSearchThreshold')
      search_contains: @get('searchContains')
      no_results_text: @get('noResultsText')
      max_selected_options: @get('maxSelectedOptions')
      allow_single_deselect: @get('allowSingleDeselect')
      inherit_select_classes: true

    options.clean_search_text = @cleanSearchText
    options.calling_context = @

    @.$().chosen(options)

    @addObserver @get("optionLabelPath").replace(/^content/, "content.@each"), =>
      @rerenderChosen()
    @addObserver "value", =>
      @rerenderChosen()
  ).on('didInsertElement')

  teardown: (->
    @.$().chosen('destroy')
  ).on('willDestroyElement')

  cleanSearchText: (option, context) ->
    option.text

  rerenderChosen: ->
    # Don't trigger Chosen update until after DOM elements have finished rendering.
    Ember.run.scheduleOnce 'afterRender', @, ->
      if @.$()
        @.$().trigger('chosen:updated')

Ember.Handlebars.helper('chosen', ETahi.ChosenView)

Fix issue where chosen wouldn't update if bound selected value changed elsewhere


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

module.exports =
  class AtomPythonTestView extends ScrollView

    message: ''
    maximized: false

    @content: ->
      @div class: 'atom-python-test-view native-key-bindings', outlet: 'atomTestView', tabindex: -1, overflow: "auto", =>
        @div class: 'btn-toolbar', outlet:'toolbar', =>
          @button outlet: 'closeBtn', class: 'btn inline-block-tight right', click: 'destroy', style: 'float: right', =>
            @span class: 'icon icon-x'
        @pre class: 'output', outlet: 'output'

    initialize: ->
      @panel ?= atom.workspace.addBottomPanel(item: this)

    addLine: (line) ->
      @message += line
      @find(".output").text(@message)

    clear: ->
      @message = ''

    finish: ->
      console.log('finish')

    destroy: ->
      @panel.hide()

    reset: -> @message = defaultMessage

    toggle: ->
      @find(".output").height(500)
      @addLine 'Running tests... \n'
      @panel.show()

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

module.exports =
  class AtomPythonTestView extends ScrollView

    message: ''
    maximized: false

    @content: ->
      @div class: 'atom-python-test-view native-key-bindings', outlet: 'atomTestView', tabindex: -1, overflow: "auto", =>
        @div class: 'btn-toolbar', outlet:'toolbar', =>
          @button outlet: 'closeBtn', class: 'btn inline-block-tight right', click: 'destroy', style: 'float: right', =>
            @span class: 'icon icon-x'
        @pre class: 'output', outlet: 'output'

    initialize: ->
      @panel ?= atom.workspace.addBottomPanel(item: this)
      @panel.hide()

    addLine: (line) ->
      @message += line
      @find(".output").text(@message)

    clear: ->
      @message = ''

    finish: ->
      console.log('finish')

    destroy: ->
      @panel.hide()

    reset: -> @message = defaultMessage

    toggle: ->
      @find(".output").height(500)
      @addLine 'Running tests... \n'
      @panel.show()

Hide atom python test panel on Atom opening.


Sprangular.controller 'AccountCtrl', ($scope, $location, $routeParams, Status, Account) ->
  Status.pageTitle = 'My Account'

  user = Account.user

  $scope.editing = false
  $scope.user = user

  refreshAccount = ->
    Account.init().then ->
      user = Account.user
      user.password = ''
      user.password_confirmation = ''

  $scope.edit = ->
    $scope.editing = true

  $scope.stopEdit = ->
    $scope.editing = false

  $scope.save = ->
    user.errors = {}

    Account.save(user)
      .then (content) ->
        $scope.editing = false
        $location.path('/') if !Account.isLogged
      , (errors) ->
        user.errors = errors

  refreshAccount()

Sprangular.controller 'AccountCtrl', ($scope, $location, $routeParams, Status, Account) ->
  Status.pageTitle = 'My Account'

  user = Account.user

  $scope.editing = false
  $scope.user = user

  refreshAccount = ->
    Account.reload().then ->
      user = Account.user
      user.password = ''
      user.password_confirmation = ''

  $scope.edit = ->
    $scope.editing = true

  $scope.stopEdit = ->
    $scope.editing = false

  $scope.save = ->
    user.errors = {}

    Account.save(user)
      .then (content) ->
        $scope.editing = false
        $location.path('/') if !Account.isLogged
      , (errors) ->
        user.errors = errors

  refreshAccount()

Use `Account.reload` instead of `init`

Use `Account.reload` instead of `init`


ETahi.InlineEditBodyPartComponent = Em.Component.extend
  editing: false
  snapshot: []
  confirmDelete: false

  createSnapshot: (->
    @set('snapshot', Em.copy(@get('block'), true))
  ).observes('editing')

  hasContent: (->
    @get('block').any(@_isEmpty)
  ).property('block.@each.value')

  hasNoContent: Em.computed.not('hasContent')

  bodyPartType: (->
    @get('block.firstObject.type')
  ).property('block.@each.type')

  _isEmpty: (item) ->
    item && !Ember.isEmpty(item.value)

  actions:
    toggleEdit: ->
      @sendAction('cancel', @get('block'), @get('snapshot')) if @get('editing')
      @toggleProperty 'editing'

    deleteBlock: ->
      @sendAction('delete', @get('block'))

    save: ->
      if @get('hasContent')
        @sendAction('save', @get('block'))
        @toggleProperty 'editing'

    confirmDeletion: ->
      @set('confirmDelete', true)

    cancelDestroy: ->
      @set('confirmDelete', false)

    addItem: ->
      @sendAction('addItem', @get('block'))

ETahi.InlineEditBodyPartComponent = Em.Component.extend
  editing: false
  snapshot: []
  confirmDelete: false

  createSnapshot: (->
    @set('snapshot', Em.copy(@get('block'), true))
  ).observes('editing')

  hasContent: (->
    @get('block').any(@_isNotEmpty)
  ).property('block.@each.value')

  hasNoContent: Em.computed.not('hasContent')

  bodyPartType: (->
    @get('block.firstObject.type')
  ).property('block.@each.type')

  _isNotEmpty: (item) ->
    item && !Em.isEmpty(item.value)

  actions:
    toggleEdit: ->
      @sendAction('cancel', @get('block'), @get('snapshot')) if @get('editing')
      @toggleProperty 'editing'

    deleteBlock: ->
      @sendAction('delete', @get('block'))

    save: ->
      if @get('hasContent')
        @sendAction('save', @get('block'))
        @toggleProperty 'editing'

    confirmDeletion: ->
      @set('confirmDelete', true)

    cancelDestroy: ->
      @set('confirmDelete', false)

    addItem: ->
      @sendAction('addItem', @get('block'))

Correct poorly named private method

Correct poorly named private method


logger = require 'winston'
Visualizer = require('../model/visualizer').Visualizer
authorisation = require './authorisation'
utils = require '../utils'

exports.getAllVisualizers = ->
  # Must be admin
  if not authorisation.inGroup 'admin', this.authenticated
    utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getAllVisualizers denied.", 'info'
    return

  try
    v = yield Visualizer.find().exec()
    this.body = v
  catch err
    utils.logAndSetResponse this, 500, "Could not fetch visualizers via the API: #{err}", 'error'

exports.removeVisualizer = (name) ->
  # Must be admin
  if not authorisation.inGroup 'admin', this.authenticated
    utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeVisualizer denied.", 'info'
    return

  name = unescape name

  try
    v = yield Visualizer.findOneAndRemove(name: name).exec()
    if not v
      return utils.logAndSetResponse this, 404, "Could not find visualizer with #{name}", 'info'

    this.body = "Successfully removed visualizer with name #{name}"
    logger.info "User #{this.authenticated.name} removed visualizer #{name}"
  catch e
    utils.logAndSetResponse this, 500, "Could not remove visualizer #{name} via the API #{e}", 'error'

logger = require 'winston'
Visualizer = require('../model/visualizer').Visualizer
authorisation = require './authorisation'
utils = require '../utils'

exports.getAllVisualizers = ->
  # Must be admin
  if not authorisation.inGroup 'admin', this.authenticated
    utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to getAllVisualizers denied.", 'info'
    return

  try
    v = yield Visualizer.find().exec()
    this.body = v
  catch err
    utils.logAndSetResponse this, 500, "Could not fetch visualizers via the API: #{err}", 'error'

exports.removeVisualizer = (name) ->
  # Must be admin
  if not authorisation.inGroup 'admin', this.authenticated
    utils.logAndSetResponse this, 403, "User #{this.authenticated.email} is not an admin, API access to removeVisualizer denied.", 'info'
    return

  name = unescape name

  try
    v = yield Visualizer.findOneAndRemove(name: name).exec()
    if not v
      return utils.logAndSetResponse this, 404, "Could not find visualizer with #{name}", 'info'

    this.body = "Successfully removed visualizer with name #{name}"
    logger.info "User #{this.authenticated.email} removed visualizer #{name}"
  catch e
    utils.logAndSetResponse this, 500, "Could not remove visualizer #{name} via the API #{e}", 'error'

Fix user name in log

Fix user name in log


class Workbench.Views.DatastreamShowView extends Backbone.View
  template: JST["workbench/templates/datastream"]

  tagName: "li"
  className: "datastream"

  initialize: ->
    @renderDeferred = $.Deferred()

    @chartView = new Workbench.Views.DatastreamChartView
      model: @model

    @latestView = new Workbench.Views.DatastreamLatestView
      model: @model

    @listenTo @model, "change:seriesData", =>
      # Defer until after main element is rendered
      @renderDeferred.done(=>
        # Render the chart
        _.delay(=>
          @chartView.setElement(@$(".chart")).render()
        , 0)

        # Render the latest view
        @latestView.setElement(@$("#latest_#{@model.id}")).render()
      )

  remove: ->
    @chartView.remove()
    @latestView.remove()
    super()

  render: ->
    @$el.animate("min-height": 200).promise().done(=>
      @$el.html(@template(@model.toJSON()))
      @renderDeferred.resolve()
    )
    this

class Workbench.Views.DatastreamShowView extends Backbone.Marionette.ItemView
  template: "workbench/templates/datastream"

  tagName: "li"
  className: "datastream"

  initialize: ->
    @renderDeferred = $.Deferred()

    @chartView = new Workbench.Views.DatastreamChartView
      model: @model

    @latestView = new Workbench.Views.DatastreamLatestView
      model: @model

    @listenTo @model, "change:seriesData", =>
      # Defer until after main element is rendered
      @renderDeferred.done(=>
        # Render the chart
        _.delay(=>
          @chartView.setElement(@$(".chart")).render()
        , 0)

        # Render the latest view
        @latestView.setElement(@$("#latest_#{@model.id}")).render()
      )

  onBeforeDestroy: ->
    @chartView.remove()
    @latestView.remove()

  onRender: ->
    @renderDeferred.resolve()

Update Datastream view to ItemView

Update Datastream view to ItemView


class @WalletPairingProgressDialogViewController extends DialogViewController

  view:
    contentContainer: "#content_container"

  onAfterRender: ->
    super
    # launch request
    @_request = @params.request
    @_request?.onComplete (screen, error) =>
      @_request = null
      if screen?
        dialog = new CommonDialogsMessageDialogViewController(kind: "success", title: t("wallet.pairing.errors.pairing_succeeded"), subtitle: _.str.sprintf(t("wallet.pairing.errors.dongle_is_now_paired"), screen.name))
      else
        dialog = new CommonDialogsMessageDialogViewController(kind: "error", title: t("wallet.pairing.errors.pairing_failed"), subtitle: t("wallet.pairing.errors." + error))
      dialog.show()
    @_request?.on 'finalizing', @_onFinalizing
    # show spinner
    @view.spinner = ledger.spinners.createLargeSpinner(@view.contentContainer[0])

  onDetach: ->
    super
    @_request?.off 'finalizing', @_onFinalizing

  onDismiss: ->
    super
    @_request?.cancel()

  _onFinalizing: ->
    ledger.m2fa.PairedSecureScreen.getScreensByUuidFromSyncedStore @_request.getDeviceUuid(), (screens, error) =>
      if screens?.length is 0
        @getDialog().push new WalletPairingFinalizingDialogViewController(request: @_request)
      else
        @_request.setSecureScreenName(screens[0].name)

class @WalletPairingProgressDialogViewController extends DialogViewController

  view:
    contentContainer: "#content_container"

  onAfterRender: ->
    super
    # launch request
    @_request = @params.request
    @_request?.onComplete (screen, error) =>
      @_request = null
      @dismiss () =>
        if screen?
          dialog = new CommonDialogsMessageDialogViewController(kind: "success", title: t("wallet.pairing.errors.pairing_succeeded"), subtitle: _.str.sprintf(t("wallet.pairing.errors.dongle_is_now_paired"), screen.name))
        else
          dialog = new CommonDialogsMessageDialogViewController(kind: "error", title: t("wallet.pairing.errors.pairing_failed"), subtitle: t("wallet.pairing.errors." + error))
        dialog.show()
    @_request?.on 'finalizing', @_onFinalizing
    # show spinner
    @view.spinner = ledger.spinners.createLargeSpinner(@view.contentContainer[0])

  onDetach: ->
    super
    @_request?.off 'finalizing', @_onFinalizing

  onDismiss: ->
    super
    @_request?.cancel()

  _onFinalizing: ->
    ledger.m2fa.PairedSecureScreen.getScreensByUuidFromSyncedStore @_request.getDeviceUuid(), (screens, error) =>
      if screens?.length is 0
        @getDialog().push new WalletPairingFinalizingDialogViewController(request: @_request)
      else
        @_request.setSecureScreenName(screens[0].name)

Fix "don't dismiss pairing progress dialog when displaying success"


angular.module("hyperadmin", [ "ui.router" ])
  .config ($httpProvider) ->
    authToken = $("meta[name=\"csrf-token\"]").attr("content")
    $httpProvider.defaults.headers.common["X-CSRF-TOKEN"] = authToken
    $httpProvider.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"
    $httpProvider.defaults.headers.common["Accept"] = "text/html,application/json"

Configure $http service for Rails

Configure $http service for Rails


kd                = require 'kd'
KDButtonView      = kd.ButtonView
KDProgressBarView = kd.ProgressBarView
KDCustomHTMLView  = kd.CustomHTMLView

module.exports = class ButtonViewWithProgressBar extends KDCustomHTMLView

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

    super options, data

    o               = @getOptions()     or {}
    buttonOptions   = o.buttonOptions   or {}
    progressOptions = o.progressOptions or {}
    loaderOptions   = o.loaderOptions   or {}

    buttonOptions.cb         = buttonOptions.callback
    buttonOptions.callback   = @bound 'handleCallback'
    progressOptions.cssClass = kd.utils.curry 'hidden', progressOptions.cssClass

    @addSubView @button      = new KDButtonView buttonOptions
    @addSubView @progressBar = new KDProgressBarView progressOptions

  handleCallback: ->

    buttonOptions = @getOption 'buttonOptions' or {}
    buttonOptions.cb?.call()

    @startProgress()

  startProgress: ->

    @button.disable()
    @progressBar.show()

  resetProgress: ->

    @show()
    @progressBar.hide()
    @updateProgress 0
    @button.enable()

  updateProgress: (value, unit, label) ->

    @progressBar.updateBar value, unit, label

kd                = require 'kd'
KDButtonView      = kd.ButtonView
KDProgressBarView = kd.ProgressBarView
KDCustomHTMLView  = kd.CustomHTMLView

module.exports = class ButtonViewWithProgressBar extends KDCustomHTMLView

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

    super options, data

    o                = @getOptions()     or {}
    o.startProgress ?= yes

    buttonOptions    = o.buttonOptions   or {}
    progressOptions  = o.progressOptions or {}
    loaderOptions    = o.loaderOptions   or {}

    buttonOptions.cb         = buttonOptions.callback
    buttonOptions.callback   = @bound 'handleCallback'
    progressOptions.cssClass = kd.utils.curry 'hidden', progressOptions.cssClass

    @addSubView @button      = new KDButtonView buttonOptions
    @addSubView @progressBar = new KDProgressBarView progressOptions

  handleCallback: ->

    buttonOptions = @getOption 'buttonOptions' or {}
    buttonOptions.cb?.call()

    @startProgress()  if @getOption 'startProgress'

  startProgress: ->

    @button.disable()
    @progressBar.show()

  resetProgress: ->

    @show()
    @progressBar.hide()
    @updateProgress 0
    @button.enable()

  updateProgress: (value, unit, label) ->

    @progressBar.updateBar value, unit, label

ButtonViewWithProgressBar: Add "startProgress" parameter to start to show progress bar.


# Keybindings require three things to be fully defined: A selector that is
# matched against the focused element, the keystroke and the command to
# execute.
#
# Below is a basic keybinding which registers on all platforms by applying to
# the root workspace element.

# For more detailed documentation see
# https://atom.io/docs/latest/advanced/keymaps

'atom-text-editor[data-grammar~=fsharp]':
    'alt-enter': 'FSI:Send-Selection'
    'alt-/':'FSI:Send-Line'
    'ctrl-space': 'fsharp:autocomplete'
    'cmd-space': 'fsharp:autocomplete'

# Keybindings require three things to be fully defined: A selector that is
# matched against the focused element, the keystroke and the command to
# execute.
#
# Below is a basic keybinding which registers on all platforms by applying to
# the root workspace element.

# For more detailed documentation see
# https://atom.io/docs/latest/advanced/keymaps

'atom-workspace atom-text-editor:not([mini])[data-grammar~=fsharp]':
    'alt-enter': 'FSI:Send-Selection'
    'alt-/':'FSI:Send-Line'
    'ctrl-space': 'fsharp:autocomplete'
    'cmd-space': 'fsharp:autocomplete'

Change keymap selector (fixes alt-enter override in OSX)


ETahi.FigureOverlayView = ETahi.OverlayView.extend
  templateName: 'overlays/figure_overlay'
  layoutName: 'layouts/no_assignee_overlay_layout' #TODO: include assignee here?
  uploads: Ember.ArrayController.create content: []
  figures: null

  didInsertElement: ->
    @set 'figures', @get('controller.paper.figures')
    uploader = $('.js-jquery-fileupload')
    uploader.fileupload
      url: "/papers/#{@controller.get('paper.id')}/figures"
      dataType: 'json'
      method: 'POST'

    uploader.on 'fileuploadprocessalways', (e, data) =>
      file = data.files[0]
      @uploads.pushObject
        filename: file.name
        preview: file.preview?.toDataURL()
        progress: 0
        progressBarStyle: "width: 0%;"

    uploader.on 'fileuploadprogress', (e, data) =>
      currentUpload = @uploads.findBy('filename', data.files[0].name)
      progress = parseInt(data.loaded / data.total * 100.0, 10) #rounds the number
      Ember.setProperties currentUpload,
        progress: progress
        progressBarStyle: "width: #{progress}%;"

    uploader.on 'fileuploaddone', (e, data) =>
      newUpload = @uploads.findBy 'filename', data.files[0].name
      @uploads.removeObject newUpload

      store = @get('controller.store')
      updatedFigures = _.map data.result.figures, (figure) ->
        store.createRecord 'figure', figure

      @figures.pushObjects updatedFigures

ETahi.FigureOverlayView = ETahi.OverlayView.extend
  templateName: 'overlays/figure_overlay'
  layoutName: 'layouts/no_assignee_overlay_layout' #TODO: include assignee here?
  uploads: []
  figures: Em.computed.alias('controller.paper.figures')

  setupUpload: (->
    uploader = $('.js-jquery-fileupload')
    uploader.fileupload
      url: "/papers/#{@controller.get('paper.id')}/figures"
      dataType: 'json'
      method: 'POST'

    uploader.on 'fileuploadprocessalways', (e, data) =>
      file = data.files[0]
      @uploads.pushObject
        filename: file.name
        preview: file.preview?.toDataURL()
        progress: 0
        progressBarStyle: "width: 0%;"

    uploader.on 'fileuploadprogress', (e, data) =>
      currentUpload = @uploads.findBy('filename', data.files[0].name)
      progress = parseInt(data.loaded / data.total * 100.0, 10) #rounds the number
      Ember.setProperties currentUpload,
        progress: progress
        progressBarStyle: "width: #{progress}%;"

    uploader.on 'fileuploaddone', (e, data) =>
      newUpload = @uploads.findBy 'filename', data.files[0].name
      @uploads.removeObject newUpload

      store = @get('controller.store')
      updatedFigures = _.map data.result.figures, (figure) ->
        store.push 'figure', figure

      @get('figures').pushObjects updatedFigures

  ).on('didInsertElement')

Fix deleting of newly uploaded figures

Fix deleting of newly uploaded figures


IdrisController = require './idris-controller'
{CompositeDisposable} = require 'atom'

module.exports =
  active: false
  statusbar: null

  config:
    pathToIdris:
      type: 'string'
      default: 'idris'
      description: 'Path to the idris executable'

  activate: ->
    @disposables = new CompositeDisposable

    @active = @initIdris()
    if not @isActive()
      @disposables.add myself=atom.workspace.onDidOpen (event) =>
        item = event.item
        @active = @initIdris()
        if @isActive()
          myself.dispose()

  initIdris: () ->
    if @isActive()
      true
    else
      idrisFileOpened = atom.workspace.getTextEditors().some @isIdrisFile
      if idrisFileOpened
        @controller = new IdrisController
        if @statusbar
          @controller.attachStatusIndicator @statusbar
        subscription = atom.commands.add 'atom-text-editor[data-grammar~="idris"]', @controller.getCommands()
        @subscriptions = new CompositeDisposable
        @subscriptions.add subscription
        true
      else
        false

  isActive: ->
    @active

  isIdrisFile: (editor) ->
    editor.getGrammar?()?.scopeName == 'source.idris'

  deactivate: ->
    @subscriptions.dispose()
    this.controller.destroy()

  consumeStatusBar: (statusbar) ->
    @statusbar = statusbar
    @controller?.attachStatusIndicator statusbar

IdrisController = require './idris-controller'
{CompositeDisposable} = require 'atom'

module.exports =
  config:
    pathToIdris:
      type: 'string'
      default: 'idris'
      description: 'Path to the idris executable'

  activate: ->
    @controller = new IdrisController

    subscription = atom.commands.add 'atom-text-editor[data-grammar~="idris"]', @controller.getCommands()
    @subscriptions = new CompositeDisposable
    @subscriptions.add subscription

  deactivate: ->
    @subscriptions.dispose()
    this.controller.destroy()

  consumeStatusBar: (statusBar) ->
    @controller.attachStatusIndicator statusBar

Revert "only start the idris compiler when there is an idris file opened"

This reverts commit 89c0032aca1593cc851a65e7836ea8f539258a11.

Conflicts:
	lib/language-idris.coffee


"*":
  editor:
    fontFamily: "input"
    fontSize: 13
    showInvisibles: true
    showIndentGuide: true
    invisibles: {}
  core:
    themes: [
      "one-dark-ui"
      "facebook-syntax"
    ]
  welcome:
    showOnStartup: false
  whitespace:
    removeTrailingWhitespace: true
    ignoreWhitespaceOnCurrentLine: false
    ensureSingleTrailingNewline: true
  "exception-reporting":
    userId: "b6917109-8650-33d4-94c7-9edad015d73f"
  linter: {}
  "highlight-column": {}
  "block-cursor":
    primaryColor:
      red: 195
      green: 59
      blue: 50
      alpha: 1
"highlight-line":
  hideHighlightOnSelect: true

"*":
  editor:
    fontFamily: "input"
    fontSize: 12
    showInvisibles: true
    showIndentGuide: true
    invisibles: {}
  core:
    themes: [
      "atom-material-ui"
      "gotham-syntax"
    ]
  welcome:
    showOnStartup: false
  whitespace:
    removeTrailingWhitespace: true
    ignoreWhitespaceOnCurrentLine: false
    ensureSingleTrailingNewline: true
  "exception-reporting":
    userId: "b6917109-8650-33d4-94c7-9edad015d73f"
  linter: {}
  "highlight-column": {}
  "block-cursor":
    primaryColor:
      red: 195
      green: 59
      blue: 50
      alpha: 1
"highlight-line":
  hideHighlightOnSelect: true

Update atom theme and change font-size

Update atom theme and change font-size


fs = require 'fs'
optimist = require 'optimist'

parseOptions = (args=[]) ->
  options = optimist(args)
  options.usage('Usage: filings <command>')
  options.alias('h', 'help').describe('h', 'Print this usage message')
  options.alias('v', 'version').describe('v', 'Print the filings version')
  options

module.exports =
  run: (args=process.argv[2..]) ->
    options = parseOptions(args)
    if options.argv.v
      console.log JSON.parse(fs.readFileSync('package.json')).version
    else if options.argv.h
      options.showHelp()
    else if command = options.argv._.shift()
      console.error "Unrecognized command: #{command}"
    else
      options.showHelp()

fs = require 'fs'
path = require 'path'
optimist = require 'optimist'
{FormFour} = require './filings'

parseOptions = (args=[]) ->
  options = optimist(args)
  options.usage('Usage: filings <command>')
  options.alias('h', 'help').describe('h', 'Print this usage message')
  options.alias('v', 'version').describe('v', 'Print the filings version')
  options

module.exports =
  run: (args=process.argv[2..]) ->
    options = parseOptions(args)
    [command, commandArgs...] = options.argv._
    if options.argv.v
      console.log JSON.parse(fs.readFileSync('package.json')).version
    else if options.argv.h
      options.showHelp()
    else if command = options.argv._.shift()
      switch command
        when 'profit'
          reportPath = path.resolve(process.cwd(), commandArgs.shift())
          FormFour.open reportPath, (error, formFour) ->
            if error?
              console.error(error)
            else
              console.log(formFour.getProfit())
        else
          console.error "Unrecognized command: #{command}"
    else
      options.showHelp()

Add form 4 profit command

Add form 4 profit command


# Helper function needed to deal with array-like stylesheet objects.
toArray = (obj) -> Array::slice.call obj

# Scans your stylesheet for pseudo classes and adds a class with the same name.
# Thanks to Knyle Style Sheets for the idea.

processStyles = ->
  # Compile regular expression.
  pseudos = [ 'link', 'visited', 'hover', 'active', 'focus', 'target',
              'enabled', 'disabled', 'checked' ]
  pseudoRe = new RegExp(":((" + pseudos.join(")|(") + "))", "gi")

  # Only get inline style elements, and only the first one
  styleSheet = toArray(document.styleSheets).filter((ss) -> not ss.href?)[0]
  if styleSheet?
    processedStyles = toArray(styleSheet.cssRules).filter((rule) ->
      # Keep only rules with pseudo classes.
      rule.selectorText and rule.selectorText.match pseudoRe
    ).map((rule) ->
      # Replace : with . and encoded :
      rule.cssText.replace pseudoRe, ".\\3A $1"
    ).reduce((prev, cur) ->
      prev + cur
    )

    # Add the styles to the document
    styleEl = document.createElement "style"
    styleEl.appendChild document.createTextNode processedStyles
    document.getElementsByTagName("head")[0].appendChild styleEl

# Scans your stylesheet for pseudo classes and adds a class with the same name.
# Thanks to Knyle Style Sheets for the idea.
$ ->
  addPseudoClasses()

add = (a, b) -> a + b

addPseudoClasses = ->
  # Compile regular expression.
  pseudos = [ 'link', 'visited', 'hover', 'active', 'focus', 'target',
              'enabled', 'disabled', 'checked' ]
  pseudoRe = new RegExp(":((" + pseudos.join(")|(") + "))", "gi")

  processedPseudoClasses = _.toArray(document.styleSheets)
    # Filter out `link` elements.
    .filter(
      (ss) ->
        not ss.href?
    ).map((ss) ->
      _.toArray(ss.cssRules)
      .filter((rule) ->
        # Keep only rules with pseudo classes.
        rule.selectorText and rule.selectorText.match pseudoRe
      ).map((rule) ->
        # Replace : with . and encoded :
        rule.cssText.replace pseudoRe, ".\\3A $1"
      ).reduce(add)
    ).reduce(add, '')

  if processedPseudoClasses.length
    # Add a new style element with the processed pseudo class styles.
    $('head').append $('<style />').text(processedPseudoClasses)

Refactor pseudo class selector script a bit


scrollbarWidth = 0
FactlinkJailRoot.loaded_promise.then ->
  # Create the measurement nod; see http://davidwalsh.name/detect-scrollbar-width
  scrollDiv = document.createElement("div");
  $(scrollDiv).css(
    width: "100px"
    height: "100px"
    overflow: "scroll"
    position: "absolute"
    top: "-9999px"
  )
  document.body.appendChild(scrollDiv)

  scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth

  document.body.removeChild(scrollDiv)
  console.log 'scrollbar width: ', scrollbarWidth

# To check for scrollbars on the window,  use the slightly unusual window.innerHeight
# rather than  document.documentElement.clientHeight so it works in css compat mode.
window_has_scrollbar = -> window.innerHeight < document.documentElement.scrollHeight
FactlinkJailRoot.on 'modalOpened', ->
  if scrollbarWidth > 0 && window_has_scrollbar()
    console.log 'has scrollbar!'
  document.documentElement.setAttribute('data-factlink-suppress-scrolling', '')
FactlinkJailRoot.on 'modalClosed', -> document.documentElement.removeAttribute('data-factlink-suppress-scrolling')

scrollbarWidth = 0
FactlinkJailRoot.loaded_promise.then ->
  # Create the measurement nod; see http://davidwalsh.name/detect-scrollbar-width
  scrollDiv = document.createElement("div");
  $(scrollDiv).css(
    width: "100px"
    height: "100px"
    overflow: "scroll"
    position: "absolute"
    top: "-9999px"
  )
  document.body.appendChild(scrollDiv)

  scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth

  document.body.removeChild(scrollDiv)
  console.log 'scrollbar width: ', scrollbarWidth

# To check for scrollbars on the window,  use the slightly unusual window.innerHeight
# rather than  document.documentElement.clientHeight so it works in css compat mode.
window_has_scrollbar = -> window.innerHeight < document.documentElement.scrollHeight

saved_marginRight = null

FactlinkJailRoot.on 'modalOpened', ->
  if scrollbarWidth > 0 && window_has_scrollbar()
    console.log 'has scrollbar!'
    saved_marginRight = document.documentElement.style.marginRight
    document.documentElement.style.marginRight = scrollbarWidth + 'px'

  document.documentElement.setAttribute('data-factlink-suppress-scrolling', '')
FactlinkJailRoot.on 'modalClosed', ->
  if saved_marginRight != null
    document.documentElement.style.marginRight = saved_marginRight

  document.documentElement.removeAttribute('data-factlink-suppress-scrolling')

Change html margin when the sidebar opens to compensate for change in


angular.module('admin.orderCycles', ['ngTagsInput', 'admin.indexUtils', 'admin.enterprises'])
  .directive 'datetimepicker', ($timeout, $parse) ->
    require: "ngModel"
    link: (scope, element, attrs, ngModel) ->
      $timeout ->
        flatpickr(element,  Object.assign({},
                            window.FLATPICKR_DATETIME_DEFAULT, {
                            onOpen: (selectedDates, dateStr, instance) ->
                              instance.setDate(ngModel.$modelValue)
                              instance.input.dispatchEvent(new Event('focus', { bubbles: true }));
                            }));

  .directive 'ofnOnChange', ->
    (scope, element, attrs) ->
      element.bind 'change', ->
        scope.$apply(attrs.ofnOnChange)

  .directive 'ofnSyncDistributions', ->
    (scope, element, attrs) ->
      element.bind 'change', ->
        if !$(this).is(':checked')
          scope.$apply ->
            scope.removeDistributionOfVariant(attrs.ofnSyncDistributions)

angular.module('admin.orderCycles', ['ngTagsInput', 'admin.indexUtils', 'admin.enterprises'])
  .directive 'datetimepicker', ($timeout, $parse) ->
    require: "ngModel"
    link: (scope, element, attrs, ngModel) ->
      $timeout ->
        fp = flatpickr(element,  Object.assign({},
                            window.FLATPICKR_DATETIME_DEFAULT, {
                            onOpen: (selectedDates, dateStr, instance) ->
                              instance.setDate(ngModel.$modelValue)
                              instance.input.dispatchEvent(new Event('focus', { bubbles: true }));
                            }));
        fp.minuteElement.addEventListener "keyup", (e) ->
          if !isNaN(event.target.value)
            fp.setDate(fp.selectedDates[0].setMinutes(e.target.value), true)
        fp.hourElement.addEventListener "keyup", (e) ->
          if !isNaN(event.target.value)
            fp.setDate(fp.selectedDates[0].setHours(e.target.value), true)

  .directive 'ofnOnChange', ->
    (scope, element, attrs) ->
      element.bind 'change', ->
        scope.$apply(attrs.ofnOnChange)

  .directive 'ofnSyncDistributions', ->
    (scope, element, attrs) ->
      element.bind 'change', ->
        if !$(this).is(':checked')
          scope.$apply ->
            scope.removeDistributionOfVariant(attrs.ofnSyncDistributions)

Add keyup event listener on hour/minute inputs

 - To set the date (and trigger the onChange event) when the user is typing through its keyboard


UIWatcher = require './ui-watcher'

module.exports =
  activate: (state) ->
    uiWatcher = new UIWatcher
      themeManager: atom.themes

    rootView.command 'dev-live-reload:reload-all', ->
      uiWatcher.reloadAll()

$ = require 'jquery'
UIWatcher = require './ui-watcher'

module.exports =
  activate: (state) ->

    # HACK: I need an actvation event when the ui or packages are all loaded.
    # It cant watch all the packages until they are all loaded.
    createUIWatcher = ->
      uiWatcher = new UIWatcher
        themeManager: atom.themes
      $(window).off 'focus', createUIWatcher
    $(window).on 'focus', createUIWatcher

    rootView.command 'dev-live-reload:reload-all', ->
      uiWatcher.reloadAll()

Create the UIWatcher after everything has been loaded


#= require trix/controllers/abstract_input_controller

class Trix.Level2InputController extends Trix.AbstractInputController
  events:
    beforeinput: (event) ->
      log(event)

    input: (event) ->
      log(event)

log = (event) ->
  console.log("[#{event.type}] #{event.inputType}: #{JSON.stringify(event.data)}")

#= require trix/controllers/abstract_input_controller

{objectsAreEqual} = Trix

class Trix.Level2InputController extends Trix.AbstractInputController
  mutationIsExpected: (mutationSummary) ->
    result = objectsAreEqual(mutationSummary, @inputSummary)
    console.log("[mutation] [#{if result then "expected" else "unexpected"}] #{JSON.stringify({mutationSummary})}")
    delete @inputSummary
    result

  events:
    beforeinput: (event) ->
      @inputSummary = @[event.inputType]?(event)
      console.group(event.inputType)
      console.log("[#{event.type}] #{JSON.stringify(event.data)} #{JSON.stringify({@inputSummary})}")

    input: (event) ->
      console.log("[#{event.type}] #{JSON.stringify(event.data)}")
      Promise.resolve().then(console.groupEnd)

  insertText: (event) ->
    textAdded = event.data
    @delegate?.inputControllerWillPerformTyping()
    @responder?.insertString(textAdded)
    {textAdded}

  deleteContentBackward: (event) ->
    textDeleted = [event.getTargetRanges()...].map(staticRangeToRange).join("")
    @delegate?.inputControllerWillPerformTyping()
    @responder?.deleteInDirection("backward")
    {textDeleted}

staticRangeToRange = (staticRange) ->
  range = document.createRange()
  range.setStart(staticRange.startContainer, staticRange.startOffset)
  range.setEnd(staticRange.endContainer, staticRange.endOffset)
  range

Add "insertText" and "deleteContentBackward" inputType handlers


determineBrowser = ->
  [ 'chrome', 'firefox', 'safari', 'phantom_js', 'unsupported-browser' ]
  .filter( (browser) -> $('html.'+browser).length
  )[0]

extension_link_by_browser =
  firefox: 'https://static.factlink.com/extension/firefox/factlink-latest.xpi'
  safari: 'https://static.factlink.com/extension/firefox/factlink.safariextz'
  chrome: 'javascript:chrome.webstore.install()'

icon_class_by_browser =
  firefox: 'install-firefox'
  safari: 'install-safari'
  chrome: 'install-chrome'

window.ReactInstallExtensionButton = React.createClass
  displayName: 'ReactInstallExtensionButton'
  render: ->
    browserName = determineBrowser()
    extension_link = extension_link_by_browser[browserName]
    icon_class = icon_class_by_browser[browserName]
    extra_class = if @props.huge_button then 'button-huge' else null
    if document.documentElement.getAttribute('data-factlink-extension-loaded') != undefined
      _button ['button', extra_class,
        disabled: true],
        'Factlink already installed.'
    else
      _div [],
        _div ['visible-when-chrome'],
          _a ['button-success', extra_class, href: extension_link],
            _span [icon_class]
            'Install Factlink for ' + browserName.capitalize()
        _div ['visible-when-firefox'],
          _a ['button-success', extra_class, href: extension_link],
            _span [icon_class]
            'Install Factlink for ' + browserName.capitalize()
        _div ['visible-when-safari'],
          _a ['button-success', extra_class, href: extension_link],
            _span [icon_class]
            'Install Factlink for ' + browserName.capitalize()

determineBrowser = ->
  [ 'chrome', 'firefox', 'safari', 'phantom_js', 'unsupported-browser' ]
  .filter( (browser) -> $('html.'+browser).length
  )[0]

extension_link_by_browser =
  firefox: 'https://static.factlink.com/extension/firefox/factlink-latest.xpi'
  safari: 'https://static.factlink.com/extension/firefox/factlink.safariextz'
  chrome: 'javascript:chrome.webstore.install()'

icon_class_by_browser =
  firefox: 'install-firefox'
  safari: 'install-safari'
  chrome: 'install-chrome'

window.ReactInstallExtensionButton = React.createClass
  displayName: 'ReactInstallExtensionButton'
  render: ->
    browserName = determineBrowser()
    extension_link = extension_link_by_browser[browserName]
    icon_class = icon_class_by_browser[browserName]
    extra_class = if @props.huge_button then 'button-huge' else null
    if document.documentElement.getAttribute('data-factlink-extension-loaded') != undefined
      _button ['button', extra_class,
        disabled: true],
        'Factlink already installed.'
    else
      _a ['button-success', extra_class, href: extension_link],
        _span [icon_class]
        'Install Factlink for ' + browserName.capitalize()

Simplify browser-specific extension install logic


# IMPORTANT: choose one
RL_LIB = "libreadline"  # NOTE: libreadline is GPL
#RL_LIB = "libedit"

HISTORY_FILE = require('path').join(process.env.HOME, '.mal-history')

rlwrap = {} # namespace for this module in web context

ffi = require('ffi')
fs = require('fs')

rllib = ffi.Library(RL_LIB, {
    'readline': ['string', ['string']],
    'add_history': ['int', ['string']]})

rl_history_loaded = false

exports.readline = rlwrap.readline = (prompt = 'user> ') ->
  if !rl_history_loaded
    rl_history_loaded = true
    lines = []
    if fs.existsSync(HISTORY_FILE)
        lines = fs.readFileSync(HISTORY_FILE).toString().split("\n");

    # Max of 2000 lines
    lines = lines[Math.max(lines.length - 2000, 0)..]
    rllib.add_history(line) for line in lines when line != ""

  line = rllib.readline prompt
  if line
    rllib.add_history line
    try
      fs.appendFileSync HISTORY_FILE, line + "\n"
    catch exc
      true

  line

# vim: ts=2:sw=2

readlineSync = require('readline-sync');

exports.readline = (prompt = 'user> ') ->
  readlineSync.question(prompt)

Fix CoffeeScript example. Use readline-sync. Old ffi thing does not work.


React = require 'react'
deep = require 'deep-get-set'

module.exports = React.createClass
  displayName: "SimpleTable"

  propTypes:
    columns: React.PropTypes.array
    data: React.PropTypes.array

  render: ->
    columns = @props.columns.map (column) ->
      if typeof column is "string"
        {column}
      else
        {column.displayName}

    body = @props.data.map (rowData, i) =>
      row = []
      for column in @props.columns
        # Columns can either be a simple string or be an object that defines
        # both a displayName and path for accessing the data.
        if typeof column is "string"
          datum = deep(rowData, column.toLowerCase())
          key = i + "-" + column
        else if column.path?
          datum = deep(rowData, column.path)
          key = i + "-" + column.path
        else if column.function?
          datum = column.function(rowData)
          key = i + "-" + column.displayName
        row.push {datum}
      return
{row}

    return (

{columns}

{body}

    )

Make react happy with keys

Make react happy with keys


class FactlinkJailRoot.ControlIframe
  constructor: ->
    @el = document.createElement('iframe')
    @el.className = 'factlink-control-frame'
    #need to append to outer document before we can access frame document.
    FactlinkJailRoot.$factlinkCoreContainer.append(@el)
    @$el = $(@el)
    @doc = @el.contentWindow.document;
    @doc.open()
    #need doctype to avoid quirks mode
    @doc.write('<!DOCTYPE html><title></title>')
    @doc.close()
    style = @doc.createElement('style')
    style.appendChild(@doc.createTextNode(FrameCss))
    @doc.head.appendChild(style)

  setContent: (contentNode) ->
    bodyEl = @doc.body
    while bodyEl.firstChild
      bodyEl.removeChild(bodyEl.firstChild)
    bodyEl.appendChild(contentNode)
    @resizeFrame()

  resizeFrame: ->
    @el.style.width = @doc.body.clientWidth  + 'px'
    @el.style.height = @doc.body.clientHeight + 'px'

  destroy: ->
    return unless @el
    @doc = null
    @el.parentElement?.removeChild(@el)
    @$el = @el = null

control_visibility_transition_time = 300+1000/60 #keep in sync with scss

class FactlinkJailRoot.ControlIframe
  constructor: ->
    @el = document.createElement('iframe')
    @el.className = 'factlink-control-frame'
    #need to append to outer document before we can access frame document.
    FactlinkJailRoot.$factlinkCoreContainer.append(@el)
    @$el = $(@el)
    @doc = @el.contentWindow.document;
    @doc.open()
    #need doctype to avoid quirks mode
    @doc.write('<!DOCTYPE html><title></title>')
    @doc.close()
    style = @doc.createElement('style')
    style.appendChild(@doc.createTextNode(FrameCss))
    @doc.head.appendChild(style)

  setContent: (contentNode) ->
    bodyEl = @doc.body
    while bodyEl.firstChild
      bodyEl.removeChild(bodyEl.firstChild)
    bodyEl.appendChild(contentNode)
    @resizeFrame()

  resizeFrame: ->
    @el.style.width = @doc.body.clientWidth  + 'px'
    @el.style.height = @doc.body.clientHeight + 'px'

  fadeIn: ->
    @$el.addClass 'factlink-control-visible'
    FactlinkJailRoot.Timer control_visibility_transition_time

  fadeOut: ->
    @$el.removeClass 'factlink-control-visible'
    FactlinkJailRoot.Timer control_visibility_transition_time

  #feature:should we communicate visibility to the control contents?

  destroy: ->
    return unless @el
    @doc = null
    @el.parentElement?.removeChild(@el)
    @$el = @el = null

Implement fadeout/in in control iframe; return deferred for completion handlers


_ = require('underscore')

class DeploymentMonitor

  timeout = 10000

  constructor: ()->
    @_deployment = null
    @_chat = null
    @_currentTimeout = 0
    @_eventListeners = {
      'change': ()=>
        @_resetTimeout()
        @_monitorTimeout()
      'close': ()=>
        @.removeDeployment()
      'error': ()=>
        @.removeDeployment()
    }

  setDeployment: (deployment, chat)->
    @removeDeployment() if @hasDeployment()
    @_deployment = deployment
    @_chat = chat
    _.each(@_eventListeners, (listener, event)=>
      @_deployment.on(event, listener)
    )

  hasDeployment: ()->
    return null != @_deployment

  getDeployment: ()->
    return @_deployment

  removeDeployment: ()->
    _.each(@_eventListeners, (listener, event)=>
      @_deployment.removeListener(event, listener)
    )
    @_deployment = null
    @_chat = null

  _monitorTimeout: _.debounce(()->
    if !@.hasDeployment()
      return
    @_currentTimeout += timeout
    @_chat.send "Running #{@_currentTimeout}ms: #{getLastText(@_deployment.data.output)}"
    @_monitorTimeout()
  , timeout)

  _resetTimeout: ()->
    if @_currentTimeout > 0
      @_chat.send "Continuing..."
    @_currentTimeout = 0

  getLastText = (text)->
    textLines = text.split(/\r?\n/)
    n = textLines.length - 1
    while(!textLines[n].trim() && n > 0)
      n--
    return textLines[n]

module.exports = DeploymentMonitor

_ = require('underscore')

class DeploymentMonitor

  timeout = 10000

  constructor: ()->
    @_deployment = null
    @_chat = null
    @_currentTimeout = 0
    @_eventListeners = {
      change: ()=>
        @_resetTimeout()
        @_monitorTimeout()
      close: ()=>
        @.removeDeployment()
      error: ()=>
        @.removeDeployment()
    }

  setDeployment: (deployment, chat)->
    @removeDeployment() if @hasDeployment()
    @_deployment = deployment
    @_chat = chat
    _.each(@_eventListeners, (listener, event)=>
      @_deployment.on(event, listener)
    )

  hasDeployment: ()->
    return null != @_deployment

  getDeployment: ()->
    return @_deployment

  removeDeployment: ()->
    _.each(@_eventListeners, (listener, event)=>
      @_deployment.removeListener(event, listener)
    )
    @_deployment = null
    @_chat = null

  _monitorTimeout: _.debounce(()->
    if !@.hasDeployment()
      return
    @_currentTimeout += timeout
    @_chat.send "Running #{@_currentTimeout}ms: #{getLastText(@_deployment.data.output)}"
    @_monitorTimeout()
  , timeout)

  _resetTimeout: ()->
    if @_currentTimeout > 0
      @_chat.send "Continuing..."
    @_currentTimeout = 0

  getLastText = (text)->
    textLines = text.split(/\r?\n/)
    n = textLines.length - 1
    while(!textLines[n].trim() && n > 0)
      n--
    return textLines[n]

module.exports = DeploymentMonitor

Remove unnecessary quotes of eventListeners.


App.CwbResultTableView = Em.View.extend

  didInsertElement: ->
    @$('[data-ot]').each (index, token) ->
      new Opentip token, $(token).data('ot'),
        style: 'dark'
        fixed: true

App.CwbResultTableView = Em.View.extend

  contentBinding: 'controller.arrangedContent'

  # We need to create tooltips with grammatical info for tokens after both of these have happened:
  # - the controller's content property has been filled with a page of search results
  # - the view has been rendered
  contentDidChange: (->
    return unless @get('content.length')

    # Use the afterRender queue since the table rows may not be rendered yet even though the
    # content property has been filled.
    Ember.run.scheduleOnce 'afterRender', @, ->
      @$('[data-ot]').each (index, token) ->
        new Opentip token, $(token).data('ot'),
          style: 'dark'
          fixed: true
  ).observes('content.length')

Fix creation of tooltips with grammatical token info


# Monkey patch Turbolinks to render 401
# See https://github.com/turbolinks/turbolinks/issues/179
#     https://github.com/projecthydra-labs/hyrax/issues/617
Turbolinks.HttpRequest.prototype.requestLoaded = ->
  @endRequest =>
    if 200 <= @xhr.status < 300 or @xhr.status == 401
      @delegate.requestCompletedWithResponse(@xhr.responseText, @xhr.getResponseHeader("Turbolinks-Location"))
    else
      @failed = true
      @delegate.requestFailedWithStatusCode(@xhr.status, @xhr.responseText)

# Monkey patch Turbolinks to render 401
# See https://github.com/turbolinks/turbolinks/issues/179
#     https://github.com/projecthydra-labs/hyrax/issues/617
if Turbolinks?
  Turbolinks.HttpRequest.prototype.requestLoaded = ->
    @endRequest =>
      if 200 <= @xhr.status < 300 or @xhr.status == 401
        @delegate.requestCompletedWithResponse(@xhr.responseText, @xhr.getResponseHeader("Turbolinks-Location"))
      else
        @failed = true
        @delegate.requestFailedWithStatusCode(@xhr.status, @xhr.responseText)

Make sure Turbolinks is defined before patching.


#= require almond

window.ttm ||= {}

ttm.ClassMixer = (klass)->
  klass.build = ->
    it = new klass
    it.initialize && it.initialize.apply(it, arguments)
    it
  klass.prototype.klass = klass
  klass

define "lib/class_mixer", ->
  return ttm.ClassMixer

#= require almond

window.ttm ||= {}
window.decorators ||= {}

ttm.ClassMixer = (klass)->
  klass.build = ->
    it = new klass
    it.initialize && it.initialize.apply(it, arguments)
    it
  klass.prototype.klass = klass
  klass

define "lib/class_mixer", ->
  return ttm.ClassMixer

WIP: Implement decorator pattern for student dashboard.


ETahi.AddAuthorFormComponent = Ember.Component.extend
  tagName: 'div'

  setNewAuthor: ( ->
    unless @get('newAuthor')
      @set('newAuthor', {})
  ).on('init')

  actions:
    toggleAuthorForm: ->
      @sendAction('hideAuthorForm')

    saveNewAuthor: ->
      @sendAction('saveAuthor', @get('newAuthor'))

ETahi.AddAuthorFormComponent = Ember.Component.extend
  tagName: 'div'

  setNewAuthor: ( ->
    unless @get('newAuthor')
      @set('newAuthor', {})
  ).on('init')

  actions:
    toggleAuthorForm: ->
      @sendAction('hideAuthorForm')

    saveNewAuthor: ->
      author = @get('newAuthor')
      @sendAction('saveAuthor', author)
      if Ember.typeOf(author) == 'object'
        @set('newAuthor', {})

Fix new author form holding on to new author.


Lanes.React.Mixins.Screen = {
    childContextTypes:
        screen: React.PropTypes.object

    listenNetworkEvents: true

    loadOrCreateModel: (options) ->
        if options.prop and @props[options.prop]
            @props[options.prop]
        else
            model = new options.klass
            if options.attribute and @props.args?.length
                model.fetch(_.extend( {}, options.syncOptions, {
                    query: {"#{options.attribute}": @props.args[0]}
                }))
            model

}

Lanes.React.Mixins.Screen = {

    childContextTypes:
        screen: React.PropTypes.object

    listenNetworkEvents: true

    loadOrCreateModel: (options) ->
        if options.prop and @props[options.prop]
            @props[options.prop]
        else
            model = new options.klass
            if options.attribute and @props.args?.length
                model.fetch(_.extend( {}, options.syncOptions, {
                    query: {"#{options.attribute}": @props.args[0]}
                })).then => @state?.commands?.setModel(model)
            model

}

Call setModel after fetching model

Call setModel after fetching model

Needed so the commands can notify observers


module.exports =
  configDefaults:
    clangCommand: 'clang'
    clangPlusPlusCommand: 'clang++'
    clangExecutablePath: null
    clangIncludePaths: '.'
    clangSuppressWarnings: false
    clangDefaultCFlags: '-Wall'
    clangDefaultCppFlags: '-Wall'

  activate: ->
    console.log 'activate linter-clang'

module.exports =
  configDefaults:
    clangCommand: 'clang'
    clangExecutablePath: null
    clangIncludePaths: '.'
    clangSuppressWarnings: false
    clangDefaultCFlags: '-Wall'
    clangDefaultCppFlags: '-Wall'

  activate: ->
    console.log 'activate linter-clang'

Remove Clang Plus Plus Command Variable.


app = require 'app'
fs = require 'fs'
path = require 'path'
protocol = require 'protocol'

# Handles requests with 'atom' protocol.
#
# It's created by {AtomApplication} upon instantiation and is used to create a
# custom resource loader for 'atom://' URLs.
#
# The following directories are searched in order:
#   * ~/.atom/assets
#   * ~/.atom/dev/packages (unless in safe mode)
#   * ~/.atom/packages
#   * RESOURCE_PATH/node_modules
#
module.exports =
class AtomProtocolHandler
  constructor: (@resourcePath, safeMode) ->
    @loadPaths = []

    unless safeMode
      @loadPaths.push(path.join(app.getHomeDir(), '.atom', 'dev', 'packages'))

    @loadPaths.push(path.join(app.getHomeDir(), '.atom', 'packages'))
    @loadPaths.push(path.join(@resourcePath, 'node_modules'))

    @registerAtomProtocol()

  # Creates the 'atom' custom protocol handler.
  registerAtomProtocol: ->
    protocol.registerProtocol 'atom', (request) =>
      relativePath = path.normalize(request.url.substr(7))

      if relativePath.indexOf('assets/') is 0
        assetsPath = path.join(app.getHomeDir(), '.atom', relativePath)
        filePath = assetsPath if fs.statSyncNoException(assetsPath).isFile?()

      unless filePath
        for loadPath in @loadPaths
          filePath = path.join(loadPath, relativePath)
          break if fs.statSyncNoException(filePath).isFile?()

      new protocol.RequestFileJob(filePath)

app = require 'app'
fs = require 'fs'
path = require 'path'
protocol = require 'protocol'

# Handles requests with 'atom' protocol.
#
# It's created by {AtomApplication} upon instantiation and is used to create a
# custom resource loader for 'atom://' URLs.
#
# The following directories are searched in order:
#   * ~/.atom/assets
#   * ~/.atom/dev/packages (unless in safe mode)
#   * ~/.atom/packages
#   * RESOURCE_PATH/node_modules
#
module.exports =
class AtomProtocolHandler
  constructor: (@resourcePath, safeMode) ->
    @loadPaths = []
    @dotAtomDirectory = path.join(app.getHomeDir(), '.atom')

    unless safeMode
      @loadPaths.push(path.join(@dotAtomDirectory, 'dev', 'packages'))

    @loadPaths.push(path.join(@dotAtomDirectory, 'packages'))
    @loadPaths.push(path.join(@resourcePath, 'node_modules'))

    @registerAtomProtocol()

  # Creates the 'atom' custom protocol handler.
  registerAtomProtocol: ->
    protocol.registerProtocol 'atom', (request) =>
      relativePath = path.normalize(request.url.substr(7))

      if relativePath.indexOf('assets/') is 0
        assetsPath = path.join(@dotAtomDirectory, relativePath)
        filePath = assetsPath if fs.statSyncNoException(assetsPath).isFile?()

      unless filePath
        for loadPath in @loadPaths
          filePath = path.join(loadPath, relativePath)
          break if fs.statSyncNoException(filePath).isFile?()

      new protocol.RequestFileJob(filePath)

Add dot atom directory ivar

Add dot atom directory ivar


Gather.Views.Work.JobFormView = Backbone.View.extend

  initialize: (options) ->

  events:
    'cocoon:after-insert': 'shiftInserted'

  shiftInserted: (event, inserted) ->
    @initDatePickers(inserted)

  initDatePickers: (inserted) ->
    $(inserted).find(".datetimepicker").datetimepicker()

Gather.Views.Work.JobFormView = Backbone.View.extend

  initialize: (options) ->
    @formatFields()

  events:
    'cocoon:after-insert': 'shiftInserted'
    'change #work_job_times': 'formatFields'

  formatFields: ->
    dateFormat = I18n.t('datepicker.pformat')
    timeFormat = I18n.t('timepicker.pformat')
    times = @$('#work_job_times').val()
    switch times
      when 'date_time' then @setPickerFormat("#{dateFormat} #{timeFormat}")
      when 'date_only', 'full_period' then @setPickerFormat(dateFormat)

  shiftInserted: (event, inserted) ->
    @initDatePickers(inserted)

  initDatePickers: (inserted) ->
    @$(inserted).find('.datetimepicker').datetimepicker()

  setPickerFormat: (format) ->
    @shiftDatePickers().map (picker) ->
      $(this).data('DateTimePicker').format(format)

  shiftDatePickers: ->
    @$('#shift-table .datetimepicker')

Set picker format based on times

7836: Set picker format based on times


class window.FavouriteTopicButtonView extends ActionButtonView
  mini: true

  onRender: -> @updateButton()

  initialize: ->
    @user = currentUser
    @bindTo @user.favourite_topics, 'add remove change reset', @updateButton, @

  templateHelpers: =>
    disabled_label: Factlink.Global.t.follow_topic.capitalize()
    disable_label:  Factlink.Global.t.unfavourite.capitalize()
    enabled_label:  Factlink.Global.t.favourited.capitalize()

  buttonEnabled: ->
    @model.get('slug_title') in @user.favourite_topics.pluck('slug_title')

  primaryAction: (e) ->
    @model.favourite()

  secondaryAction: (e) ->
    @model.unfavourite()

class window.FavouriteTopicButtonView extends ActionButtonView
  mini: true

  onRender: -> @updateButton()

  initialize: ->
    @user = currentUser
    @bindTo @user.favourite_topics, 'add remove change reset', @updateButton, @

  templateHelpers: =>
    disabled_label: Factlink.Global.t.follow_topic.capitalize()
    disable_label:  Factlink.Global.t.unfollow.capitalize()
    enabled_label:  Factlink.Global.t.followed.capitalize()

  buttonEnabled: ->
    @model.get('slug_title') in @user.favourite_topics.pluck('slug_title')

  primaryAction: (e) ->
    @model.favourite()

  secondaryAction: (e) ->
    @model.unfavourite()

Use unfollow labels for 'Follow topic' button


#!/usr/bin/env coffee

argv = require('yargs')
  .usage('Usage: $0 --teams [num] --time [num] --rest [num] --areas [num]')
  .demand(['teams'])
  .default('time', 33)
  .default('rest', 7)
  .default('areas', 1)
  .argv

{teams, time, rest, areas} = argv
{timeNeededMinutes, tourneySchedule, playoffGames} = require('../lib/tourney-time')(argv)

hours = Math.floor(timeNeededMinutes / 60)
minutes = timeNeededMinutes % 60

time = ""
time += "#{hours} hours" if hours
time += ', ' if hours and minutes
time += "#{minutes} minutes" if minutes

console.log """For #{teams} teams
               Playing #{time} minute games
               with #{rest} minute breaks in between games
               on #{areas} playing area(s)
               you'll play a #{tourneySchedule.type} tournament with #{tourneySchedule.games + playoffGames} total games
               #{tourneySchedule.games} tourney games and #{playoffGames} playoff games
               which will take #{time} """

console.log tourneySchedule

#!/usr/bin/env coffee

argv = require('yargs')
  .usage('Usage: $0 --teams [num] --time [num] --rest [num] --areas [num]')
  .demand(['teams'])
  .default('time', 33)
  .default('rest', 7)
  .default('areas', 1)
  .argv

{teams, time, rest, areas} = argv
{timeNeededMinutes, tourneySchedule, playoffGames, schedule} = require('../lib/tourney-time')(argv)

hours = Math.floor(timeNeededMinutes / 60)
minutes = timeNeededMinutes % 60

totalTime = ""
totalTime += "#{hours} hours" if hours
totalTime += ', ' if hours and minutes
totalTime += "#{minutes} minutes" if minutes

console.log """For #{teams} teams
               Playing #{time} minute games
               with #{rest} minute breaks in between games
               on #{areas} playing area(s)
               you'll play a #{tourneySchedule.type} tournament with #{tourneySchedule.games + playoffGames} total games
               #{tourneySchedule.games} tourney games and #{playoffGames} playoff games
               which will take #{totalTime} """

console.log schedule

Fix for bad game time output

bug: Fix for bad game time output


class DevToolsController extends AppController

  name    = "DevTools"
  version = "0.1"
  route   = "/:name?/#{name}"

  KD.registerAppClass this, {
    name, version, behavior: "application", route,
    menu          : [
      { title     : "Create a new App",    eventName : "create" }
      { type      : "separator" }
      { title     : "Save",                eventName : "save" }
      { title     : "Save All",            eventName : "saveAll" }
      { type      : "separator" }
      { title     : "Publish to AppStore", eventName : "publish" }
      { title     : "customViewToggleLiveReload" }
      { type      : "separator" }
      { title     : "customViewToggleFullscreen" }
      { type      : "separator" }
      { title     : "Exit",                eventName : "exit" }
    ]
  }

  constructor:(options = {}, data)->
    options.view    = new DevToolsMainView
    options.appInfo =
      name     : "DevTools"
      type     : "application"

    super options, data

  # FIXME facet, to make it work I had to call notifyWindowResizeListeners here
  handleQuery:->
    {workspace} = @getView()
    workspace.ready ->
      KD.getSingleton("windowController").notifyWindowResizeListeners()

class DevToolsController extends AppController

  name    = "DevTools"
  version = "0.1"
  route   = "/:name?/#{name}"

  KD.registerAppClass this, {
    name, version, behavior: "application", route,
    menu          : [
      { title     : "Create a new App",    eventName : "create" }
      { type      : "separator" }
      { title     : "Save",                eventName : "save" }
      { title     : "Save All",            eventName : "saveAll" }
      { type      : "separator" }
      { title     : "Publish to AppStore", eventName : "publish" }
      { title     : "customViewToggleLiveReload" }
      { type      : "separator" }
      { title     : "customViewToggleFullscreen" }
      { type      : "separator" }
      { title     : "Exit",                eventName : "exit" }
    ]
  }

  constructor:(options = {}, data)->
    options.view    = new DevToolsMainView
    options.appInfo =
      name     : "DevTools"
      type     : "application"

    super options, data

  # FIXME facet, to make it work I had to call notifyWindowResizeListeners here
  handleQuery:->
    {workspace} = @getView()
    workspace.ready ->
      wc = KD.getSingleton("windowController")
      wc.notifyWindowResizeListeners()
      wc.notifyWindowResizeListeners()

DevTools: Fix the resizeHandler, dunno why it needs to be called two times ~ FIXME later


unless Offline
  throw new Error("Offline simulate brought in without offline.js")

for state in ['up', 'down']
  if document.querySelector("script[data-simulate='#{ state }']") or localStorage.OFFLINE_SIMULATE is state
    Offline.options ?= {}
    Offline.options.checks ?= {}
    Offline.options.checks.active = state

unless Offline
  throw new Error("Offline simulate brought in without offline.js")

for state in ['up', 'down']
  if document.querySelector("script[data-simulate='#{ state }']") or localStorage?.OFFLINE_SIMULATE is state
    Offline.options ?= {}
    Offline.options.checks ?= {}
    Offline.options.checks.active = state

Fix missing availability check for window.localStorage (e.g. it is disabled by default in android webviews)


try
  ReactDOM = require 'react-dom'
catch
  ReactDOM = window.ReactDOM
unless ReactDOM?
  throw "Can't find ReactDOM"
module.exports = ReactDOM

try
  ReactDOM = require 'react-dom'
catch
  ReactDOM = window.ReactDOM

# can fall back to normal React until 0.15
unless ReactDOM?
  try
    ReactDOM = require 'react'
  catch
    ReactDOM = window.React

unless ReactDOM?
  throw "Can't find ReactDOM"

module.exports = ReactDOM

Allow ReactDOM -> React fallback

Allow ReactDOM -> React fallback


require 'atom'
{runSpecSuite} = require '../spec/jasmine-helper'

atom.openDevTools()

document.title = "Benchmark Suite"
benchmarkSuite = require.resolve('./benchmark-suite')
runSpecSuite(benchmarkSuite, true)

require '../src/atom'
{runSpecSuite} = require '../spec/jasmine-helper'

atom.openDevTools()

document.title = "Benchmark Suite"
benchmarkSuite = require.resolve('./benchmark-suite')
runSpecSuite(benchmarkSuite, true)

Use relative path to atom require

Use relative path to atom require


Template.newTaskForm.events
  'submit #new-task, click #addTaskButton': (e) ->
    e.preventDefault()
    body = $('#new-task-text').val()
    $('#new-task-text').val("")
    now = new Date()
    priority = 'low'
    list = 'Adel'
    Tasks.insert
      body: body
      dateDue: moment(now).add('w', 1).toDate()
      dateCreated: now
      dateCompleted: false
      modified: now
      list: list
      priority: priority
      completed: false
      repeating: false
    list = Lists.findOne
      name: list
    Lists.update list._id,
      $inc:
        numTodos: 1

Template.newTaskForm.events
  'submit #new-task, click #addTaskButton': (e) ->
    e.preventDefault()
    body = $('#new-task-text').val()
    $('#new-task-text').val("")
    now = new Date()
    priority = 'low'
    list = 'Home'
    Tasks.insert
      body: body
      dateDue: moment(now).add('w', 1).toDate()
      dateCreated: now
      dateCompleted: false
      modified: now
      list: list
      priority: priority
      completed: false
      repeating: false
    list = Lists.findOne
      name: list
    Lists.update list._id,
      $inc:
        numTodos: 1

Add tasks to 'Home' list by default

Add tasks to 'Home' list by default


{View} = require 'space-pen'

module.exports =
class Tab extends View
  @content: (editSession) ->
    @div class: 'tab', =>
      @span class: 'file-name', outlet: 'fileName'
      @span class: 'close-icon'

  initialize: (@editSession) ->
    @buffer = @editSession.buffer
    @subscribe @buffer, 'path-change', => @updateFileName()
    @subscribe @buffer, 'contents-modified', => @updateModifiedStatus()
    @subscribe @buffer, 'after-save', => @updateModifiedStatus()
    @subscribe @buffer, 'git-status-change', => @updateModifiedStatus()
    @updateFileName()
    @updateModifiedStatus()

  updateModifiedStatus: ->
    if @buffer.isModified()
      @toggleClass('file-modified') unless @isModified
      @isModified = true
    else
      @removeClass('file-modified') if @isModified
      @isModified = false

  updateFileName: ->
    @fileName.text(@editSession.buffer.getBaseName() ? 'untitled')

{View} = require 'space-pen'

module.exports =
class Tab extends View
  @content: (editSession) ->
    @div class: 'tab', =>
      @span class: 'file-name', outlet: 'fileName'
      @span class: 'close-icon'

  initialize: (@editSession) ->
    @buffer = @editSession.buffer
    @subscribe @buffer, 'path-changed', => @updateFileName()
    @subscribe @buffer, 'contents-modified', => @updateModifiedStatus()
    @subscribe @buffer, 'saved', => @updateModifiedStatus()
    @subscribe @buffer, 'git-status-changed', => @updateModifiedStatus()
    @updateFileName()
    @updateModifiedStatus()

  updateModifiedStatus: ->
    if @buffer.isModified()
      @toggleClass('file-modified') unless @isModified
      @isModified = true
    else
      @removeClass('file-modified') if @isModified
      @isModified = false

  updateFileName: ->
    @fileName.text(@editSession.buffer.getBaseName() ? 'untitled')

Rename `Anchor` and `Buffer` events to passive-voice scheme


class OpinionatorsAvatarView extends Backbone.Marionette.Layout
  tagName: 'span'
  className: 'opinionators-avatar'
  template: 'opinionators/avatar'

  onRender: ->
    UserPopoverContentView.makeTooltip @, @model

class window.OpinionatorsAvatarsView extends Backbone.Marionette.CompositeView
  tagName: 'span'
  className: 'opinionators-avatars'
  template: "opinionators/avatars"
  itemView: OpinionatorsAvatarView

  itemViewContainer: ".js-opinionators-avatars-collection"

  events:
    'click .js-show-all' : 'show_all'

  number_of_items: 7

  initialize: (options) ->
    @listenTo @collection, 'add remove reset sync', @render

  _initialEvents: -> # don't use default bindings to collection

  appendHtml: (collectionView, itemView, index) ->
    super if index < @truncatedListSizes().numberToShow

  templateHelpers: =>
    numberOfOthers: @truncatedListSizes().numberOfOthers

  truncatedListSizes: ->
    truncatedListSizes @collection.totalRecords, @number_of_items

  show_all: (e) ->
    e.stopPropagation()
    e.preventDefault()
    @number_of_items = Infinity
    @render()

class OpinionatorsAvatarView extends Backbone.Marionette.Layout
  tagName: 'span'
  className: 'opinionators-avatar'
  template: 'opinionators/avatar'

  onRender: ->
    UserPopoverContentView.makeTooltip @, @model

class window.OpinionatorsAvatarsView extends Backbone.Marionette.CompositeView
  tagName: 'span'
  className: 'opinionators-avatars'
  template: "opinionators/avatars"
  itemView: OpinionatorsAvatarView

  itemViewContainer: ".js-opinionators-avatars-collection"

  events:
    'click .js-show-all' : 'show_all'

  number_of_items: 4

  initialize: (options) ->
    @listenTo @collection, 'add remove reset sync', @render

  _initialEvents: -> # don't use default bindings to collection

  appendHtml: (collectionView, itemView, index) ->
    super if index < @truncatedListSizes().numberToShow

  templateHelpers: =>
    numberOfOthers: @truncatedListSizes().numberOfOthers

  truncatedListSizes: ->
    truncatedListSizes @collection.totalRecords, @number_of_items

  show_all: (e) ->
    e.stopPropagation()
    e.preventDefault()
    @number_of_items = Infinity
    @render()

Truncate to 4 images by default

Truncate to 4 images by default


settings = require "settings-sharelatex"
logger = require "logger-sharelatex"
_ = require "underscore"
request = require "request"

makeRequest: (opts, callback)->
	if settings.apis?.analytics?.url?
		request opts, callback
	else
		callback()

module.exports =

	recordEvent: (user_id, event, segmentation = {}, callback = (error) ->) ->
		if user_id == settings.smokeTest?.userId
			return callback()
		opts =
			body:
				event:event
				segmentation:segmentation
			json:true
			method:"POST"
			timeout:1000
			url: "#{settings.apis.analytics.url}/user/#{user_id}/event"
		makeRequest opts, callback

	getLastOccurance: (user_id, event, callback = (error) ->) ->
		opts =
			body:
				event:event
			json:true
			method:"POST"
			timeout:1000
			url: "#{settings.apis.analytics.url}/user/#{user_id}/event/last_occurnace"
		makeRequest opts, (err, response, body)->
			if err?
				console.log response, opts
				logger.err {user_id, err}, "error getting last occurance of event"
				return callback err
			else
				return callback null, body

settings = require "settings-sharelatex"
logger = require "logger-sharelatex"
_ = require "underscore"
request = require "request"

makeRequest = (opts, callback)->
	if settings.apis?.analytics?.url?
		urlPath = opts.url
		opts.url = "#{settings.apis.analytics.url}#{urlPath}"
		request opts, callback
	else
		callback()

module.exports =

	recordEvent: (user_id, event, segmentation = {}, callback = (error) ->) ->
		if user_id == settings.smokeTest?.userId
			return callback()
		opts =
			body:
				event:event
				segmentation:segmentation
			json:true
			method:"POST"
			timeout:1000
			url: "/user/#{user_id}/event"
		makeRequest opts, callback

	getLastOccurance: (user_id, event, callback = (error) ->) ->
		opts =
			body:
				event:event
			json:true
			method:"POST"
			timeout:1000
			url: "/user/#{user_id}/event/last_occurnace"
		makeRequest opts, (err, response, body)->
			if err?
				console.log response, opts
				logger.err {user_id, err}, "error getting last occurance of event"
				return callback err
			else
				return callback null, body

Fix up makeRequest, so it copes with `analytics.url` being un-configured.


CI.outer.Error = class Error extends CI.outer.Page
  constructor: ->
    @name = "error"
    @status = renderContext.status or 404
    @url = renderContext.githubPrivateAuthURL

  title: =>
    titles =
      401: "Login required"
      404: "Page not found"
      500: "Internal server error"

    titles[@status] or "Something unexpected happened"

  message: =>
    messages =
      401: "Login here to view this page"
      404: "We're sorry, but that page doesn't exist"
      500: "We're sorry, but something broke"
    messages[@status] or "Something completely unexpected happened"

  viewContext: =>
    title: @title()
    error: @status
    message: @message()

CI.outer.Error = class Error extends CI.outer.Page
  constructor: ->
    super
    @name = "error"
    @status = renderContext.status or 404
    @url = renderContext.githubPrivateAuthURL

  title: =>
    titles =
      401: "Login required"
      404: "Page not found"
      500: "Internal server error"

    titles[@status] or "Something unexpected happened"

  message: =>
    messages =
      401: "Login here to view this page"
      404: "We're sorry, but that page doesn't exist"
      500: "We're sorry, but something broke"
    messages[@status] or "Something completely unexpected happened"

  viewContext: =>
    title: @title()
    error: @status
    message: @message()

Fix the 401 page looking incorrect.

Fix the 401 page looking incorrect.

CI.outer.Error inherited from outer.Page, but wasn't calling super, so variables that Page expected, @opts, wasn't created

Fixes #1740


describe 'HeaderCells StringCell', ->
  HeaderCell = require '../../lib/header-cells/string-cell'

  initView = ({ model } = {}) ->
    model ?= new Backbone.Model label: 'header cell label'
    new HeaderCell { model }

  showView = ->
    initView(arguments...).render()

  it 'renders the label', ->
    expect(showView().$el).toHaveText 'header cell label'

  it 'has a className', ->
    expect(showView().$el).toHaveClass 'string-cell'

Improve string cell spec coverage

Improve string cell spec coverage


module.exports = (grunt) ->
  documentation = 'doc'
  grunt.initConfig
    pkg: grunt.file.readJSON 'package.json'
    clean: [
      'bin'
      '.grunt'
      documentation
    ]
    jsdoc:
      dist:
        src: ['topicmap.js', 'README.md']
        options:
          destination: documentation
          template: 'node_modules/ink-docstrap/template'
          configure: 'jsdoc.conf.json'
    'gh-pages':
      'default':
        src: '**/*'
        options:
          base: 'doc'
          message: 'Update documentation'
    travis:
      src: '**/*'
      options:
        base: 'doc'
        message: 'Update documentation'
        repo: 'https://' + process.env.GH_TOKEN + '@github.com/' + process.env.TRAVIS_REPO_SLUG
        user:
          name: 'Travis CI Server'
          email: 'will.byrne@hpe.com'
    watch:
      doc:
        files: [
          'src/**/*.js'
          'README.md'
        ]
        tasks: ['doc']

  grunt.loadNpmTasks 'grunt-gh-pages'
  grunt.loadNpmTasks 'grunt-jsdoc'

  grunt.registerTask 'doc', ['jsdoc']
  grunt.registerTask 'push-doc', ['doc', 'gh-pages:default']
  grunt.registerTask 'push-doc-travis', ['doc', 'gh-pages:travis']
  grunt.registerTask 'watch-doc', ['watch:doc']

[BIFHI-38] Set up travis for Topic Map [rev: Alex Scown]


#
# User icon via gravatar email address or user initials
#
angular.module('doubtfire.common.user-icon', [])
.directive('userIcon', ->
  restrict: 'E'
  replace: true
  scope:
    user: '=?'
    size: '=?'
    email: '=?'
  templateUrl: 'common/user-icon/user-icon.tpl.html'
  controller: ($scope, $http, currentUser, md5) ->
    $scope.user ?= currentUser.profile
    $scope.size ?= 100
    $scope.email ?= $scope.user.email

    $scope.userBackgroundStyle = (email) ->
      # Gravatar hash
      hash = if (email) then md5.createHash(email.trim().toLowerCase()) else md5.createHash('')
      backgroundUrl = "https://www.gravatar.com/avatar/#{hash}.png?default=blank&size=#{$scope.size}"
      "background-image: url('#{backgroundUrl}')"

    $scope.initials = (->
      initials = if ($scope.user && $scope.user.name) then $scope.user.name.split(" ") else "  "
      ("#{initials[0][0]}#{initials[1][0]}").toUpperCase()
    )()
)

#
# User icon via gravatar email address or user initials
#
angular.module('doubtfire.common.user-icon', [])
.directive('userIcon', ->
  restrict: 'E'
  replace: true
  scope:
    user: '=?'
    size: '=?'
    email: '=?'
  templateUrl: 'common/user-icon/user-icon.tpl.html'
  controller: ($scope, $http, currentUser, md5) ->
    $scope.user ?= currentUser.profile
    $scope.size ?= 100
    $scope.email ?= $scope.user.email

    $scope.userBackgroundStyle = (email) ->
      # Gravatar hash
      hash = if (email) then md5.createHash(email.trim().toLowerCase()) else md5.createHash('')
      backgroundUrl = "https://www.gravatar.com/avatar/#{hash}.png?default=blank&size=#{$scope.size}"
      "background-image: url('#{backgroundUrl}')"

    $scope.initials = (->
      initials = if ($scope.user && $scope.user.name) then $scope.user.name.split(" ") else "  "
      if initials.length > 1 then ("#{initials[0][0]}#{initials[1][0]}").toUpperCase() else "  "
    )()
)

Test length of name array in initials

FIX: Test length of name array in initials


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

ready = ->
  engine = new Bloodhound(
    datumTokenizer: (d) ->
      console.log d
      Bloodhound.tokenizers.whitespace d.title
    queryTokenizer: Bloodhound.tokenizers.whitespace
    remote: url: '../projects/typeahead/%QUERY')
  promise = engine.initialize()
  $('.typeahead').typeahead null,
    name: 'engine'
    displayKey: 'email'
    source: engine.ttAdapter()
  return

$(document).ready ready
$(document).on 'page:load', ready

ready = ->
  $('#SignOutMyself').click ->
    if !@checked
      url = document.URL

      alert 'You won\'t be able to perform any more actions on the project after you\'re unenrolled!'
    return
  return

$(document).ready ready
$(document).on 'page:load', ready

ready = ->
  $('#setInactiveButton').click ->
    alert 'You\'re going to set the project status to inactive'
  return

$(document).ready ready
$(document).on 'page:load', ready

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

ready = ->
  engine = new Bloodhound(
    datumTokenizer: (d) ->
      console.log d
      Bloodhound.tokenizers.whitespace d.title
    queryTokenizer: Bloodhound.tokenizers.whitespace
    remote: url: '../projects/typeahead/%QUERY')
  promise = engine.initialize()
  $('.typeahead').typeahead null,
    name: 'engine'
    displayKey: 'email'
    source: engine.ttAdapter()
  return

$(document).ready ready
$(document).on 'page:load', ready

ready = ->
  $('#SignOutMyself').click ->
    if !@checked
      url = document.URL
      locale = url.split('?')[1].split('=')[1]
      if locale == 'de'
        alert 'Sie sind nicht mehr befugt, weitere Maßnahmen für das Projekt durchzuführen, nachdem Sie sich aus dem Projekt ausgetragen haben!'
      else
        alert 'You won\'t be able to perform any more actions on the project after you\'re unenrolled!'
      return
    return
  return

$(document).ready ready
$(document).on 'page:load', ready

ready = ->
  $('#setInactiveButton').click ->
    url = document.URL
    locale = url.split('?')[1].split('=')[1]
    if locale == 'de'
      alert 'Das Projekt wird nun inaktiv geschalten!'
    else
      alert 'You\'re going to set the project status to inactive'
    return
  return

$(document).ready ready
$(document).on 'page:load', ready

Add translation for pop up messages

Add translation for pop up messages


{BufferedProcess, CompositeDisposable} = require 'atom'
lsc = require 'atom-livescript'

module.exports =
  provideLinter: ->
    grammarScopes: ['source.livescript']
    scope: 'file'
    lintOnFly: true
    lint: (textEditor)=>
      new Promise (resolve, reject)=>
        filePath = textEditor.getPath()
        fileText = textEditor.getText()
        try
          lsc.compile fileText
          resolve []
        catch err
          result = /Parse error on line (\d+): (.*)/.exec err.message
          messages = [
            type: 'Error'
            text: result[2]
            filePath: filePath
            range: [
              [parseInt(result[1])-1, 0]
              [parseInt(result[1]), 0]
            ]
          ]
          resolve messages

        process.onWillThrowError ({error, handle})=>
          atom.notifications.addError "Failed to run lsc",
            detail: error.message
            dismissable: true
          handle()
          resolve []

{BufferedProcess, CompositeDisposable} = require 'atom'
lsc = require 'atom-livescript'

module.exports =
  provideLinter: ->
    grammarScopes: ['source.livescript']
    scope: 'file'
    lintOnFly: true
    lint: (textEditor)=>
      new Promise (resolve, reject)=>
        filePath = textEditor.getPath()
        fileText = textEditor.getText()
        try
          lsc.compile fileText
          resolve []
        catch err
          result = switch
            when err instanceof SyntaxError
              r = /(.*) on line (\d+)$/.exec err.message
              line: r[2]
              text: r[1]
            else
              r = /Parse error on line (\d+): (.*)/.exec err.message
              line: r[1]
              text: r[2]
          messages = [
            type: 'Error'
            text: result.text
            filePath: filePath
            range: [
              [parseInt(result.line)-1, 0]
              [parseInt(result.line), 0]
            ]
          ]
          resolve messages

        process.onWillThrowError ({error, handle})=>
          atom.notifications.addError "Failed to run lsc",
            detail: error.message
            dismissable: true
          handle()
          resolve []

Fix for another parse error

Fix for another parse error