{CompositeDisposable} = require 'atom'

module.exports =
class MinimapBookmarksBinding
  constructor: (@minimap) ->
    @subscriptions = new CompositeDisposable
    @editor = @minimap.getTextEditor()

    @subscriptions.add @editor.displayBuffer.onDidCreateMarker (marker) =>
      if marker.matchesProperties(class: 'bookmark')
        @minimap.decorateMarker(marker, type: 'line', class: 'bookmark')

  destroy: ->
    @subscriptions.dispose()

{CompositeDisposable} = require 'atom'

module.exports =
class MinimapBookmarksBinding
  constructor: (@minimap) ->
    @subscriptions = new CompositeDisposable
    @editor = @minimap.getTextEditor()
    @decorationsByMarkerId = {}
    @decorationSubscriptionsByMarkerId = {}

    @subscriptions.add @editor.displayBuffer.onDidCreateMarker (marker) =>
      if marker.matchesProperties(class: 'bookmark')
        @handleMarker(marker)

    @editor.displayBuffer.findMarkers(class: 'bookmark').forEach (marker) =>
      @handleMarker(marker)

  handleMarker: (marker) ->
    {id} = marker
    decoration = @minimap.decorateMarker(marker, type: 'line', class: 'bookmark')
    @decorationsByMarkerId[id] = decoration
    @decorationSubscriptionsByMarkerId[id] = decoration.onDidDestroy =>
      @decorationSubscriptionsByMarkerId[id].dispose()

      delete @decorationsByMarkerId[id]
      delete @decorationSubscriptionsByMarkerId[id]

  destroy: ->
    for id,decoration of @decorationsByMarkerId
      @decorationSubscriptionsByMarkerId[id].dispose()
      decoration.destroy()

      delete @decorationsByMarkerId[id]
      delete @decorationSubscriptionsByMarkerId[id]

    @subscriptions.dispose()

Implement retrieving existing markers and destroying decorations along binding


request = require 'request'
should = require 'should'

startApp = require './start_app'
base = require './base'
options = require './options'

describe 'Basic Things', ->
  before (done) ->
    startApp done

  it 'should return version information', (done)->
    request (base '/'), options, (e,r,b)->
      r.statusCode.should.be.equal 200
      b.should.have.property 'version', require('../package').version
      done()

  it 'should send a JSON response on 404', (done)->
    request (base '/' + 'not-an-existent-route1234'), options, (e,r,b)->
      r.statusCode.should.be.equal 404
      r.headers['content-type'].should.be.equal 'application/json'
      b.error.should.be.equal '/not-an-existent-rout1234 was not found'
      done()

request = require 'request'
should = require 'should'

startApp = require './start_app'
base = require './base'
options = require './options'

describe 'Basic Things', ->
  before (done) ->
    startApp done

  it 'should return version information', (done)->
    request (base '/'), options, (e,r,b)->
      r.statusCode.should.be.equal 200
      b.should.have.property 'version', require('../package').version
      done()

  it 'should send a JSON response on 404', (done)->
    request (base '/' + 'not-an-existent-route1234'), options, (e,r,b)->
      r.statusCode.should.be.equal 404
      r.headers['content-type'].should.startWith 'application/json'
      b.error.should.be.equal '/not-an-existent-route1234 was not found'
      done()

Test should account for possible charset


fs = require('fs')
Q = require('q')
_ = require('underscore')

StandardIndicatorator = require('../indicatorators/standard_indicatorator')

GETTERS =
  gdoc: require('../getters/gdoc')
  cartodb: require('../getters/cartodb')

FORMATTERS =
  gdoc = require('../formatters/gdoc')

module.exports = class Indicator
  constructor: (attributes) ->
    _.extend(@, attributes)

  query: ->
    @getData().then( (data) =>
      formattedData = @formatData(data)
      StandardIndicatorator.applyRanges(formattedData, @range)
    )

  getData: ->
    Getter = GETTERS[@source]
    if Getter?
      getter = new Getter(@)
      getter.fetch()
    else
      throw new Error("No known getter for source '#{@source}'")

  formatData: (data) ->
    formatter = FORMATTERS[@source]
    if formatter?
      formatter(data)
    else
      throw new Error("No known formatter for source '#{@source}'")

  @find: (id) ->
    deferred = Q.defer()

    Q.nsend(
      fs, 'readFile', './definitions/indicators.json'
    ).then( (definitionsJSON) ->

      definitions = JSON.parse(definitionsJSON)
      indicator = new Indicator(
        _.findWhere(definitions, id: id)
      )

      deferred.resolve(indicator)
    ).fail(
      deferred.reject
    )

    return deferred.promise

fs = require('fs')
Q = require('q')
_ = require('underscore')

StandardIndicatorator = require('../indicatorators/standard_indicatorator')

GETTERS =
  gdoc: require('../getters/gdoc')
  cartodb: require('../getters/cartodb')

FORMATTERS =
  gdoc: require('../formatters/gdoc')
  cartodb: require('../formatters/cartodb')

module.exports = class Indicator
  constructor: (attributes) ->
    _.extend(@, attributes)

  query: ->
    @getData().then( (data) =>
      formattedData = @formatData(data)
      StandardIndicatorator.applyRanges(formattedData, @range)
    )

  getData: ->
    Getter = GETTERS[@source]
    if Getter?
      getter = new Getter(@)
      getter.fetch()
    else
      throw new Error("No known getter for source '#{@source}'")

  formatData: (data) ->
    formatter = FORMATTERS[@source]
    if formatter?
      formatter(data)
    else
      throw new Error("No known formatter for source '#{@source}'")

  @find: (id) ->
    deferred = Q.defer()

    Q.nsend(
      fs, 'readFile', './definitions/indicators.json'
    ).then( (definitionsJSON) ->

      definitions = JSON.parse(definitionsJSON)
      indicator = new Indicator(
        _.findWhere(definitions, id: id)
      )

      deferred.resolve(indicator)
    ).fail(
      deferred.reject
    )

    return deferred.promise

Make CartoDB formatter available for Indicator formatting


class KeypathObserver
  constructor: (@view, @model, @keypath, @callback) ->
    @interfaces = (k for k, v of @view.adapters)
    @objectPath = []
    @tokens = Rivets.KeypathParser.parse @keypath, @interfaces, @view.config.rootInterface
    @root = @tokens.shift()
    @key = @tokens.pop()
    @target = @realize()

  update: =>
    unless (next = @realize()) is @target
      @callback @target = next

  realize: =>
    current = @view.adapters[@root.interface].read @view.models, @root.path

    for token, index in @tokens
      next = @view.adapters[token.interface].read current, token.path

      if @objectPath[index]?
        if next isnt @objectPath[index]
          @view.adapters[token.interface].unsubscribe current, token.path, @update
          @view.adapters[token.interface].subscribe next, token.path, @update
      else
        @view.adapters[token.interface].subscribe current, token.path, @update

      current = next

    current

class KeypathObserver
  constructor: (@view, @model, @keypath, @callback) ->
    @interfaces = (k for k, v of @view.adapters)
    @objectPath = []
    @tokens = Rivets.KeypathParser.parse @keypath, @interfaces, @view.config.rootInterface
    @root = @tokens.shift()
    @key = @tokens.pop()
    @target = @realize()

  update: =>
    unless (next = @realize()) is @target
      @callback @target = next

  realize: =>
    current = @view.adapters[@root.interface].read @view.models, @root.path

    for token, index in @tokens
      if @objectPath[index]?
        if current isnt prev = @objectPath[index]
          @view.adapters[token.interface].unsubscribe prev, token.path, @update
          @view.adapters[token.interface].subscribe current, token.path, @update
          @objectPath[index] = current
      else
        @view.adapters[token.interface].subscribe current, token.path, @update
        @objectPath[index] = current

      current = @view.adapters[token.interface].read current, token.path

    current

Make sure that we properly unsubscribe from any outdated portions of a keypath.


Yossarian.Track = DS.Model.extend
  name: DS.attr 'string'

  recordings: DS.hasMany 'recording'

Add mising relation in Track

Add mising relation in Track


$       = require 'jquery'
globals = require 'globals'

module.exports = shortenUrl = (longUrl, callback) ->

  { apiKey } = globals.config.google

  apiUrl = "https://www.googleapis.com/urlshortener/v1/url?key=#{apiKey}"

  request = $.ajax
    url         : apiUrl
    type        : 'POST'
    contentType : 'application/json'
    data        : JSON.stringify { longUrl }
    dataType    : 'json'
    timeout     : 4000

  request.done (data) ->
    callback data?.id or longUrl, data

  request.error ({ status, statusText, responseText }) ->
    console.error 'URL shortener error', status, statusText, responseText
    callback longUrl

$       = require 'jquery'
globals = require 'globals'

module.exports = shortenUrl = (longUrl, callback) ->

  { apiKey } = globals.config.google

  apiUrl = "https://www.googleapis.com/urlshortener/v1/url?key=#{apiKey}"

  request = $.ajax
    url         : apiUrl
    type        : 'POST'
    contentType : 'application/json'
    data        : JSON.stringify { longUrl }
    dataType    : 'json'
    timeout     : 4000

  request.done (data) ->
    callback data?.id or longUrl, data

  request.fail ({ status, statusText, responseText }) ->
    console.error 'URL shortener error', status, statusText, responseText
    callback longUrl

Fix jQuery promise failure handler API reference

Signed-off-by: Sonmez Kartal <d2d15c3d37396a5f2a09f8b42cf5f27d43a3fbde@koding.com>


React    = require 'react'
BS       = require 'react-bootstrap'
classnames = require 'classnames'
_ = require 'underscore'

module.exports = React.createClass
  displayName: 'Icon'
  propTypes:
    type: React.PropTypes.string.isRequired
    spin: React.PropTypes.bool
    className: React.PropTypes.string
    tooltip: React.PropTypes.oneOf([
      React.PropTypes.string, React.PropTypes.element
    ])
    tooltipProps: React.PropTypes.object
    onNavbar: React.PropTypes.bool

  componentWillMount: ->
    uniqueId = _.uniqueId('icon-tooltip-')
    @setState({uniqueId: uniqueId})

  getDefaultProps: ->
    tooltipProps:
      placement: 'bottom',
      trigger: 'click'

  render: ->
    classNames = classnames('tutor-icon', 'fa', "fa-#{@props.type}", @props.className, {
      'fa-spin': @props.spin
      'clickable': @props.tooltip and @props.tooltipProps.trigger is 'click'
    })

    icon = <i {...@props} className={classNames} />

    if @props.tooltip
      classNames =
      tooltip = <BS.Tooltip id={@state.uniqueId}
        className={classnames({'on-navbar': @props.onNavbar})}
        >{@props.tooltip}</BS.Tooltip>
      <BS.OverlayTrigger {...@props.tooltipProps} overlay={tooltip}>{icon}</BS.OverlayTrigger>
    else
      icon

React    = require 'react'
BS       = require 'react-bootstrap'
classnames = require 'classnames'
_ = require 'underscore'

module.exports = React.createClass
  displayName: 'Icon'
  propTypes:
    type: React.PropTypes.string.isRequired
    spin: React.PropTypes.bool
    className: React.PropTypes.string
    tooltip: React.PropTypes.oneOfType([
      React.PropTypes.string, React.PropTypes.element
    ])
    tooltipProps: React.PropTypes.object
    onNavbar: React.PropTypes.bool

  componentWillMount: ->
    uniqueId = _.uniqueId('icon-tooltip-')
    @setState({uniqueId: uniqueId})

  getDefaultProps: ->
    tooltipProps:
      placement: 'bottom',
      trigger: 'click'

  render: ->
    classNames = classnames('tutor-icon', 'fa', "fa-#{@props.type}", @props.className, {
      'fa-spin': @props.spin
      'clickable': @props.tooltip and @props.tooltipProps.trigger is 'click'
    })

    icon = <i {...@props} className={classNames} />

    if @props.tooltip
      classNames =
      tooltip = <BS.Tooltip id={@state.uniqueId}
        className={classnames({'on-navbar': @props.onNavbar})}
        >{@props.tooltip}</BS.Tooltip>
      <BS.OverlayTrigger {...@props.tooltipProps} overlay={tooltip}>{icon}</BS.OverlayTrigger>
    else
      icon

Fix propType to be correct "oneOfType"

Fix propType to be correct "oneOfType"


@lobbyQueue = new Meteor.Collection "lobbyQueue"

Meteor.startup ->
  lobbyQueue.remove({})

@cancelFindServer = (lobbyId)->
  console.log "canceling server search: "+lobbyId
  lobbyQueue.remove
    lobby: lobbyId

@startFindServer = (lobbyId)->
  console.log "finding server for "+lobbyId
  lobbyQueue.insert
    lobby: lobbyId
    started: new Date().getTime()
  lobbies.update {_id: lobbyId}, {$set: {status: 1}}

Set status to 1 when queuing

Set status to 1 when queuing


ProjectManager = require '../lib/project-manager'
{WorkspaceView} = require 'atom'
fs = require 'fs'

describe "ProjectManager", ->
  activationPromise: null

  describe "Toggle Project Manager", ->
    beforeEach ->
      atom.workspaceView = new WorkspaceView
      activationPromise = atom.packages.activatePackage('project-manager')

    it "Shows the Project Viewer", ->
      expect(atom.workspaceView.find('.project-manager')).not.toExist()
      atom.workspaceView.trigger 'project-manager:toggle'
      expect(atom.workspaceView.find('.project-manager')).toExist()

  describe "Initiating Project Manager", ->
    beforeEach ->
      activationPromise = atom.packages.activatePackage('project-manager')

    it "Makes sure projects.cson exists", ->
      options =
        encoding: 'utf-8'
      fs.readFile ProjectManager.file(), options, (err, data) ->
        expect(err).toBe null

    it "getCurrentPath existential operator issue is fixed", ->
      projects = test: paths: [atom.project.getPath()]
      result = ProjectManager.getCurrentProject projects
      expect(result).not.toBe false
      projects = test: {}
      result = ProjectManager.getCurrentProject projects
      expect(result).toBe false

Add test for getCurrentPath bug

Add test for getCurrentPath bug


msgpack = require 'msgpack'
r = require('redis').createClient detect_buffers: true

r.keys '*', (err, all_keys) ->
  throw err if err
  keys = []
  for key in all_keys
    parts = key.split ':'
    continue if (parts.length == 1) || (parts[0] == 'lock')
    keys.push key
  count = keys.length
  for key in keys
    do (key) ->
      r.get key, (err, val) ->
        throw err if err
        object = JSON.parse val
        buf = msgpack.pack object
        r.set key, buf, (err) ->
          throw err if err
          unless --count
            console.log "Packed #{keys.length} keys"
            r.end()

msgpack = require 'msgpack'
r = require('redis').createClient 6379, 'localhost', detect_buffers: true

r.keys '*', (err, all_keys) ->
  throw err if err
  keys = []
  for key in all_keys
    parts = key.split ':'
    continue if (parts.length == 1) || (parts[0] == 'lock')
    keys.push key
  count = keys.length
  for key in keys
    do (key) ->
      r.get key, (err, val) ->
        throw err if err
        object = JSON.parse val
        buf = msgpack.pack object
        r.set key, buf, (err) ->
          throw err if err
          unless --count
            console.log "Packed #{keys.length} keys"
            r.end()

Fix bug in new script

Fix bug in new script


Config = require '../config'
CustomerXmlImport = require '../lib/customerxmlimport'

# Increase timeout
jasmine.getEnv().defaultTimeoutInterval = 10000

describe 'process', ->
  beforeEach ->
    @import = new CustomerXmlImport Config

  it 'one customer', (done) ->
    rawXml = '
<Customer>
  <CustomerNr>1234</CustomerNr>
  <Street>Foo 1</Street>
  <Group>B2B</Group>
  <Employees>
    <Employee>
      <employeeNr>2</employeeNr>
      <email>some.one+27@example.com</email>
      <gender>Mrs.</gender>
      <firstname>Some</firstname>
      <lastname>One</lastname>
    </Employee>
  </Employees>
</Customer>'
    @import.run rawXml, (msg) =>
      expect(msg.status).toBe false
      expect(msg.message).toBe 'Update of customer isnt implemented yet!'
      done()

_ = require('underscore')._
Config = require '../config'
CustomerXmlImport = require '../lib/customerxmlimport'

# Increase timeout
jasmine.getEnv().defaultTimeoutInterval = 10000

describe 'process', ->
  beforeEach ->
    @import = new CustomerXmlImport Config

  it 'one existing customer', (done) ->
    rawXml = '
<Customer>
  <CustomerNr>1234</CustomerNr>
  <Street>Foo 1</Street>
  <Group>B2B</Group>
  <Employees>
    <Employee>
      <employeeNr>2</employeeNr>
      <email>some.one+27@example.com</email>
      <gender>Mrs.</gender>
      <firstname>Some</firstname>
      <lastname>One</lastname>
    </Employee>
  </Employees>
</Customer>'
    @import.run rawXml, (msg) =>
      expect(msg.status).toBe false
      expect(msg.message).toBe 'Update of customer isnt implemented yet!'
      done()

  it 'one new customer', (done) ->
    unique = new Date().getTime()
    rawXml = "
<Customer>
  <CustomerNr>5678</CustomerNr>
  <Street>Foo 1</Street>
  <Group>B2C</Group>
  <Employees>
    <Employee>
      <employeeNr>1</employeeNr>
      <email>some.one.else+#{unique}@example.com</email>
      <gender>Mrs.</gender>
      <firstname>Some</firstname>
      <lastname>One</lastname>
    </Employee>
  </Employees>
</Customer>"
    @import.run rawXml, (result) =>
      console.log result unless result.status
      expect(result.status).toBe true
      expect(_.size(result.message)).toBe 2
      expect(result.message['Customer has no paymentInfo.']).toBe 1
      expect(result.message['Customer has no group.']).toBe 1
      done()

Add integration test for new customer.

Add integration test for new customer.


counterpart = require 'counterpart'
React = require 'react'
{Markdown} = (require 'markdownz').default

counterpart.registerTranslations 'en',
  glossary:
    content: '''
      ## Glossary
      A collection of definitions for terms used across the Zooniverse. The terms are split into three different groups; [General Terms](#general-terms); [People](#people) and [Project-Specific Terms](#project-specific-terms).

      ###GENERAL TERMS

      ###PEOPLE

      ###PROJECT-SPECIFIC TERMS

    '''

module.exports = React.createClass
  displayName: 'Glossary'

  render: ->

      <Markdown>{counterpart "glossary.content"}</Markdown>

counterpart = require 'counterpart'
React = require 'react'
{Markdown} = (require 'markdownz').default

counterpart.registerTranslations 'en',
  policiesPage:
    content: '''
      ## Glossary
      A collection of definitions for terms used across the Zooniverse. The terms are split into three different groups:

      ## General Terms

      ## People

      ## Project-Specific Terms

    '''

module.exports = React.createClass
  displayName: 'Glossary'

  render: ->
    <div className="secondary-page centered-grid">
      <Markdown>{counterpart "policiesPage.content"}</Markdown>
    </div>

Revert to non TOC markdown

Revert to non TOC markdown


React = require 'react'
BS = require 'react-bootstrap'
Router = require 'react-router'

{CCDashboardStore, CCDashboardActions} = require '../../flux/cc-dashboard'
LoadableItem = require '../loadable-item'
CCDashboard = require './dashboard'

BookLinks = require './book-links'

classnames = require 'classnames'

DashboardShell = React.createClass
  contextTypes:
    router: React.PropTypes.func

  render: ->
    {courseId} = @context.router.getCurrentParams()

      <BookLinks courseId={courseId} />

        Class Performance
        <Router.Link className='btn btn-default pull-right' to='viewScores' params={{courseId}}>
          View Detailed Scores
        </Router.Link>

      <LoadableItem
        store={CCDashboardStore}
        actions={CCDashboardActions}
        id={courseId}
        renderItem={-> <CCDashboard key={courseId} id={courseId} />}
      />

module.exports = DashboardShell

React = require 'react'
BS = require 'react-bootstrap'
Router = require 'react-router'

{CCDashboardStore, CCDashboardActions} = require '../../flux/cc-dashboard'
LoadableItem = require '../loadable-item'
CCDashboard = require './dashboard'

BookLinks = require './book-links'

classnames = require 'classnames'

DashboardShell = React.createClass
  contextTypes:
    router: React.PropTypes.func

  render: ->
    {courseId} = @context.router.getCurrentParams()

      <BookLinks courseId={courseId} />

        Class Dashboard
        <Router.Link className='btn btn-default pull-right' to='viewScores' params={{courseId}}>
          View Detailed Scores
        </Router.Link>

      <LoadableItem
        store={CCDashboardStore}
        actions={CCDashboardActions}
        id={courseId}
        renderItem={-> <CCDashboard key={courseId} id={courseId} />}
      />

module.exports = DashboardShell

Update title to be "Class Dashboard"

Update title to be "Class Dashboard"


#= require vendor/modernizr
#= require jquery
#= require jquery_ujs
#= require foundation/foundation
#= require foundation
#= require rails.validations
#= require rails.validations.simple_form
#= require rails.validations.simple_form.fix
#= require turbolinks
#= require nprogress
#= require nprogress-turbolinks
#= require jquery.autosize
#= require globals/_functions
#= require tools/mapbox
#= require tools/nprogress

$(document).on 'ready page:load page:restore', ->
  $(document).foundation
  $('.autosize').autosize()

#= require vendor/modernizr
#= require jquery
#= require jquery_ujs
#= require foundation/foundation
#= require foundation
#= require turbolinks
#= require nprogress
#= require nprogress-turbolinks
#= require rails.validations
#= require rails.validations.simple_form
#= require rails.validations.simple_form.fix
#= require jquery.autosize
#= require globals/_functions
#= require tools/mapbox
#= require tools/nprogress

$(document).on 'ready page:load page:restore', ->
  $(document).foundation
  $('.autosize').autosize()

Move turbolinks up to make client_side_validations working after ajax request


class IDE.FinderContextMenuController extends NFinderContextMenuController

  getFolderMenu: (fileView) ->

    fileData = fileView.getData()

    items =
      Expand                      :
        action                    : "expand"
        separator                 : yes
      Collapse                    :
        action                    : "collapse"
        separator                 : yes
      'Make this the top folder'  :
        action                    : 'makeTopFolder'
      'Workspace from here'       :
        action                    : 'createWorkspace'
      'Terminal from here'        :
        action                    : 'createTerminal'
        separator                 : yes
      Delete                      :
        action                    : 'delete'
        separator                 : yes
      Rename                      :
        action                    : 'rename'
      Duplicate                   :
        action                    : 'duplicate'
      Compress                    :
        children                  :
          'as .zip'               :
            action                : 'zip'
          'as .tar.gz'            :
            action                : 'tarball'
      'Set permissions'           :
        separator                 : yes
        children                  :
          customView              : new NSetPermissionsView {}, fileData
      'New file'                  :
        action                    : 'createFile'
      'New folder'                :
        action                    : 'createFolder'
      Refresh                     :
        action                    : 'refresh'

    if fileView.expanded
      delete items.Expand
    else
      delete items.Collapse

    return items

class IDE.FinderContextMenuController extends NFinderContextMenuController

  getFolderMenu: (fileView) ->

    fileData = fileView.getData()

    items =
      Expand                      :
        action                    : "expand"
        separator                 : yes
      Collapse                    :
        action                    : "collapse"
        separator                 : yes
      'Change top folder'         :
        separator                 : yes
        children                  : @getTopFolderItems fileView
      'Make this the top folder'  :
        action                    : 'makeTopFolder'
      'Workspace from here'       :
        action                    : 'createWorkspace'
      'Terminal from here'        :
        action                    : 'createTerminal'
        separator                 : yes
      Delete                      :
        action                    : 'delete'
        separator                 : yes
      Rename                      :
        action                    : 'rename'
      Duplicate                   :
        action                    : 'duplicate'
      Compress                    :
        children                  :
          'as .zip'               :
            action                : 'zip'
          'as .tar.gz'            :
            action                : 'tarball'
      'Set permissions'           :
        separator                 : yes
        children                  :
          customView              : new NSetPermissionsView {}, fileData
      'New file'                  :
        action                    : 'createFile'
      'New folder'                :
        action                    : 'createFolder'
      Refresh                     :
        action                    : 'refresh'

    if fileView.expanded
      delete items.Expand
    else
      delete items.Collapse

    return items

Add `Change Top Folder` context menu action


$ ->
  $(".topbar-wrapper").dropdown()
$ ->
  $(".alert-message").alert()
$ ->
  $(".modal").modal
    show: false
    backdrop: "static"

Make modals not hide when clicking on greyed out background


_ = require 'underscore'
guid = require 'guid'

module.exports =
class WsChannel
  _.extend @prototype, require('event-emitter')

  constructor: (@name) ->
    @clientId = guid.create().toString()
    @socket = new WebSocket('ws://localhost:8080')
    @socket.onopen = =>
      @rawSend 'subscribe', @name, @clientId
      @trigger 'channel:opened'

    @socket.onmessage = (message) =>
      [operation, data] = JSON.parse(message.data)
      @trigger(data...)

  send: (data...) ->
    @rawSend('broadcast', data)

  rawSend: (args...) ->
    @socket.send(JSON.stringify(args))

_ = require 'underscore'
guid = require 'guid'
keytar = require 'keytar'

module.exports =
class WsChannel
  _.extend @prototype, require('event-emitter')

  constructor: (@name) ->
    @clientId = guid.create().toString()
    token = keytar.getPassword('github.com', 'github')
    @socket = new WebSocket("ws://localhost:8080?token=#{token}")
    @socket.onopen = =>
      @rawSend 'subscribe', @name, @clientId
      @trigger 'channel:opened'

    @socket.onmessage = (message) =>
      [operation, data] = JSON.parse(message.data)
      @trigger(data...)

  send: (data...) ->
    @rawSend('broadcast', data)

  rawSend: (args...) ->
    @socket.send(JSON.stringify(args))

Send OAuth token as web socket query param


'use strict'

app.directive 'volumeEditLinksForm', [
  'pageService',
  (page) ->
    restrict: 'E',
    templateUrl: 'volume/editLinks.html',
    link: ($scope) ->
      volume = $scope.volume
      form = $scope.volumeEditLinksForm

      form.data = _.map volume.links, (ref) ->
        head: ref.head
        url: ref.url

      blank = () ->
        form.data.push
          head: ''
          url: ''
      blank()

      form.change = () -> blank() unless form.data[form.data.length-1].url == ''

      form.remove = (ref) ->
        ref.removed = true
        ref.head = ''
        ref.url = ''
        form.$setDirty()

      form.save = () ->
        page.messages.clear(form)
        data = _.filter form.data, (ref) -> !ref.removed
        volume.save({links: data}).then(() ->
            form.validator.server {}
            form.data = data.filter (ref) -> ref.head != '' || ref.url != ''
            blank()

            page.messages.add
              type: 'green'
              body: page.constants.message('volume.edit.success')
              owner: form

            form.$setPristine()
          , (res) ->
            form.validator.server res
          )

      return
]

'use strict'

app.directive 'volumeEditLinksForm', [
  'pageService',
  (page) ->
    restrict: 'E',
    templateUrl: 'volume/editLinks.html',
    link: ($scope) ->
      volume = $scope.volume
      form = $scope.volumeEditLinksForm

      form.data = _.map volume.links, (ref) ->
        head: ref.head
        url: ref.url

      blank = () ->
        form.data.push
          head: ''
          url: ''
      blank()

      form.change = () -> blank() unless form.data[form.data.length-1].url == ''

      form.remove = (ref) ->
        ref.removed = true
        ref.head = ''
        ref.url = ''
        form.$setDirty()

      form.save = () ->
        page.messages.clear(form)
        data = _.filter form.data, (ref) -> !ref.removed
        form.$setSubmitted()
        volume.save({links: data}).then(() ->
            form.validator.server {}
            form.data = data.filter (ref) -> ref.head != '' || ref.url != ''
            blank()

            page.messages.add
              type: 'green'
              body: page.constants.message('volume.edit.success')
              owner: form

            form.$setPristine()
            form.$setUnsubmitted()
          , (res) ->
            form.validator.server res
          )

      return
]

Add a submitted/unsubmitted thing to editing links.


React = require 'react'
BS = require 'react-bootstrap'
Router = require 'react-router'
_ = require 'underscore'

LearningGuide  = require '../../flux/learning-guide'
PracticeButton = require './practice-button'
WeakerSections = require './weaker-sections'

WeakerPanel = React.createClass
  propTypes:
    courseId:            React.PropTypes.string.isRequired
    sections:            React.PropTypes.array.isRequired
    weakerTitle:         React.PropTypes.string.isRequired
    weakerExplanation:   React.PropTypes.element.isRequired
    weakerEmptyMessage:  React.PropTypes.string.isRequired
    onPractice:          React.PropTypes.func
    sectionCount:        React.PropTypes.number
    sampleSizeThreshold: React.PropTypes.number.isRequired

  render: ->
    # Do not render if we have no sections
    return null if @props.sections.length is 0

        {@props.weakerTitle}
        {@props.weakerExplanation}
        {if LearningGuide.Helpers.canDisplayWeakest(@props) # hide practice button when the panel is empty
          <PracticeButton title='Practice All'
            sections=LearningGuide.Helpers.weakestSections(@props.sections)
            courseId={@props.courseId} /> }

      <WeakerSections {...@props} />

module.exports = WeakerPanel

React = require 'react'
BS = require 'react-bootstrap'
Router = require 'react-router'
_ = require 'underscore'

LearningGuide  = require '../../flux/learning-guide'
PracticeButton = require './practice-button'
WeakerSections = require './weaker-sections'

WeakerPanel = React.createClass
  propTypes:
    courseId:            React.PropTypes.string.isRequired
    sections:            React.PropTypes.array.isRequired
    weakerTitle:         React.PropTypes.string.isRequired
    weakerExplanation:   React.PropTypes.element.isRequired
    weakerEmptyMessage:  React.PropTypes.string.isRequired
    onPractice:          React.PropTypes.func
    sectionCount:        React.PropTypes.number
    sampleSizeThreshold: React.PropTypes.number.isRequired

  render: ->
    # Do not render if we have no sections
    return null if @props.sections.length is 0

        {@props.weakerTitle}
        {@props.weakerExplanation}
        {if @props.onPractice and LearningGuide.Helpers.canDisplayWeakest(@props)
          <PracticeButton title='Practice All'
            sections=LearningGuide.Helpers.weakestSections(@props.sections)
            courseId={@props.courseId} /> }

      <WeakerSections {...@props} />

module.exports = WeakerPanel

Hide practice button if practice handler isn't provided

Even though the PracticeButton doesn't use the onPractice callback, it's
a good way to determine if practicing sections is allowed.  The prop is
only given for the Student component, not Teacher or TeacherStudent.


try
  keytar = require 'keytar'
catch error
  # Gracefully handle keytar failing to load due to missing library on Linux
  if process.platform is 'linux'
    keytar =
      findPassword: ->
      replacePassword: ->
  else
    throw error

tokenName = 'Atom.io API Token'

module.exports =
  # Get the Atom.io API token from the keychain.
  #
  # callback - A function to call with an error as the first argument and a
  #            string token as the second argument.
  getToken: (callback) ->
    if token = process.env.ATOM_ACCESS_TOKEN
      callback(null, token)
      return

    if token = keytar.findPassword(tokenName)
      callback(null, token)
      return

    callback """
      No Atom.io API token in keychain
      Run `apm login` or set the `ATOM_ACCESS_TOKEN` environment variable.
    """

  # Save the given token to the keychain.
  #
  # token - A string token to save.
  saveToken: (token) ->
    keytar.replacePassword(tokenName, 'atom.io', token)

try
  keytar = require 'keytar'
catch error
  # Gracefully handle keytar failing to load due to missing library on Linux
  if process.platform is 'linux'
    keytar =
      findPassword: ->
      replacePassword: ->
  else
    throw error

tokenName = 'Atom.io API Token'

module.exports =
  # Get the Atom.io API token from the keychain.
  #
  # callback - A function to call with an error as the first argument and a
  #            string token as the second argument.
  getToken: (callback) ->
    if token = keytar.findPassword(tokenName)
      callback(null, token)
      return

    if token = process.env.ATOM_ACCESS_TOKEN
      callback(null, token)
      return

    callback """
      No Atom.io API token in keychain
      Run `apm login` or set the `ATOM_ACCESS_TOKEN` environment variable.
    """

  # Save the given token to the keychain.
  #
  # token - A string token to save.
  saveToken: (token) ->
    keytar.replacePassword(tokenName, 'atom.io', token)

Check the keychain for the token before falling back to ATOM_ACCESS_TOKEN.

Otherwise auth failures get confusing: we’d keep updating the token
stored in the keychain when the real problem was that ATOM_ACCESS_TOKEN
was out of date. See #505.


"use strict"

module.exports =
  title: 'Hytteadmin'
  version: '2.0.0-alpha'
  desc: 'Administrasjon av hytter i Nasjonal Turbase'
  author: 'Hans Kristian Flaatten, Den Norske Turistforening'
  copyright: '© Den Norske Turistforening'

"use strict"

module.exports =
  title: 'Sherpa'
  version: '2.0.0-alpha'
  desc: 'Administrasjon av hytter i Nasjonal Turbase'
  author: 'Hans Kristian Flaatten, Den Norske Turistforening'
  copyright: '© Den Norske Turistforening'

Change site tile to Sherpa

Change site tile to Sherpa


{cloneFragment} = Trix

Trix.registerElement "trix-toolbar",
  defaultCSS: """
    %t {
      white-space: collapse;
    }

    %t .dialog {
      display: none;
    }

    %t .dialog.active {
      display: block;
    }

    %t .dialog input.validate:invalid {
      background-color: #ffdddd;
    }

    %t[native] {
      display: none;
    }
  """

  attachedCallback: ->
    if @innerHTML is ""
      @appendChild(cloneFragment(Trix.config.toolbar.content))

{cloneFragment} = Trix

Trix.registerElement "trix-toolbar",
  defaultCSS: """
    %t {
      white-space: collapse;
    }

    %t .dialog {
      display: none;
    }

    %t .dialog.active {
      display: block;
    }

    %t .dialog input.validate:invalid {
      background-color: #ffdddd;
    }

    %t[native] {
      display: none;
    }
  """

  createdCallback: ->
    if @innerHTML is ""
      @appendChild(cloneFragment(Trix.config.toolbar.content))

Add default content when created to avoid extra DOM manipulation when attached


'menu': [
  {
    'label': 'View'
    'submenu': [
      {
        'label': 'Toggle Git Panel'
        'command': 'github:toggle-git-panel'
      }
    ]
  }
  {
    'label': 'Packages'
    'submenu': [
      {
        'label': 'GitHub',
        'submenu': [
          {
            'label': 'Toggle'
            'command': 'github:toggle-git-panel'
          }
        ]
      }
    ]
  }
]
'context-menu':
  '.github-FilePatchListView-item': [
    {
      'label': 'Open File'
      'command': 'github:open-file'
    }
  ]
  '.github-UnstagedChanges': [
    {
      'label': 'Discard Changes'
      'command': 'github:discard-changes'
    }
  ]
  '.github-FilePatchView': [
    {
      'label': 'Open File'
      'command': 'github:open-file'
    }
  ]

'menu': [
  {
    'label': 'View'
    'submenu': [
      {
        'label': 'Toggle Git Panel'
        'command': 'github:toggle-git-panel'
      }
    ]
  }
  {
    'label': 'Packages'
    'submenu': [
      {
        'label': 'GitHub',
        'submenu': [
          {
            'label': 'Toggle'
            'command': 'github:toggle-git-panel'
          }
        ]
      }
    ]
  }
]
'context-menu':
  '.github-FilePatchListView-item': [
    {
      'label': 'Open File'
      'command': 'github:open-file'
    }
  ]
  '.github-UnstagedChanges': [
    {
      'label': 'Discard Changes'
      'command': 'github:discard-changes'
    }
    {
      'label': 'Stage'
      'command': 'core:confirm'
    }
  ]
  '.github-StagedChanges': [
    {
      'label': 'Unstage'
      'command': 'core:confirm'
    }
  ]
  '.github-MergeConflictPaths': [
    {
      'label': 'Stage'
      'command': 'core:confirm'
    }
  ]
  '.github-FilePatchView': [
    {
      'label': 'Open File'
      'command': 'github:open-file'
    }
  ]

Add context menu items for staging and unstaging in changed files list


_       = require 'lodash'
kd      = require 'kd'
remote  = require('app/remote').getInstance()
globals = require 'globals'

defaults = require './tracking/defaults'

module.exports = class Tracker

  _.assign this, require('./tracking/trackingtypes')

  @track = (action, properties = {}) ->

    return  unless globals.config.logToExternal

    @assignDefaultProperties action, properties
    remote.api.Tracker.track action, properties, kd.noop

  @assignDefaultProperties: (action, properties) ->

    _.defaults properties, defaults.properties[action]

_       = require 'lodash'
kd      = require 'kd'
remote  = require('app/remote').getInstance()
globals = require 'globals'

defaults = require './tracking/defaults'

module.exports = class Tracker

  _.assign this, require('./tracking/trackingtypes')

  @track = (action, properties = {}) ->

    return  unless globals.config.sendEventsToSegment

    @assignDefaultProperties action, properties
    remote.api.Tracker.track action, properties, kd.noop

  @assignDefaultProperties: (action, properties) ->

    _.defaults properties, defaults.properties[action]

Fix condition clause of Tracker.track function


{CompositeDisposable} = require 'atom'

module.exports =
  config:
    executablePath:
      type: 'string'
      title: 'PHP Executable Path'
      default: 'php' # Let OS's $PATH handle the rest

  activate: ->
    @regex = '(Parse|Fatal) ' +
            '(?<error>error):(\\s*(?<type>parse|syntax) error,?)?\\s*' +
            '(?<message>(unexpected \'(?<near>[^\']+)\')?.*) ' +
            'in .*? on line (?<line>\\d+)'
    @subscriptions = new CompositeDisposable
    @subscriptions.add atom.config.observe 'linter-php.executablePath',
      (executablePath) =>
        @executablePath = executablePath

  deactivate: ->
    @subscriptions.dispose()

  provideLinter: ->
    helpers = require('atom-linter')
    provider =
      grammarScopes: ['text.html.php', 'source.php']
      scope: 'file'
      lintOnFly: false
      lint: (textEditor) =>
        filePath = textEditor.getPath()
        command = @executablePath
        parameters = []
        parameters.push('--syntax-check')
        parameters.push('--no-php-ini')
        parameters.push('--define', 'display_errors=On')
        parameters.push('--define', 'log_errors=Off')
        parameters.push('--file', filePath)
        return helpers.exec(command, parameters).then (output) =>
          messages = helpers.parse(output, @regex, {filePath: filePath})
          return messages

{CompositeDisposable} = require 'atom'

module.exports =
  config:
    executablePath:
      type: 'string'
      title: 'PHP Executable Path'
      default: 'php' # Let OS's $PATH handle the rest

  activate: ->
    @regex = '(Parse|Fatal) ' +
            '(?<error>error):(\\s*(?<type>parse|syntax) error,?)?\\s*' +
            '(?<message>(unexpected \'(?<near>[^\']+)\')?.*) ' +
            'in .*? on line (?<line>\\d+)'
    @subscriptions = new CompositeDisposable
    @subscriptions.add atom.config.observe 'linter-php.executablePath',
      (executablePath) =>
        @executablePath = executablePath

  deactivate: ->
    @subscriptions.dispose()

  provideLinter: ->
    helpers = require('atom-linter')
    provider =
      grammarScopes: ['text.html.php', 'source.php']
      scope: 'file'
      lintOnFly: true
      lint: (textEditor) =>
        filePath = textEditor.getPath()
        command = @executablePath
        parameters = []
        parameters.push('--syntax-check')
        parameters.push('--no-php-ini')
        parameters.push('--define', 'display_errors=On')
        parameters.push('--define', 'log_errors=Off')
        text = textEditor.getText()
        return helpers.exec(command, parameters, {stdin: text}).then (output) =>
          messages = helpers.parse(output, @regex, {filePath: filePath})
          return messages

Enable linting on the fly

Enable linting on the fly

Note that this represents a slight loss of functionality. With the
update to the new API the file was explicitly specified, which according
to the documentation enables checking for "fatal errors (like undefined
functions)".

Since we are linting on the fly we can't specify a file and thus lose
this functionality.


# Graph-stuff-code
# Generalised way to send an ajax request to load a chart when a
# link is clicked with data-load="graph"

$('body.coders.show, body.repositories.show').ready ->
    $('a[data-load="graph"]').on 'shown.bs.tab', (e) ->
        if !$("#chart").hasClass('google-visualization-atl container')
            $.ajax
                url: $(this).data('graphurl') + '.js'
                type: 'GET'

# Graph-stuff-code
# Generalised way to send an ajax request to load a chart when a
# link is clicked with data-load="graph"

$('body.coders.show, body.repositories.show').ready ->
    $('a[data-load="graph"]').on 'shown.bs.tab', (e) ->
        # Only initialise the chart the first time we click the tab
        # Google_visualr adds those classes when it is initialised so it's safe to
        # filter on those classes
        if !$("#chart").hasClass('google-visualization-atl container')
            $.ajax
                url: $(this).data('graphurl') + '.js'
                type: 'GET'

Add documentation for the if

Add documentation for the if


$ ->
  # $('#rows').on "change", ->
  #   $rows = $(this).val()
  #   console.log $rows

  # $('#columns').on "change", ->
  #   $columns = $(this).val()
  #   console.log $columns

  $('#submit_details').click (e) ->
    e.preventDefault()
    $rows = parseInt($('#rows').val(), 10)
    $columns = parseInt($('#columns').val(), 10)
    layout = ''
    for $rows in [$rows-1..0] by -1
      row = '
'
      layout += row
      layout += Array($columns + 1).join(seatTemplate())
      layout += '
'

    $('#layout').html(layout)

  $('#layout').on 'click', '.seat', (e) ->

    if parseInt($(this).children().val() == 1)
      $(this).children().val(0)
    else
      console.log 'test'
      $(this).children().val(1)

    unless $(this).hasClass('alley')
      $(this).addClass('alley')
    else
      $(this).removeClass('alley')

  seatTemplate = () ->
    '
<input type="hidden" value=1 class="seat_type" />
'

$ ->
  # $('#rows').on "change", ->
  #   $rows = $(this).val()
  #   console.log $rows

  # $('#columns').on "change", ->
  #   $columns = $(this).val()
  #   console.log $columns

  $('#submit_details').click (e) ->
    e.preventDefault()
    $rows = parseInt($('#rows').val(), 10)
    $columns = parseInt($('#columns').val(), 10)
    layout = ''
    for $rows in [$rows-1..0] by -1
      row = '
'
      layout += row
      layout += Array($columns + 1).join(seatTemplate())
      layout += '
'

    $('#layout').html(layout)

  $('#layout').on 'click', '.seat', (e) ->

    # if parseInt($(this).children().val() == 1)
    #   $(this).children().val(0)
    # else
    #   console.log 'test'
    #   $(this).children().val(1)

    unless $(this).hasClass('alley')
      $(this).addClass('alley')
      $(this).children().val(0)
    else
      $(this).removeClass('alley')
      $(this).children().val(1)

  seatTemplate = () ->
    '
<input type="hidden" value=1 class="seat_type" />
'

Create alleys in hall creation

Create alleys in hall creation


class Workbench.Views.SensorMapView extends Backbone.Marionette.ItemView
  template: false

  initialize: ->
    @zoom = 13

  onDestroy: ->
    @map.remove() if @map

  onShow: ->
    if @el.id is ""
      console.warn "No Map Element"
    else
      @location = [@model.get("latitude"), @model.get("longitude")]
      @map = L.map(@el.id, {
        continuousWorld: true
        center: Workbench.provider.center
        minZoom: Workbench.provider.zoomRange.min
        maxZoom: Workbench.provider.zoomRange.max
        crs: Workbench.provider.CRS
      })

      L.tileLayer(Workbench.provider.url, {
          attribution: Workbench.provider.attribution
      }).addTo(@map)

      @map.setView(@location, @zoom)

      L.marker(@location).addTo(@map)

class Workbench.Views.SensorMapView extends Backbone.Marionette.ItemView
  template: false

  initialize: ->
    @zoom = 13

  onDestroy: ->
    @map.remove() if @map

  onShow: ->
    if @el.id is ""
      console.warn "No Map Element"
    else
      @location = [@model.get("latitude"), @model.get("longitude")]
      pMap = polarMap(@el.id, { permalink: false })
      @map = pMap.map
      @map.setView(@location, @zoom)

      L.marker(@location).addTo(@map)

Use PolarMap on sensor page

Use PolarMap on sensor page


class window.SearchCollection extends Backbone.Collection
  constructor: (args...)->
    super(args...)
    @searchFor ''

  emptyState: -> []

  searchFor: (query) ->
    query = $.trim(query)
    return if query == @query
    @query = query
    @_search()

  throttle = (method) -> _.throttle method, 300
  _search: throttle ->
    @jqxhr?.abort()
    if @query == ''
      @reset @emptyState()
      @trigger 'sync'
    else
      @reset []
      @jqxhr = @fetch()

  encodedQuery: -> encodeURIComponent @query

  addNewItem: (compare_field) ->
    return unless @shouldShowNewItem(compare_field)

    @add @getNewItem()
    @trigger 'sync'

  shouldShowNewItem: (compare_field) ->
    @query != '' and not (@query.toLowerCase() in @newItemFields(compare_field))

  newItemFields: (compare_field) -> _.map @pluck(compare_field), (field)-> field.toLowerCase()

  getNewItem: -> console.error "'getNewItem' was not implemented"

class window.SearchCollection extends Backbone.Collection
  constructor: (args...)->
    super(args...)
    @searchFor ''

  emptyState: -> []

  searchFor: (query) ->
    query = $.trim(query)
    return if query == @query
    @query = query
    @_search()

  throttle = (method) -> _.throttle method, 300
  _search: throttle ->
    @jqxhr?.abort()
    if @query == ''
      @reset @emptyState()
      @trigger 'sync'
    else
      @reset []
      @jqxhr = @fetch(reset: true) # because the CollectionUtils do a full reset on add/remove

  encodedQuery: -> encodeURIComponent @query

  addNewItem: (compare_field) ->
    return unless @shouldShowNewItem(compare_field)

    @add @getNewItem()
    @trigger 'sync'

  shouldShowNewItem: (compare_field) ->
    @query != '' and not (@query.toLowerCase() in @newItemFields(compare_field))

  newItemFields: (compare_field) -> _.map @pluck(compare_field), (field)-> field.toLowerCase()

  getNewItem: -> console.error "'getNewItem' was not implemented"

Use reset for better performance

Use reset for better performance


{Document} = require 'telepath'

# Public: Manages the deserializers used for serialized state
module.exports =
class DeserializerManager
  constructor: ->
    @deserializers = {}
    @deferredDeserializers = {}

  # Public: Add a deserializer.
  add: (klasses...) ->
    @deserializers[klass.name] = klass for klass in klasses

  # Public: Add a deferred deserializer.
  addDeferred: (name, fn) ->
    @deferredDeserializers[name] = fn

  # Public: Remove a deserializer.
  remove: (klasses...) ->
    delete @deserializers[klass.name] for klass in klasses

  # Public: Deserialize the state and params.
  deserialize: (state, params) ->
    return unless state?

    if deserializer = @getDeserializer(state)
      stateVersion = state.get?('version') ? state.version
      return if deserializer.version? and deserializer.version isnt stateVersion
      if (state instanceof Document) and not deserializer.acceptsDocuments
        state = state.toObject()
      deserializer.deserialize(state, params)
    else
      console.warn "No deserializer found for", state

  # Public: Get the deserializer for the state.
  get: (state) ->
    return unless state?

    name = state.get?('deserializer') ? state.deserializer
    if @deferredDeserializers[name]
      @deferredDeserializers[name]()
      delete @deferredDeserializers[name]

    @deserializers[name]

{Document} = require 'telepath'

# Public: Manages the deserializers used for serialized state
module.exports =
class DeserializerManager
  constructor: ->
    @deserializers = {}
    @deferredDeserializers = {}

  # Public: Add a deserializer.
  add: (klasses...) ->
    @deserializers[klass.name] = klass for klass in klasses

  # Public: Add a deferred deserializer.
  addDeferred: (name, fn) ->
    @deferredDeserializers[name] = fn

  # Public: Remove a deserializer.
  remove: (klasses...) ->
    delete @deserializers[klass.name] for klass in klasses

  # Public: Deserialize the state and params.
  deserialize: (state, params) ->
    return unless state?

    if deserializer = @get(state)
      stateVersion = state.get?('version') ? state.version
      return if deserializer.version? and deserializer.version isnt stateVersion
      if (state instanceof Document) and not deserializer.acceptsDocuments
        state = state.toObject()
      deserializer.deserialize(state, params)
    else
      console.warn "No deserializer found for", state

  # Public: Get the deserializer for the state.
  get: (state) ->
    return unless state?

    name = state.get?('deserializer') ? state.deserializer
    if @deferredDeserializers[name]
      @deferredDeserializers[name]()
      delete @deferredDeserializers[name]

    @deserializers[name]

Call get instead of getDeserializer

Call get instead of getDeserializer


# 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://jashkenas.github.com/coffee-script/

$ ->
	$('select[data-reveal-section]').change(->
		section = $("##{$(@).val() + $(@).attr('data-reveal-section')}")

		if section
			$('.hide-unless-selected').hide()
			section.find(':input').removeAttr('disabled')
			section.show()
	).trigger('change')

Add javascript to show section if an option with a matching value is selected


# Newer view to manage Question form.
class ELMO.Views.QuestionFormView extends ELMO.Views.FormView
  initialize: (options) ->
    @toggleFields()

  # We use $= because the start of the ID can vary depending on whether
  # it's a question form or questioning form.
  # Note, these events must be redefined in any child classes.
  events:
    'change select[id$="_qtype_name"]': 'toggleFields'
    'change select[id$="_metadata_type"]': 'toggleFields'

  toggleFields: ->
    @showField('auto_increment', @showAutoIncrement())
    @showField('metadata_type', @showMetaDataType())

  showAutoIncrement: ->
    @fieldValue('qtype_name') == 'counter'

  showMetaDataType: ->
    @fieldValue('qtype_name') == 'datetime'

  metadataTypeBlank: ->
    !@showMetaDataType() || @fieldValue('metadata_type') == ''

  # Gets form field value, or static value if field is read-only
  fieldValue: (attrib) ->
    div = @$(".form-field[data-field-name=#{attrib}] .control")
    if div.is('.read-only')
      wrapper = div.find('.ro-val')
      wrapper.data('val') || wrapper.text()
    else
      # Rails checkbox fields have a hidden field followed by a checkbox. We need to ignore the hidden.
      field = div.find('input[type!=hidden], select, textarea')
      if field.attr('type') == 'checkbox'
        field.is(':checked')
      else
        field.val()

# Newer view to manage Question form.
class ELMO.Views.QuestionFormView extends ELMO.Views.FormView
  initialize: (options) ->
    @toggleFields()

  # We use $= because the start of the ID can vary depending on whether
  # it's a question form or questioning form.
  # Note, these events must be redefined in any child classes.
  events:
    'change select[id$="_qtype_name"]': 'toggleFields'
    'change select[id$="_metadata_type"]': 'toggleFields'

  toggleFields: ->
    @showField('auto_increment', @showAutoIncrement())
    @showField('metadata_type', @showMetaDataType())

  showAutoIncrement: ->
    @fieldValue('qtype_name') == 'counter'

  showMetaDataType: ->
    @fieldValue('qtype_name') == 'datetime'

  metadataTypeBlank: ->
    !@showMetaDataType() || @fieldValue('metadata_type') == ''

  # Gets form field value, or static value if field is read-only
  fieldValue: (attrib) ->
    div = @$(".form-field[data-field-name=#{attrib}] .control")
    if div.is('.read-only')
      wrapper = div.find('.ro-val')
      if typeof wrapper.data('val') != 'undefined' then wrapper.data('val') else wrapper.text()
    else
      # Rails checkbox fields have a hidden field followed by a checkbox. We need to ignore the hidden.
      field = div.find('input[type!=hidden], select, textarea')
      if field.attr('type') == 'checkbox'
        field.is(':checked')
      else
        field.val()

10139: Fix bug with read-only view of questioning form


{BufferedProcess} = require 'atom'
StatusView = require './status-view'

# if all param true, then 'git add .'
gitAdd = (all=false)->
  dir = atom.project.getRepo().getWorkingDirectory()
  currentFile = atom.workspace.getActiveEditor().getPath()
  toStage = if all then '.' else currentFile
  new BufferedProcess({
    command: 'git'
    args: ['add', '--all', toStage]
    options:
      cwd: dir
    stderr: (data) ->
      new StatusView(type: 'alert', message: data.toString())
    exit: (data) ->
      file = if toStage is '.' then 'all files' else prettify(dir, toStage)
      new StatusView(type: 'success', message: "Added #{file}")
  })

# only show filepaths inside the project
prettify = (dir, file) ->
  i = dir.lastIndexOf('/')
  root = dir.slice(i + 1)
  path = file.slice(i + root.length + 2)

module.exports = gitAdd

{BufferedProcess} = require 'atom'
StatusView = require './status-view'

# if all param true, then 'git add .'
gitAdd = (all=false)->
  dir = atom.project.getRepo().getWorkingDirectory()
  currentFile = atom.workspace.getActiveEditor()?.getPath()
  toStage = if all then '.' else currentFile
  if (toStage?)
    new BufferedProcess({
      command: 'git'
      args: ['add', '--all', toStage]
      options:
        cwd: dir
      stderr: (data) ->
        new StatusView(type: 'alert', message: data.toString())
      exit: (data) ->
        file = if toStage is '.' then 'all files' else prettify(dir, toStage)
        new StatusView(type: 'success', message: "Added #{file}")
    })
  else
    new StatusView(type: 'alert', message: "I don't know which file(s) to add!")

# only show filepaths inside the project
prettify = (dir, file) ->
  i = dir.lastIndexOf('/')
  root = dir.slice(i + 1)
  path = file.slice(i + root.length + 2)

module.exports = gitAdd

Fix "Git Plus: Add (all)" without open editor

In the context, it would give a type error because
`atom.workspace.getActiveEditor()` was `undefined`.


path = require 'path'
fs = require 'fs-plus'
optimist = require 'optimist'
Highlights = require './highlights'

module.exports = ->
  cli = optimist.describe('help', 'Show this message').alias('h', 'help')
                .describe('scope', 'Scope name of grammar to use').alias('s', 'scopeName')
  optimist.usage """
    Usage: highlights file

    Output the syntax highlighted HTML for a file.

    If no file is specified then the text of highlight is read from standard in.
  """

  if cli.argv.help
    cli.showHelp()
    return

  [filePath] = cli.argv._
  if filePath
    filePath = path.resolve(filePath)
    unless fs.isFileSync(filePath)
      console.error("Specified path is not a file: #{filePath}")
      process.exit(1)
      return

    html = new Highlights().highlightSync({filePath, scopeName: cli.argv.scope})
    console.log(html)
  else
    process.stdin.resume()
    process.stdin.setEncoding('utf8')
    fileContents = ''
    process.stdin.on 'data', (chunk) -> fileContents += chunk.toString()
    process.stdin.on 'end', ->
      html = new Highlights().highlightSync({fileContents, scopeName: cli.argv.scope})
      console.log(html)

path = require 'path'
fs = require 'fs-plus'
optimist = require 'optimist'
Highlights = require './highlights'

module.exports = ->
  cli = optimist.describe('help', 'Show this message').alias('h', 'help')
                .describe('scope', 'Scope name of the grammar to use').alias('s', 'scopeName')
  optimist.usage """
    Usage: highlights file

    Output the syntax highlighted HTML for a file.

    If no file is specified then the text of highlight is read from standard in.
  """

  if cli.argv.help
    cli.showHelp()
    return

  [filePath] = cli.argv._
  if filePath
    filePath = path.resolve(filePath)
    unless fs.isFileSync(filePath)
      console.error("Specified path is not a file: #{filePath}")
      process.exit(1)
      return

    html = new Highlights().highlightSync({filePath, scopeName: cli.argv.scope})
    console.log(html)
  else
    process.stdin.resume()
    process.stdin.setEncoding('utf8')
    fileContents = ''
    process.stdin.on 'data', (chunk) -> fileContents += chunk.toString()
    process.stdin.on 'end', ->
      html = new Highlights().highlightSync({fileContents, scopeName: cli.argv.scope})
      console.log(html)

Add the to arg doc

Add the to arg doc


# Description:
#   A simple interaction with the built in HTTP Daemon
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   None
#
# URLS:
#   /hubot/version
#   /hubot/ping
#   /hubot/time
#   /hubot/info

spawn = require('child_process').spawn

module.exports = (robot) ->

  robot.router.get "/hubot/version", (req, res) ->
    res.end robot.version

  robot.router.post "/hubot/ping", (req, res) ->
    res.end "PONG"

  robot.router.get "/hubot/time", (req, res) ->
    res.end "Server time is: #{new Date()}"

  robot.router.get "/hubot/info", (req, res) ->
    child = spawn('/bin/sh', ['-c', "echo I\\'m $LOGNAME@$(hostname):$(pwd) \\($(git rev-parse HEAD)\\)"])

    child.stdout.on 'data', (data) ->
      res.end "#{data.toString().trim()} running node #{process.version} [pid: #{process.pid}]"
      child.stdin.end()

# Description:
#   A simple interaction with the built in HTTP Daemon
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   None
#
# URLS:
#   /hubot/version
#   /hubot/ping
#   /hubot/time
#   /hubot/info
#   /hubot/ip

spawn = require('child_process').spawn

module.exports = (robot) ->

  robot.router.get "/hubot/version", (req, res) ->
    res.end robot.version

  robot.router.post "/hubot/ping", (req, res) ->
    res.end "PONG"

  robot.router.get "/hubot/time", (req, res) ->
    res.end "Server time is: #{new Date()}"

  robot.router.get "/hubot/info", (req, res) ->
    child = spawn('/bin/sh', ['-c', "echo I\\'m $LOGNAME@$(hostname):$(pwd) \\($(git rev-parse HEAD)\\)"])

    child.stdout.on 'data', (data) ->
      res.end "#{data.toString().trim()} running node #{process.version} [pid: #{process.pid}]"
      child.stdin.end()

  robot.router.get "/hubot/ip", (req, res) ->
    robot.http('http://checkip.dyndns.org').get() (err, r, body) ->
      res.end body

Add route for knowing the IP where the bot is host


# Public: An object that aggregates multiple {Disposable} instances together
# into a single disposable, so they can all be disposed as a group.
module.exports =
class CompositeDisposable
  disposed: false

  constructor: ->
    @disposables = []

  # Public: Add a disposable to be disposed when the composite is disposed.
  #
  # If this object has already been disposed, this method has no effect.
  #
  # * `disposable` {Disposable} instance or any object with a `.dispose()`
  #   method.
  add: (disposable) ->
    unless @disposed
      @disposables.push(disposable)

  # Public: Remove a previously added disposable.
  #
  # * `disposable` {Disposable} instance or any object with a `.dispose()`
  #   method.
  remove: (disposable) ->
    index = @disposables.indexOf(disposable)
    @disposables.splice(index, 1) if index isnt -1

  # Public: Dispose all disposables added to this composite disposable.
  #
  # If this object has already been disposed, this method has no effect.
  dispose: ->
    unless @disposed
      @disposed = true
      disposable.dispose() for disposable in @disposables
      @clear()

  # Public: Clear all disposables. They will not be disposed by the next call
  # to dispose.
  clear: ->
    @disposables.length = 0

# Public: An object that aggregates multiple {Disposable} instances together
# into a single disposable, so they can all be disposed as a group.
module.exports =
class CompositeDisposable
  disposed: false

  # Public: Construct an instance, optionally with one or more
  constructor: ->
    @disposables = []
    @add(disposable) for disposable in arguments

  # Public: Add a disposable to be disposed when the composite is disposed.
  #
  # If this object has already been disposed, this method has no effect.
  #
  # * `disposable` {Disposable} instance or any object with a `.dispose()`
  #   method.
  add: (disposable) ->
    unless @disposed
      @disposables.push(disposable)

  # Public: Remove a previously added disposable.
  #
  # * `disposable` {Disposable} instance or any object with a `.dispose()`
  #   method.
  remove: (disposable) ->
    index = @disposables.indexOf(disposable)
    @disposables.splice(index, 1) if index isnt -1

  # Public: Dispose all disposables added to this composite disposable.
  #
  # If this object has already been disposed, this method has no effect.
  dispose: ->
    unless @disposed
      @disposed = true
      disposable.dispose() for disposable in @disposables
      @clear()

  # Public: Clear all disposables. They will not be disposed by the next call
  # to dispose.
  clear: ->
    @disposables.length = 0

Allow CompositeDisposable to be constructed with multiple disposables


Opener = require '../opener'

module.exports =
class AtomPdfOpener extends Opener
  open: (filePath, texPath, lineNumber, callback) ->
    # Opens PDF in a new pane -- requires pdf-view module
    openPanes = atom.workspace.getPaneItems()
    for pane in openPanes
      if pane.filePath is filePath
        # File is already open in another pane
        return
    pane = atom.workspace.getActivePane()
    newPane = pane.split('horizontal', 'after')
    atom.workspace.openURIInPane(filePath, newPane)

Opener = require '../opener'

module.exports =
class AtomPdfOpener extends Opener
  open: (filePath, texPath, lineNumber, callback) ->
    # Opens PDF in a new pane -- requires pdf-view module
    openPanes = atom.workspace.getPaneItems()
    for pane in openPanes
      # File is already open in another pane
      return if pane.filePath is filePath
    pane = atom.workspace.getActivePane()
    newPane = pane.split('horizontal', 'after') # TODO: Make this configurable?
    atom.workspace.openURIInPane(filePath, newPane)

Compress block, and add TODO comment

:art: Compress block, and add TODO comment


Helpers = require('./helpers')
{CompositeDisposable, Emitter} = require 'atom'

class MessageRegistry
  constructor: (@linter)->
    @messages = new Map()
    @emitter = new Emitter
    @subscriptions = new CompositeDisposable
    @subscriptions.add atom.workspace.onDidChangeActivePaneItem =>
      @messages.forEach (messages) => @classifyMessages(messages)
      @emitter.emit 'did-classify'

  set: (linter, messages) ->
    Helpers.validateMessages(messages)
    @classifyMessages(messages)
    @messages.set(linter, messages)
    @emitter.emit 'did-classify'
    @emitter.emit 'did-change', @messages

  delete: (linter) ->
    @messages.delete(linter)
    @emitter.emit 'did-change', @messages

  get: ->
    return @messages

  onDidChange: (callback) ->
    return @emitter.on 'did-change', callback

  onDidClassify: (callback) ->
    return @emitter.on 'did-classify', callback

  classifyMessages: (messages)->
    isProject = @linter.state.scope is 'Project'
    activeFile = atom.workspace.getActiveTextEditor()?.getPath()
    messages.forEach (message) =>
      if (not message.filePath and not isProject) or message.filePath is activeFile
        message.currentFile = true
      else
        message.currentFile = false

  destroy: ->
    @messages.clear()
    @subscriptions.dispose()
    @emitter.dispose()

module.exports = MessageRegistry

Helpers = require('./helpers')
{Emitter} = require 'atom'

class MessageRegistry
  constructor: (@linter)->
    @messages = new Map()
    @emitter = new Emitter

  set: (linter, messages) ->
    Helpers.validateMessages(messages)
    @classifyMessages(messages)
    @messages.set(linter, messages)
    @emitter.emit 'did-change', @messages

  delete: (linter) ->
    @messages.delete(linter)
    @emitter.emit 'did-change', @messages

  get: ->
    return @messages

  onDidChange: (callback) ->
    return @emitter.on 'did-change', callback

  classifyMessages: (messages)->
    isProject = @linter.state.scope is 'Project'
    activeFile = atom.workspace.getActiveTextEditor()?.getPath()
    messages.forEach (message) =>
      if (not message.filePath and not isProject) or message.filePath is activeFile
        message.currentFile = true
      else
        message.currentFile = false

  destroy: ->
    @messages.clear()
    @emitter.dispose()

module.exports = MessageRegistry

:fire: Remove all the subs from MessageRegistry


RocketChat.models._Base = class
	_baseName: ->
		return 'rocketchat_'

	_initModel: (name) ->
		check name, String

		@model = new Mongo.Collection @_baseName() + name

	find: ->
		return @model.find.apply @model, arguments

	findOne: ->
		return @model.findOne.apply @model, arguments

	insert: ->
		return @model.insert.apply @model, arguments

	update: ->
		return @model.update.apply @model, arguments

	upsert: ->
		return @model.upsert.apply @model, arguments

	remove: ->
		return @model.remove.apply @model, arguments

	allow: ->
		return @model.allow.apply @model, arguments

	deny: ->
		return @model.deny.apply @model, arguments

	ensureIndex: ->
		return @model._ensureIndex.apply @model, arguments

	dropIndex: ->
		return @model._dropIndex.apply @model, arguments

	tryEnsureIndex: ->
		try
			return @ensureIndex.apply @, arguments
		catch e
			console.log e

	tryDropIndex: ->
		try
			return @dropIndex.apply @, arguments
		catch e
			console.log e

RocketChat.models._Base = class
	_baseName: ->
		return 'rocketchat_'

	_initModel: (name) ->
		check name, String

		@model = new Mongo.Collection @_baseName() + name

	find: ->
		return @model.find.apply @model, arguments

	findOne: ->
		return @model.findOne.apply @model, arguments

	insert: ->
		return @model.insert.apply @model, arguments

	insertOrUpsert: (args...) ->
		if args[0]?._id?
			_id = args[0]._id
			delete args[0]._id
			args.unshift
				_id: _id
			@model.upsert.apply @model, args
			return _id
		else
			return @model.insert.apply @model, args

	update: ->
		return @model.update.apply @model, arguments

	upsert: ->
		return @model.upsert.apply @model, arguments

	remove: ->
		return @model.remove.apply @model, arguments

	allow: ->
		return @model.allow.apply @model, arguments

	deny: ->
		return @model.deny.apply @model, arguments

	ensureIndex: ->
		return @model._ensureIndex.apply @model, arguments

	dropIndex: ->
		return @model._dropIndex.apply @model, arguments

	tryEnsureIndex: ->
		try
			return @ensureIndex.apply @, arguments
		catch e
			console.log e

	tryDropIndex: ->
		try
			return @dropIndex.apply @, arguments
		catch e
			console.log e

Create new model method insertOrUpsert based on _id


require 'appirio-tech-ng-ui-components'
require 'appirio-tech-ng-api-services'
require './scripts/ap-file-upload.module'

require './scripts/file.controller'
require './scripts/file.directive'
require './scripts/file.service'
require './scripts/on-file-changed.directive'
require './scripts/uploaded-files.directive'
require './scripts/uploader.controller'
require './scripts/uploader.directive'
require './scripts/uploader.service'

requireContextFiles = (files) ->
  paths = files.keys()

  for path in paths
    files path

styles      = require.context './styles/', true, /^(.*\.(scss$))[^.]*$/igm

requireContextFiles styles

views     = require.context './views/', true, /^(.*\.(jade$))[^.]*$/igm
viewPaths = views.keys()

templateCache = ($templateCache) ->
  for viewPath in viewPaths
    viewPathClean = viewPath.split('./').pop()

    # TODD: bug if .jade occurs more often than once
    viewPathCleanHtml = viewPathClean.replace '.jade', '.html'

    $templateCache.put "views/#{viewPathCleanHtml}", views(viewPath)()

templateCache.$inject = ['$templateCache']

angular.module('ap-file-upload').run templateCache

Remove requires to prep for consolidation into work-app


#= require "vendor/jquery-1.7.1.min"

#= require "vendor/plugins/jquery.fittext.js"

Add fittext to asset pipeline

Add fittext to asset pipeline


setTimeout ->

  if /^(interactive|complete)$/.test(document.readyState)
    FactlinkJailRoot.host_ready_promise.resolve()
  else
    document.addEventListener('DOMContentLoaded', -> FactlinkJailRoot.host_ready_promise.resolve())

  if 'complete' == document.readyState
    FactlinkJailRoot.host_loaded_promise.resolve()
  else
    window.addEventListener('load', -> FactlinkJailRoot.host_loaded_promise.resolve())
, 0

setTimeout ->
  ok =
    loaded: true
    interactive: !(document.documentMode < 11)
    complete: true

  if ok[document.readyState]
    FactlinkJailRoot.host_ready_promise.resolve()
  else
    document.addEventListener('DOMContentLoaded', -> FactlinkJailRoot.host_ready_promise.resolve())

  if 'complete' == document.readyState
    FactlinkJailRoot.host_loaded_promise.resolve()
  else
    window.addEventListener('load', ->
      FactlinkJailRoot.host_ready_promise.resolve()
      #IE pre 11's readyStates are weird; to ensure we can't miss anything,
      #trigger ready at the latest on load
      FactlinkJailRoot.host_loaded_promise.resolve()
    )
, 0

Fix IE 9/10 host_ready event

Fix IE 9/10 host_ready event


deps = ['angular', './routes', 'angular-route', 'angular-ui', 'angular-ui-select2',
        './filters', './services', './directives', './controllers']

modules = [
  'ngRoute',
  'steps.controllers',
  'steps.services',
  'steps.filters',
  'steps.directives',
  'ui.bootstrap',
  'ui.select2']

$providers = [
  '$routeProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide'
]

define deps, (angular, router) ->
  Steps = angular.module('steps', modules)

  # Capture references to providers.
  Steps.config Array $providers..., (routes, controllers, directives, filters, provide) ->
    Steps.routes = routes
    Steps.controllers = controllers
    Steps.directives = directives
    Steps.filters = filters
    Steps.provide = provide

  router Steps

  return Steps

deps = ['angular', './routes', 'angular-route', 'angular-ui', 'angular-ui-select2',
        './filters', './services', './directives', './controllers']

modules = [
  'ngRoute',
  'steps.controllers',
  'steps.services',
  'steps.filters',
  'steps.directives',
  'ui.bootstrap',
  'ui.select2']

$providers = [
  '$routeProvider', '$controllerProvider', '$compileProvider',
  '$filterProvider', '$provide', '$sceDelegateProvider'
]

define deps, (angular, router) ->
  Steps = angular.module('steps', modules)

  # Capture references to providers.
  Steps.config Array $providers..., (routes, controllers, directives, filters, provide, sceDelegateProvider) ->
    Steps.routes = routes
    Steps.controllers = controllers
    Steps.directives = directives
    Steps.filters = filters
    Steps.provide = provide
    sceDelegateProvider.resourceUrlWhitelist([
      'self', # TODO: make configurable.
      'http://*.labs.intermine.org/**'
    ])

  router Steps

  return Steps

Allow loading iframe tools from labs.intermine.


wait = ->
  $.getJSON(window.location.pathname + '/wait', ->
    $.get window.location.pathname + '.js', (html)->
      $('#book').html html
      initMathJax()
      wait()
  ).fail -> wait()

initMathJax = ->
  $('#mathJaxJS').remove()
  delete MathJax

  script = document.createElement( 'script' )
  script.id = 'mathJaxJS'
  script.type = 'text/javascript'
  script.src = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js' +
               '?config=TeX-AMS_HTML'
  script.innerHTML = '
      MathJax.Hub.Config({
        "HTML-CSS": {
          availableFonts: ["TeX"],
        },
        showProcessingMessages: false,
        messageStyle: "none"
      });
    '

  $('head').append script

$ ->
  initMathJax()
  wait()

wait = ->
  $.getJSON(window.location.pathname + '/wait', ->
    $.get window.location.pathname + '.js', (html)->
      $('#book').html html
      initMathJax()
      wait()
  ).fail -> wait()

initMathJax = ->
  $('#mathJaxJS').remove()
  delete MathJax

  chapter_number = $('.chapter').attr('data-number')
  script = document.createElement( 'script' )
  script.id = 'mathJaxJS'
  script.type = 'text/javascript'
  script.src = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js' +
               '?config=TeX-AMS_HTML'
  script.innerHTML = '
      MathJax.Hub.Config({
        "HTML-CSS": {
          availableFonts: ["TeX"],
        },
        TeX: {
          extensions: ["AMSmath.js", "AMSsymbols.js"],
          equationNumbers: {
            autoNumber: "AMS",
            formatNumber: function (n) { return "#{chapter_number}." + n }
          },
        },
        showProcessingMessages: false,
        messageStyle: "none"
      });
    '

  $('head').append script

$ ->
  initMathJax()
  wait()

Add formatNumber using current chapter number

[Delivers #50579297]


"*":
  "exception-reporting":
    userId: "30e6f2d0-42d3-ab77-4984-dde4c431f019"
  welcome:
    showOnStartup: false
  core:
    projectHome: "/Users/randy/src"
    audioBeep: false
    excludeVcsIgnoredPaths: false
  editor:
    invisibles: {}
    fontFamily: "Hack"
    showIndentGuide: true
  autosave:
    enabled: true
  "git-diff":
    showIconsInEditorGutter: true
  "ruby-test":
    testFramework: "minitest"
    rspecAllCommand: "vagrant ssh -c \"rspec --tty spec\""
    rspecFileCommand: "vagrant ssh -c \"rspec --tty {relative_path}\""
    rspecSingleCommand: "vagrant ssh -c \"rspec --tty {relative_path}:{line_number}\""
  "git-blame": {}

"*":
  "exception-reporting":
    userId: "30e6f2d0-42d3-ab77-4984-dde4c431f019"
  welcome:
    showOnStartup: false
  core:
    projectHome: "/Users/randy/src"
    audioBeep: false
    excludeVcsIgnoredPaths: false
  editor:
    invisibles: {}
    fontFamily: "Hack"
    showIndentGuide: true
    fontSize: 15
  autosave:
    enabled: true
  "git-diff":
    showIconsInEditorGutter: true
  "ruby-test":
    testFramework: "minitest"
    rspecAllCommand: "vagrant ssh -c \"rspec --tty spec\""
    rspecFileCommand: "vagrant ssh -c \"rspec --tty {relative_path}\""
    rspecSingleCommand: "vagrant ssh -c \"rspec --tty {relative_path}:{line_number}\""
  "git-blame": {}

Increase default font size a bit

Increase default font size a bit


assert  = require 'assert'
request = require 'supertest'

resolve = require('path').resolve

req = request require '../../src/server'
base = ''

describe '/', ->
  it 'should not return much', (done) ->
    req.get "#{base}/"
      .expect 204
      .end done

describe '/upload', ->
  url = "#{base}/upload"

  it 'should upload single landscape image to s3', (done) ->
    @timeout 30000
    req.post url
      .attach 'files[]', resolve __dirname, '../assets/IMG_5836.jpg'
      .expect 201
      .expect (res) ->
        assert.deepEqual res.body[0].meta.imageSize, { width: 5184, height: 3456 }
        assert.equal res.body[0].versions.length, 3
      .end done

  it 'should upload single horizontal image to s3', (done) ->
    @timeout 30000
    req.post url
      .attach 'files[]', resolve __dirname, '../assets/IMG_5299.jpg'
      .expect 201
      .expect (res) ->
        assert.deepEqual res.body[0].meta.imageSize, { width: 5184, height: 3456 }
        assert.equal res.body[0].versions.length, 3
      .end done

assert  = require 'assert'
request = require 'supertest'

resolve = require('path').resolve

req = request require '../../src/server'
base = ''

describe '/', ->
  it 'should not return much', (done) ->
    req.get "#{base}/"
      .expect 204
      .end done

describe '/upload', ->
  url = "#{base}/upload"

  it 'should upload single landscape image to s3', (done) ->
    @timeout 30000
    req.post url
      .attach 'files[]', resolve __dirname, '../assets/IMG_5836.jpg'
      .expect 201
      .expect (res) ->
        assert.deepEqual res.body[0].meta.imageSize, { width: 5184, height: 3456 }
        assert.equal res.body[0].versions.length, 3
      .end done

  it 'should upload single horizontal image to s3', (done) ->
    @timeout 30000
    req.post url
      .attach 'files[]', resolve __dirname, '../assets/IMG_5299.jpg'
      .expect 201
      .expect (res) ->
        assert.deepEqual res.body[0].meta.imageSize, { width: 3264, height: 2448 }
        assert.equal res.body[0].versions.length, 3
      .end done

Fix metadata assert for failing test case


Wheelmap.FlashMessageView = Ember.View.extend
  template: Ember.Handlebars.compile('{{ view.content.message }}')
  classNameBindings: [':flash', 'content.type', ':fade', 'fadeIn:in']
  fadeIn: false

  didInsertElement: ()->
    Ember.run.next @, 'toggleProperty', 'fadeIn'
    Ember.run.later @, 'toggleProperty', 'fadeIn', @get('delay')

  transitionEnd: (event)->
    # @TODO Use event informations instead?
    unless @get('fadeIn')
      @get('controller').send('removed', @get('content'))

  delay: (()->
    @get('content.message').split(' ').compact().length / 0.00333333333 # based on 200 WpM
  ).property('content.message')

Wheelmap.FlashMessagesView = Ember.CollectionView.extend
  classNames: ['flash-wrapper']
  contentBinding: 'controller'
  itemViewClass: 'flash-message'

Wheelmap.FlashMessageView = Ember.View.extend
  template: Ember.Handlebars.compile('{{ view.content.message }}')
  classNameBindings: [':flash', 'content.type', ':fade', 'fadeIn:in']
  fadeIn: false

  didInsertElement: ()->
    Ember.run.next @, 'toggleProperty', 'fadeIn'
    Ember.run.later @, 'toggleProperty', 'fadeIn', @get('delay')

  transitionEnd: (event)->
    # @TODO Use event informations instead?
    unless @get('fadeIn')
      @get('controller').send('removed', @get('content'))

  delay: (()->
    @get('content.message').split(' ').compact().length / 0.001 # based on 200 WpM
  ).property('content.message')

Wheelmap.FlashMessagesView = Ember.CollectionView.extend
  classNames: ['flash-wrapper']
  contentBinding: 'controller'
  itemViewClass: 'flash-message'

Fix reading time for flash messages.

Fix reading time for flash messages.


class @FlexibilityOrder
  constructor: (@element) ->
    @lastGood = null

  url: (path) ->
    "#{ App.scenario.url_path() }/flexibility_order/#{ path }"

  update: (sortable) =>
    options = sortable.toArray()

    $.ajax
      url: @url('set'),
      type: 'POST',
      data:
        flexibility_order:
          order: options
      success: =>
        App.call_api()
        @lastGood = options
      error: (e,f) =>
        if @lastGood
          sortable.sort(@lastGood)

  render: =>
    $.ajax
      url: @url('get')
      type: 'GET'
      success: (data) =>
        Sortable.create @element,
          ghostClass: 'ghost'
          animation: 150
          store:
            get: (_sortable) =>
              @lastGood = data.order
              data.order

            set: (sortable) =>
              @update(sortable)

class @FlexibilityOrder
  constructor: (@element) ->
    @lastGood = null

  url: ->
    "#{App.scenario.url_path()}/flexibility_order"

  update: (sortable) =>
    options = sortable.toArray()

    $.ajax
      url: @url(),
      type: 'POST',
      data:
        flexibility_order:
          order: options
      success: =>
        App.call_api()
        @lastGood = options
      error: (e,f) =>
        if @lastGood
          sortable.sort(@lastGood)

  render: =>
    $.ajax
      url: @url()
      type: 'GET'
      success: (data) =>
        Sortable.create @element,
          ghostClass: 'ghost'
          animation: 150
          store:
            get: (_sortable) =>
              @lastGood = data.order
              data.order

            set: (sortable) =>
              @update(sortable)

Update FlexibilityOrder to use new ETEngine API


React = require 'react'
talkClient = require 'panoptes-client/lib/talk-client'
PromiseRenderer = require '../../components/promise-renderer'
SingleSubmitButton = require '../../components/single-submit-button'

DEFAULT_BOARD_TITLE = 'Notes'            # Name of board to put subject comments
DEFAULT_BOARD_DESCRIPTION = 'General comment threads about individual subjects'

module.exports = React.createClass
  displayName: 'CreateSubjectDefaultButton'

  propTypes:
    section: React.PropTypes.string
    onCreateBoard: React.PropTypes.func # passed (board) on create

  defaultBoardPromise: ->
    talkClient
      .type('boards')
      .get({section: @props.section, subject_default: true})
      .index(0)

  createSubjectDefaultBoard: ->
    board =
      title: DEFAULT_BOARD_TITLE,
      description: DEFAULT_BOARD_DESCRIPTION
      subject_default: true,
      permissions: {read: 'all', write: 'all'}
      section: @props.section

    talkClient.type('boards').create(board).save()
      .then => @props.onCreateBoard?(board)

  render: ->
    <PromiseRenderer promise={@defaultBoardPromise()}>{(defaultBoard) =>
      if defaultBoard?
        <div>
          <i className="fa fa-check" /> Subject Default Board Setup
        </div>
      else
        <SingleSubmitButton type="button" onClick={@createSubjectDefaultBoard}>
          <i className="fa fa-photo" /> Activate Talk Subject Comments Board
        </SingleSubmitButton>
    }</PromiseRenderer>

React = require 'react'
talkClient = require 'panoptes-client/lib/talk-client'
SingleSubmitButton = require '../../components/single-submit-button'

DEFAULT_BOARD_TITLE = 'Notes'            # Name of board to put subject comments
DEFAULT_BOARD_DESCRIPTION = 'General comment threads about individual subjects'

module.exports = React.createClass
  displayName: 'CreateSubjectDefaultButton'

  propTypes:
    section: React.PropTypes.string
    onCreateBoard: React.PropTypes.func # passed (board) on create

  getInitialState: ->
    defaultBoard: null

  componentWillMount: ->
    @getDefaultBoard @props.section

  componentWillReceiveProps: (newProps) ->
    @getDefaultBoard newProps.section if newProps.section isnt @props.section

  getDefaultBoard: (section) ->
    talkClient
      .type 'boards'
      .get
        section: section
        subject_default: true
      .index 0
      .then (defaultBoard) =>
        @setState {defaultBoard}

  createSubjectDefaultBoard: ->
    board =
      title: DEFAULT_BOARD_TITLE,
      description: DEFAULT_BOARD_DESCRIPTION
      subject_default: true,
      permissions: {read: 'all', write: 'all'}
      section: @props.section

    talkClient.type('boards').create(board).save()
      .then => @props.onCreateBoard?(board)

  render: ->
    if @state.defaultBoard?
      <div>
        <i className="fa fa-check" /> Subject Default Board Setup
      </div>
    else
      <SingleSubmitButton type="button" onClick={@createSubjectDefaultBoard}>
        <i className="fa fa-photo" /> Activate Talk Subject Comments Board
      </SingleSubmitButton>

Remove PromiseRenderer from subject default button


'use strict'

class Pocket
  constructor: ->
    element = document.createElement 'div'
    element.classList.add 'pocket'
    element.innerText = 'Pocket'
    document.body.appendChild element

pocket = new Pocket()

'use strict'

class Pocket

  State:
    OPEN: 'open'
    CLOSE: 'close'
  state: null

  constructor: ->
    @state = @State.CLOSE

    element = document.createElement 'div'
    element.classList.add 'pocket'
    element.innerText = 'Pocket'

    element.addEventListener 'mouseover', @onMouseOver.bind(@)
    element.addEventListener 'mouseleave', @onMouseLeave.bind(@)

    document.body.appendChild element

  onMouseOver: ->
    @state = @State.OPEN

  onMouseLeave: ->
    @state = @State.CLOSE

pocket = new Pocket()

Add open and close states by mouse over and leave


# @Compiler-Output "../Dist/ExceptedWrite.js"

EventEmitter = require('events').EventEmitter
Promise = require('a-promise')
Buffer = require('buffer').Buffer

class ExpectedWrite extends EventEmitter
  constructor: (@stream) ->
    super
    @status = true
    @expected = null
    @callback = null
    @data = stdout: '', stderr: ''

    @stream.on 'close', =>
      @emit('end')
    if @stream.stdout
      @stream.stdout.on 'data', (data) =>
        @data.stdout += data
    else
      @stream.on 'data', (data) =>
        @data.stdout += data
    @stream.stderr.on 'data', (data) =>
      @data.stderr += data

  onEnd: ->
    return new Promise (Resolve)=>
      if @status
        @once('end', Resolve)
      else
        Resolve()

module.exports = ExpectedWrite

# @Compiler-Output "../Dist/ExceptedWrite.js"

EventEmitter = require('events').EventEmitter
Promise = require('a-promise')
Buffer = require('buffer').Buffer

class ExpectedWrite extends EventEmitter
  constructor: (@stream) ->
    super
    @status = true
    @expected = null
    @expectedStream = 'both' # enum{ stdout, stderr, both }
    @callback = null
    @data = stdout: '', stderr: ''

    @stream.on 'close', =>
      @emit('end', @data)
    if @stream.stdout
      @stream.stdout.on 'data', (data) =>
        @data.stdout += data
        @validateExpected()
    else
      @stream.on 'data', (data) =>
        @data.stdout += data
        @validateExpected()
    @stream.stderr.on 'data', (data) =>
      @data.stderr += data
      @validateExpected()

  # Internal
  validateExpected: ->
    return unless @expected
    return unless @callback
    valid = false
    if @expectedStream isnt 'stderr'
      if @data.stdout.indexOf(@expected) isnt -1 then valid = 'stdout'
    if @expectedStream isnt 'stdout' and not valid
      if @data.stderr.indexOf(@expected) isnt -1 then valid = 'stderr'
    return unless valid
    content = @data[valid]
    callback = @callback
    @data = stdout: '', stderr: ''
    @callback = null
    @expected = null
    @expectedStream = 'both'
    callback({Content: content, E: @})

  expect: (toExpect) ->
    return new Promise (Resolve) =>
      @expected = toExpect
      @callback = Resolve
      @validateExpected()

  write: (Content)->
    if @stream.stdin
      @stream.stdin.write Content
    else
      @stream.write Content

  end: ->
    if @stream.kill
      @stream.kill()
    else
      @stream.close()
    @onEnd()

  onEnd: ->
    return new Promise (Resolve) =>
      if @status
        @once('end', Resolve)
      else
        Resolve(@data)

module.exports = ExpectedWrite

Implement expect, write and end

:new: Implement expect, write and end


Spine = require('spine')

class Dashboard extends Spine.Controller
  constructor: ->
    super
    @render()

  tools: []

  channels: []

  count: 0

  render: =>
    @html require('views/dashboard')() if @el.html

  addTool: (tool) ->
    @tools.push tool
    @channels.push tool.channel

  createTool: (className) ->
    @count += 1
    @append "

"
    @addTool new className({el: "##{@count}"})

module.exports = Dashboard

Fix class name problem with divs

Fix class name problem with divs


# Your keymap
#
# Atom keymaps work similarly to stylesheets. Just as stylesheets use selectors
# to apply styles to elements, Atom keymaps use selectors to associate
# keystrokes with events in specific contexts.
#
# You can create a new keybinding in this file by typing "key" and then hitting
# tab.
#
# Here's an example taken from Atom's built-in keymap:
#
# '.editor':
#   'enter': 'editor:newline'
#
# '.workspace':
#   'ctrl-P': 'core:move-up'
#   'ctrl-p': 'core:move-down'
#
'atom-text-editor[data-grammar="text xml"]:not([mini])':
  'tab': 'emmet:expand-abbreviation-with-tab'

'atom-text-editor[data-grammar="text xml"]:not([mini])':
  'tab': 'emmet:expand-abbreviation-with-tab'

'.platform-darwin':
  'cmd-p': 'command-palette:toggle'

Use cmd-p to toggle command-palette

Use cmd-p to toggle command-palette


if Meteor.isClient
  if Package.ui
    Handlebars = Package.ui.Handlebars

  Handlebars.registerHelper 't9n', (x, prefix='') ->
    T9n.get(x, prefix)

class T9n

  @get: (x, prefix='') ->
    _get(x, prefix)

  @map: (language, map) ->
    if not i18n.map[language]
      i18n.map[language] = {}
    _extend(i18n.map[language], map)
    i18n.dep.changed()

  _get = (x, prefix='') ->
    prefix = (if prefix then prefix + '.' else '')
#    console.log "_get: " + (i18n prefix + _killDots x)
    (i18n prefix + _killDots x) || x

  _killDots = (x) ->
    x.replace(/\./g, '')

  _extend = (dest, from) ->
    props = Object.getOwnPropertyNames(from)
    props.forEach (name) ->
      if (typeof from[name]) is 'object'
        if (typeof dest[name]) is 'undefined'
          dest[name] = {}
        _extend(dest[name],from[name])
      else
        destination = Object.getOwnPropertyDescriptor(from, name)
        Object.defineProperty(dest, name, destination)

@T9n = T9n

if Meteor.isClient
  if Package.ui
    Handlebars = Package.ui.Handlebars

  Handlebars.registerHelper 't9n', (x, prefix='') ->
    T9n.get(x, prefix)

class T9n

  @get: (x, prefix='') ->
    _get(x, prefix)

  @map: (language, map) ->
    if not i18n.map[language]
      i18n.map[language] = {}
    _extend(i18n.map[language], map)
    #i18n.dep.changed()

  _get = (x, prefix='') ->
    prefix = (if prefix then prefix + '.' else '')
#    console.log "_get: " + (i18n prefix + _killDots x)
    (i18n prefix + _killDots x) || x

  _killDots = (x) ->
    x.replace(/\./g, '')

  _extend = (dest, from) ->
    props = Object.getOwnPropertyNames(from)
    props.forEach (name) ->
      if (typeof from[name]) is 'object'
        if (typeof dest[name]) is 'undefined'
          dest[name] = {}
        _extend(dest[name],from[name])
      else
        destination = Object.getOwnPropertyDescriptor(from, name)
        Object.defineProperty(dest, name, destination)

@T9n = T9n

Comment out, still not working

Comment out, still not working


{Subscriber} = require 'emissary'

module.exports =
class Whitespace
  Subscriber.includeInto(this)

  constructor: ->
    atom.workspace.eachEditor (editor) =>
      @handleEditorEvents(editor)

  destroy: ->
    @unsubscribe()

  handleEditorEvents: (editor) ->
    @subscribe editor, 'will-be-saved', =>
      editor.transact =>
        if atom.config.get('whitespace.removeTrailingWhitespace')
          @removeTrailingWhitespace(editor)

        if atom.config.get('whitespace.ensureSingleTrailingNewline')
          @ensureSingleTrailingNewline(editor)

    @subscribe editor, 'destroyed', =>
      @unsubscribe(editor)

  removeTrailingWhitespace: (editor) ->
    editor.getBuffer().scan /[ \t]+$/g, ({lineText, match, replace}) ->
      if editor.getGrammar().scopeName is 'source.gfm'
        # GitHub Flavored Markdown permits two spaces at the end of a line
        [whitespace] = match
        replace('') unless whitespace is '  ' and whitespace isnt lineText
      else
        replace('')

  ensureSingleTrailingNewline: (editor) ->
    buffer = editor.getBuffer()
    if buffer.getLastLine() is ''
      row = buffer.getLastRow() - 1
      buffer.deleteRow(row--) while row and buffer.lineForRow(row) is ''
    else
      selectedBufferRanges = editor.getSelectedBufferRanges()
      buffer.append('\n')
      editor.setSelectedBufferRanges(selectedBufferRanges)

{Subscriber} = require 'emissary'

module.exports =
class Whitespace
  Subscriber.includeInto(this)

  constructor: ->
    atom.workspace.eachEditor (editor) =>
      @handleEditorEvents(editor)

  destroy: ->
    @unsubscribe()

  handleEditorEvents: (editor) ->
    @subscribe editor, 'will-be-saved', =>
      editor.transact =>
        if atom.config.get('whitespace.removeTrailingWhitespace')
          @removeTrailingWhitespace(editor)

        if atom.config.get('whitespace.ensureSingleTrailingNewline')
          @ensureSingleTrailingNewline(editor)

    @subscribe editor, 'destroyed', =>
      @unsubscribe(editor)

  removeTrailingWhitespace: (editor) ->
    editor.getBuffer().scan /[ \t]+$/g, ({lineText, match, replace}) ->
      if editor.getGrammar().scopeName is 'source.gfm'
        # GitHub Flavored Markdown permits two spaces at the end of a line
        [whitespace] = match
        replace('') unless whitespace is '  ' and whitespace isnt lineText
      else
        replace('')

  ensureSingleTrailingNewline: (editor) ->
    lastRow = editor.getLastBufferRow()
    lastLine = editor.lineForBufferRow(lastRow)
    if lastLine is ''
      row = lastRow - 1
      while row and editor.lineForBufferRow(row) is ''
        editor.deleteBufferRow(row--)
    else
      selectedBufferRanges = editor.getSelectedBufferRanges()
      editor.appendText('\n')
      editor.setSelectedBufferRanges(selectedBufferRanges)

Remove need for buffer in `ensureSingleTrailingNewline`


module.exports = (grunt) ->
  grunt.initConfig
    nodewebkit:
      options:
        build_dir: './builds'
        version: '0.8.4'
        mac_icns: './src/assets/icon.icns'
        mac: true
        win: true
        linux32: true
        linux64: true
      src: [ './src/**/*' ]

  grunt.loadNpmTasks 'grunt-node-webkit-builder'
  grunt.registerTask 'default', ['nodewebkit']

module.exports = (grunt) ->
  grunt.initConfig
    nodewebkit:
      options:
        build_dir: './builds'
        version: '0.9.2'
        mac_icns: './src/assets/icon.icns'
        mac: true
        win: true
        linux32: true
        linux64: true
      src: [ './src/**/*' ]

  grunt.loadNpmTasks 'grunt-node-webkit-builder'
  grunt.registerTask 'default', ['nodewebkit']

Update node-webkit version to 0.9.2

Update node-webkit version to 0.9.2


App.FoundationExtras =

  initialize: ->
    $(document).foundation()
    $(window).trigger "load.zf.sticky"
    $(window).trigger "resize"

    clearSticky = ->
      $("[data-sticky]").foundation("destroy") if $("[data-sticky]").length

    $(document).on("page:before-unload", clearSticky)

    window.addEventListener("popstate", clearSticky, false)

Reset sticky component before clicking back button on browser


root = exports ? this

ShowHideCheckboxesModule =

  expandOnLoad: ->
    $('input.show-hide-checkbox:checkbox').each ->
      if $(this).is(':checked')
        $('#' + $(this).data('section') + '-only').toggle('hide')

  bindToCheckboxes: ->
    $('input.show-hide-checkbox:checkbox').on 'change', ->
      $('#' + $(this).data('section') + '-only').toggle('hide')

  setup: ->
    ShowHideCheckboxesModule.bindToCheckboxes()
    ShowHideCheckboxesModule.expandOnLoad()

root.ShowHideCheckboxesModule = ShowHideCheckboxesModule

jQuery ->
  ShowHideCheckboxesModule.setup()

root = exports ? this

ShowHideCheckboxesModule =

  expandOnLoad: ->
    $('input.show-hide-checkbox:checkbox').each ->
      $(this).parents('label').toggleClass('selected', $(this).is(':checked'));
      if $(this).is(':checked')
        $('#' + $(this).data('section') + '-only').toggle('hide')

  bindToCheckboxes: ->
    $('input.show-hide-checkbox:checkbox').on 'change', ->
      $('#' + $(this).data('section') + '-only').toggle('hide')

    $('input[type=checkbox]').on 'change', ->
      $(this).parents('label').toggleClass('selected', $(this).is(':checked'));

  setup: ->
    ShowHideCheckboxesModule.bindToCheckboxes()
    ShowHideCheckboxesModule.expandOnLoad()

root.ShowHideCheckboxesModule = ShowHideCheckboxesModule

jQuery ->
  ShowHideCheckboxesModule.setup()

Add selected to checkbox labels

Add selected to checkbox labels


class TourStepBox extends Backbone.Marionette.ItemView
  className: 'white-well tour-block'

  events:
    'click .next-step': 'next'

  next: ->
    next_button = @$el.find('.next-step')

    if next_button and next_button.data('disable-with')
      next_button.addClass('disabled').text(next_button.data('disable-with'))
    @trigger('next')

class window.AddChannelsTourStep1 extends TourStepBox
  template: 'tour/add_channel_step1'

class window.AddChannelsTourStep2 extends TourStepBox
  template: 'tour/add_channel_step2'
  templateHelpers: ->
    topics: Factlink.Global.t.topics.capitalize()
    channels: Factlink.Global.t.channels.capitalize()

class window.AddChannelsTourStep3 extends TourStepBox
  template: 'tour/add_channel_step3'

class TourStepBox extends Backbone.Marionette.ItemView
  className: 'white-well tour-block'

  events:
    'click .next-step': 'next'

  next: ->
    next_button = @$el.find('.next-step')

    if next_button and next_button.data('disable-with')
      next_button.addClass('disabled').text(next_button.data('disable-with'))
    @trigger('next')

class window.AddChannelsTourStep1 extends TourStepBox
  template: 'tour/add_channel_step1'

class window.AddChannelsTourStep2 extends TourStepBox
  template: 'tour/add_channel_step2'

class window.AddChannelsTourStep3 extends TourStepBox
  template: 'tour/add_channel_step3'

Revert "Added template helpers for capitalized translation"

This reverts commit 7837b49e1fc34efa2071cbd331cedc58b1bbfa32.