enemies = null
enemyList = []

class EnemyManager

  maxEnemies: 15
  spawnFrequency: 3 #seconds

  constructor: ->
    @enemiesOnScreen = 0
    enemies = game.add.group()
    enemies.enableBody = true

    game.time.events.loop(Phaser.Timer.SECOND * @spawnFrequency, @spawnWrapper, this)

  spawn: (x, y) ->
    @enemiesOnScreen++
    enemy = new Enemy(x, y)
    enemies.add(enemy.ref)
    enemyList.push(enemy)

  spawnWrapper: ->
    if @enemiesOnScreen < @maxEnemies
      x = Math.floor(Math.random()*(player.ref.x + 300) + player.ref.x - 300)
      while Math.abs(player.ref.x - x) <= 175
        x = Math.floor(Math.random()*(player.ref.x + 300) + player.ref.x - 300)
      y = Math.floor(Math.random()*(GameWorld.groundHeight-1000) + GameWorld.groundHeight-100)
      new Explosion(x-32, y-50, 0xffffff, player.scale, 5)
      @spawn(x, y)

enemies = null
enemyList = []

class EnemyManager

  maxEnemies: 15

  constructor: ->
    @enemiesOnScreen = 0
    enemies = game.add.group()
    enemies.enableBody = true

    switch currentLevel
      when 'one'   then @spawnFrequency = 4 #seconds
      when 'two'   then @spawnFrequency = 3 #seconds
      when 'three' then @spawnFrequency = 2 #seconds
      when 'four'  then @spawnFrequency = 1 #second

    game.time.events.loop(Phaser.Timer.SECOND * @spawnFrequency, @spawnWrapper, this)

  spawn: (x, y) ->
    @enemiesOnScreen++
    enemy = new Enemy(x, y)
    enemies.add(enemy.ref)
    enemyList.push(enemy)

  spawnWrapper: ->
    if @enemiesOnScreen < @maxEnemies
      x = Math.floor(Math.random()*(player.ref.x + 300) + player.ref.x - 300)
      while Math.abs(player.ref.x - x) <= 175
        x = Math.floor(Math.random()*(player.ref.x + 300) + player.ref.x - 300)
      y = Math.floor(Math.random()*(GameWorld.groundHeight-1000) + GameWorld.groundHeight-100)
      new Explosion(x-32, y-50, 0xffffff, player.scale, 5)
      @spawn(x, y)

Add varying enemy spawn frequency depending on selected level


crypto = nodeRequire 'crypto'

module.exports =
class Pasteboard
  signatureForMetadata: null

  md5: (text) ->
    crypto.createHash('md5').update(text).digest('hex')

  write: (text, metadata) ->
    @signatureForMetadata = @md5(text)
    @metadata = metadata
    $native.writeToPasteboard(text)

  read: ->
    text = $native.readFromPasteboard()
    value = [text]
    value.push(@metadata) if @signatureForMetadata == @md5(text)
    value

crypto = nodeRequire 'crypto'

module.exports =
class Pasteboard
  signatureForMetadata: null

  md5: (text) ->
    crypto.createHash('md5').update(text, 'utf8').digest('hex')

  write: (text, metadata) ->
    @signatureForMetadata = @md5(text)
    @metadata = metadata
    $native.writeToPasteboard(text)

  read: ->
    text = $native.readFromPasteboard()
    value = [text]
    value.push(@metadata) if @signatureForMetadata == @md5(text)
    value

Set input encoding to utf8

Set input encoding to utf8


#!highlights/node_modules/coffee-script/bin/coffee

Highlights = require 'highlights'
fs = require 'fs'
path = require 'path'
split = require 'split'
highlighter = new Highlights()
highlighter.requireGrammarsSync
  modulePath: require.resolve('./atom-language-perl6/package.json')

stdin = process.openStdin()
stdin.setEncoding 'utf8'

stdin.on 'data', (input) ->
    name = input.trim()
    process.exit() if name == 'exit'
    file_to_hl = path.resolve(name)
    console.error "Highlights is reading #{file_to_hl}"
    foo = ->
      fs.readFileSync file_to_hl, 'utf8'

    html = highlighter.highlightSync
      fileContents: foo()
      scopeName: 'source.perl6fe'

    console.log html

#!highlights/node_modules/coffee-script/bin/coffee

Highlights = require 'highlights'
fs = require 'fs'
path = require 'path'
highlighter = new Highlights()
highlighter.requireGrammarsSync
  modulePath: require.resolve('./atom-language-perl6/package.json')

stdin = process.openStdin()
stdin.setEncoding 'utf8'

stdin.on 'data', (input) ->
    name = input.trim()
    process.exit() if name == 'exit'
    file_to_hl = path.resolve(name)
    console.error "Highlights is reading #{file_to_hl}"
    foo = ->
      fs.readFileSync file_to_hl, 'utf8'

    html = highlighter.highlightSync
      fileContents: foo()
      scopeName: 'source.perl6fe'

    console.log html

Remove split which isn't in the node package dependencies


Darkswarm.controller "AccordionCtrl", ($scope, localStorageService, $timeout, $document, CurrentHub) ->
  key = "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"
  value = if localStorageService.get(key) then {} else { details: true, billing: false, shipping: false, payment: false }
  localStorageService.bind $scope, "accordion", value, key
  $scope.accordionSections = ["details", "billing", "shipping", "payment"]

  $scope.show = (section)->
    $scope.accordion[section] = true

  $scope.$on 'purchaseFormInvalid', (event, form) ->
    # Scroll to first invalid section
    for section in $scope.accordionSections
      if not form[section].$valid
        $scope.show section

        # If we call scrollTo() directly after show(), when one of the accordions above the
        # scroll location is closed by show(), scrollTo() will scroll to the old location of
        # the element. Putting this in a zero-length timeout is enough delay for the DOM to
        # have updated.
        $timeout ->
          # Scrolling is confused by our position:fixed top bar - add an offset to scroll
          # to the correct location, plus 5px buffer
          offset_height = $("nav.top-bar").height() + 5
          $document.scrollTo $("##{section}"), offset_height, 500
        break

Darkswarm.controller "AccordionCtrl", ($scope, localStorageService, $timeout, $document, CurrentHub) ->
  key = "accordion_#{$scope.order.id}#{CurrentHub.hub.id}#{$scope.order.user_id}"
  value = if localStorageService.get(key) then {} else { details: true, billing: false, shipping: false, payment: false }
  localStorageService.bind $scope, "accordion", value, key
  $scope.accordionSections = ["details", "billing", "shipping", "payment"]
  # Scrolling is confused by our position:fixed top bar - add an offset to scroll
  # to the correct location, plus 5px buffer
  offset_height = $("nav.top-bar").height() + 5

  $scope.show = (section)->
    $scope.accordion[section] = true
    # If we call scrollTo() directly after show(), when one of the accordions above the
    # scroll location is closed by show(), scrollTo() will scroll to the old location of
    # the element. Putting this in a 50 ms timeout is enough delay for the DOM to
    # have updated.
    $timeout (->
      $document.scrollTo $("##{section}"), offset_height, 500), 50

  $scope.$on 'purchaseFormInvalid', (event, form) ->
    # Scroll to first invalid section
    for section in $scope.accordionSections
      if not form[section].$valid
        $scope.show section
        break

Call toScroll after any new panel is . Also added an actual delay as it still scrolled to the 'old' location.. 10 ms was too short to allow the location to update after the old panel closes (on Chrome), 50 ms seems ok.


require './spec-helper'
ColorSearch = require '../lib/color-search'

describe 'ColorSearch', ->
  [search, pigments, project] = []

  beforeEach ->
    waitsForPromise -> atom.packages.activatePackage('pigments').then (pkg) ->
      pigments = pkg.mainModule
      project = pigments.getProject()

    waitsForPromise -> project.initialize()

  describe 'when created with basic options', ->
    beforeEach ->
      search = new ColorSearch
        sourceNames: [
          '**/*.styl'
          '**/*.less'
        ]
        ignoredNames: [
          'project/vendor/**'
        ]
        context: project.getContext()

    it 'dispatches a did-complete-search when finalizing its search', ->
      spy = jasmine.createSpy('did-complete-search')
      search.onDidCompleteSearch(spy)
      waitsFor -> spy.callCount > 0
      runs -> expect(spy.argsForCall[0][0].length).toEqual(23)

require './spec-helper'
ColorSearch = require '../lib/color-search'

describe 'ColorSearch', ->
  [search, pigments, project] = []

  beforeEach ->
    atom.config.set 'pigments.sourceNames', [
      '**/*.styl'
      '**/*.less'
    ]

    waitsForPromise -> atom.packages.activatePackage('pigments').then (pkg) ->
      pigments = pkg.mainModule
      project = pigments.getProject()

    waitsForPromise -> project.initialize()

  describe 'when created with basic options', ->
    beforeEach ->
      search = new ColorSearch
        sourceNames: atom.config.get 'pigments.sourceNames'
        ignoredNames: [
          'project/vendor/**'
        ]
        context: project.getContext()

    it 'dispatches a did-complete-search when finalizing its search', ->
      spy = jasmine.createSpy('did-complete-search')
      search.onDidCompleteSearch(spy)
      waitsFor -> spy.callCount > 0
      runs -> expect(spy.argsForCall[0][0].length).toEqual(23)

Fix missing config in search specs

:green_heart: Fix missing config in search specs


Q = require('q')

class GeoCoder
  constructor: () ->
    @geocoder = new google.maps.Geocoder()
  code: (request) ->
    deferred = Q.defer()
    @geocoder.geocode request, (results, status) ->
      if status is google.maps.GeocoderStatus.OK
        deferred.resolve results.map (result) ->
          address: result.formatted_address
          location:
            longitude: result.geometry.loaction.lng()
            latitude:  result.geometry.loaction.lat()
      else
        deferred.reject status
    deferred.promise
  codeAddress: (address) ->
    @code address: address
  codeLocation: (location) ->
    @code location: google.maps.LatLng(location.latitude, location.longitude)

exports = {GeoCoder}

$ = require('jquery')
Bacon = require('bacon')

class GeoCoder
  constructor: () ->
    @geocoder = new google.maps.Geocoder()
  code: (request) ->
    deferred = $.Deferred()
    @geocoder.geocode request, (results, status) ->
      if status is google.maps.GeocoderStatus.OK
        deferred.resolve results.map (result) ->
          address: result.formatted_address
          location:
            longitude: result.geometry.loaction.lng()
            latitude:  result.geometry.loaction.lat()
      else
        deferred.reject status
    Bacon.fromPromise deferred
  codeAddress: (address) ->
    @code address: address
  codeLocation: (location) ->
    @code location: google.maps.LatLng(location.latitude, location.longitude)

class CurrentLocation
  constructor: ->
    stream = Bacon.fromBinder (sink) ->
      navigator.geolocation.watchPosition(
        (coords:{longitude, latitude}) -> sink {longitude, lataiude}
        (e) -> sink new Bacon.Error(e)
    @location = stream.toProperty()

module.exports = {GeoCoder, CurrentLocation}

Add a class for tracking current location


ETahi.PaperEditRoute = ETahi.AuthorizedRoute.extend
  beforeModel: ->
    visualEditorScript = '/visual-editor.js'
    unless ETahi.LazyLoaderMixin.loaded[visualEditorScript]
      $.getScript(visualEditorScript).then ->
        ETahi.LazyLoaderMixin.loaded[visualEditorScript] = true

  model: (params) ->
    paper = @modelFor('paper')
    new Ember.RSVP.Promise((resolve, reject) ->
      paper.get('tasks').then((tasks) -> resolve(paper)))

  afterModel: (model) ->
    @replaceWith('paper.index', model) if model.get('submitted')

  setupController: (controller, model) ->
    controller.set('model', model)
    controller.set 'authors', @store.all('author').filter (author) =>
      author.get('authorGroup.paper') == model

  actions:
    viewCard: (task) ->
      paper = @modelFor('paper')
      redirectParams = ['paper.edit', @modelFor('paper')]
      @controllerFor('application').get('overlayRedirect').pushObject(redirectParams)
      @controllerFor('application').set('overlayBackground', 'paper/edit')
      @transitionTo('task', paper.id, task.id)

ETahi.PaperEditRoute = ETahi.AuthorizedRoute.extend
  beforeModel: ->
    visualEditorScript = '/visual-editor.js'
    unless ETahi.LazyLoaderMixin.loaded[visualEditorScript]
      $.getScript(visualEditorScript).then ->
        ETahi.LazyLoaderMixin.loaded[visualEditorScript] = true

  model: ->
    paper = @modelFor('paper')
    new Ember.RSVP.Promise((resolve, reject) ->
      paper.get('tasks').then((tasks) -> resolve(paper)))

  afterModel: (model) ->
    @replaceWith('paper.index', model) if model.get('submitted')

  setupController: (controller, model) ->
    controller.set('model', model)
    controller.set 'authors', @store.all('author').filter (author) =>
      model.get('authorGroups').indexOf(author.get('authorGroup')) > -1

  actions:
    viewCard: (task) ->
      paper = @modelFor('paper')
      redirectParams = ['paper.edit', @modelFor('paper')]
      @controllerFor('application').get('overlayRedirect').pushObject(redirectParams)
      @controllerFor('application').set('overlayBackground', 'paper/edit')
      @transitionTo('task', paper.id, task.id)

Change Author filter criteria in PaperEditRoute.

Don't filter using AuthorGroup.paper, the yet-to-be-hydrated paper model
will clobber the reference and screw things up.


Shothere.Views.Movies ||= {}

class Shothere.Views.Movies.IndexView extends Shothere.Views.MapView
  template: JST["templates/movies/index"]

  initialize: () ->
    @options.movies.bind('reset', @addAll)

  addAll: () =>
    @options.movies.each(@addOne)

  addOne: (movie) =>
    view = new Shothere.Views.Movies.MovieView({model : movie})
    @$("tbody").append(view.render().el)
    @addMarker movie.get("latitude"), movie.get("longitude")

  render: =>
    $(@el).html(@template(movies: @options.movies.toJSON() ))
    @renderMap @options.center[0], @options.center[1], 2
    @addAll()
    return this

Shothere.Views.Movies ||= {}

class Shothere.Views.Movies.IndexView extends Shothere.Views.MapView
  template: JST["templates/movies/index"]

  templatePopup: JST["templates/movies/popup"]

  initialize: () ->
    @options.movies.bind('reset', @addAll)

  addAll: () =>
    @options.movies.each(@addOne)

  addOne: (movie) =>
    view = new Shothere.Views.Movies.MovieView({model : movie})
    @$("tbody").append(view.render().el)
    @addMarkerWithPopup movie.get("latitude"), movie.get("longitude"), @templatePopup, movie.toJSON()

  render: =>
    $(@el).html(@template(movies: @options.movies.toJSON() ))
    @renderMap @options.center[0], @options.center[1], 2
    @addAll()
    return this

Add popups to the index map

Add popups to the index map


if @Curri && @Curri.user
  userData =
    email: Curri.user.email
    classRole: Curri.user.classrole_type
    created: Curri.user.created_at
    firstName: Curri.user.first_name || ''
    lastName: Curri.user.last_name || ''

  analytics.identify(Curri.user.id, userData)

if @Curri && @Curri.user
  userData =
    email: Curri.user.email
    classRole: Curri.user.classrole_type
    created: Curri.user.created_at
    firstName: Curri.user.first_name || 'No'
    lastName: Curri.user.last_name || 'Name'

  analytics.identify(Curri.user.id, userData)

Fix for issue with blank names

Fix for issue with blank names


ModalView = require 'views/core/ModalView'
template = require 'templates/courses/student-log-in-modal'
auth = require 'core/auth'
forms = require 'core/forms'
User = require 'models/User'

module.exports = class StudentSignInModal extends ModalView
  id: 'student-log-in-modal'
  template: template

  events:
    'click #log-in-btn': 'onClickLogInButton'
    'submit form': 'onSubmitForm'

  onSubmitForm: (e) ->
    e.preventDefault()
    @login()

  onClickLogInButton: ->
    @login()

  login: ->
    userObject = forms.formToObject @$el
    res = tv4.validateMultiple userObject, User.schema
    return forms.applyErrorsToForm(@$el, res.errors) unless res.valid
    @enableModalInProgress(@$el)
    auth.loginUser userObject, (jqxhr) =>
      error = jqxhr.responseJSON[0]
      message = error.property + ' ' + error.message
      @disableModalInProgress(@$el)
      @$('#errors-alert').text(message).removeClass('hide')

ModalView = require 'views/core/ModalView'
template = require 'templates/courses/student-log-in-modal'
auth = require 'core/auth'
forms = require 'core/forms'
User = require 'models/User'

module.exports = class StudentSignInModal extends ModalView
  id: 'student-log-in-modal'
  template: template

  events:
    'click #log-in-btn': 'onClickLogInButton'
    'submit form': 'onSubmitForm'

  onSubmitForm: (e) ->
    e.preventDefault()
    @login()

  onClickLogInButton: ->
    @login()

  login: ->
    data = forms.formToObject @$el
    @enableModalInProgress(@$el)
    auth.loginUser data, (jqxhr) =>
      error = jqxhr.responseJSON[0]
      message = _.filter([error.property, error.message]).join(' ')
      @disableModalInProgress(@$el)
      @$('#errors-alert').text(message).removeClass('hide')

Fix StudentLoginModal when email or password is not included


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

ready = ->
	parseText = (text) ->
		# parsing markdown to html
		$('#item-preview-content').html(marked(text))
		# highlighting
		$('#item-preview-content').find('pre code').each (i, block) ->
			hljs.highlightBlock(block);
	parseBody = ->
		$('#item-body').html(marked(text))
		$('#item-body').find('pre code').each (i, block) ->
			hljs.highlightBlock(block);
	checkTextChange = (e) ->
		old = v = $(e).find('#item-text').val()
		return ->
			v = $(e).find('#item-text').val()
			if old isnt v
				old = v
				parseText(v)

	parseBody()
	parseText $('#item-text').val() if $('#item-text').val()
	$(document).on 'keyup', '#item-text', checkTextChange(this)

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

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

ready = ->
	parseText = (text) ->
		# parsing markdown to html
		$('#item-preview-content').html(marked(text))
		# highlighting
		$('#item-preview-content').find('pre code').each (i, block) ->
			hljs.highlightBlock(block);
	parseBody = ->
		$('#item-body').html(marked(text))
		$('#item-body').find('pre code').each (i, block) ->
			hljs.highlightBlock(block);
	checkTextChange = (e) ->
		old = v = $(e).find('#item-text').val()
		return ->
			v = $(e).find('#item-text').val()
			if old isnt v
				old = v
				parseText(v)

	parseBody() if $('#item-body')[0]
	parseText $('#item-text').val() if $('#item-text').val()
	$(document).on 'keyup', '#item-text', checkTextChange(this)

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

Fix error for parsing undefined

Fix error for parsing undefined


## Key-value table panel without a table header

## Example
#  React.createElement TablePanel,
#    type:  'success'
#    title: "Volume for each room"
#    obj:   { ocean: 23, air: 12, ... }

@MovingVolumePanel = React.createClass
  getInitialState: ->
    data: @props.data

  render: ->
    $ = React.DOM

    $.div
      className: "panel panel-#{ @props.type }"
      $.div
        className: 'panel-heading'
        @props.title
      $.div
        className: 'panel-body'
        $.table
          className: "table"
          $.tbody null,
            for key, i in Object.keys(@props.data)
              $.tr
                key: i # Requried by React.js
                $.td
                  className: 'lead'
                  key
                $.td
                  className: 'lead'
                  @props.data[key]

## Key-value table panel without a table header

## Example
#  React.createElement TablePanel,
#    type:  'success'
#    title: "Volume for each room"
#    obj:   { ocean: 23, air: 12, ... }

@MovingVolumePanel = React.createClass
  getInitialState: ->
    data: @props.data

  render: ->
    $ = React.DOM

    $.div
      className: "panel panel-#{ @props.type }"
      $.div
        className: 'panel-heading'
        @props.title
      $.div
        className: 'panel-body'
        $.table
          className: "table table-striped"
          $.tbody null,
            for key, i in Object.keys(@props.data)
              $.tr
                key: i # Requried by React.js
                $.td
                  className: 'lead text-center col-sm-5'
                  key
                $.td
                  className: 'lead text-center col-sm-5'
                  @props.data[key]

Adjust table widths for table panels

Adjust table widths for table panels


mongo = require '../models/connection'

exports.collect = (req, res) ->
    if req.get('content-type').indexOf('application/json') == -1
        throw new Error("Body request is not JSON.")

    jsonData = req.body

    mongo.db.collection('sensor').count(
        {sensor_id : jsonData.sensor_id}, (err, count) ->
            if err
                console.log(err)
                res.send 500

            else if  count < 1
                console.log "Adding new sensor " + jsonData.sensor_id + " to DB"
                mongo.db.collection('sensor').insert(
                    {sensor_id : jsonData.sensor_id, model : jsonData.model }, {w:1}, (err, collection) ->
                        console.log(err)
                )
        )

    mongo.db.collection('data').insert(
        jsonData, {w:1}, (err, collection) ->
            if err
                console.log(err)
                res.send 500
            else
                res.send 200
    )

mongo = require '../models/connection'

exports.collect = (req, res) ->
    if req.get('content-type').indexOf('application/json') == -1
        throw new Error("Body request is not JSON.")

    jsonData = req.body

    mongo.db.collection('sensors').count(
        {sensor_id : jsonData.sensor_id}, (err, count) ->
            if err
                console.log(err)
                res.send 500

            else if  count < 1
                mongo.db.collection('sensors').insert(
                    {sensor_id : jsonData.sensor_id, model : jsonData.model, hub_id : jsonData.hub_id, created_on : Date.now()}, {w:1}, (err, collection) ->
                        console.log(err)
                )
        )
    data =
        sensor_id : jsonData.sensor_id
        value : jsonData.value
        model : jsonData.model
        unit : jsonData.unit
        created_on : jsonData.created_on

    mongo.db.collection('data').insert(
        jsonData, {w:1}, (err, collection) ->
            if err
                console.log(err)
                res.send 500
            else
                res.send 200
    )

Save the hub_id from the HomePi

Save the hub_id from the HomePi


Settings = require 'settings-sharelatex'

module.exports = Features =
	externalAuthenticationSystemUsed: ->
		Settings.ldap? or Settings.saml? or Settings.overleaf?.oauth?

	hasFeature: (feature) ->
		switch feature
			when 'homepage'
				return Settings.enableHomepage
			when 'registration'
				return not Features.externalAuthenticationSystemUsed()
			when 'github-sync'
				return Settings.enableGithubSync
			when 'v1-return-message'
				return Settings.accountMerge? and Settings.overleaf?
			when 'publish-modal'
				return Settings.showPublishModal
			when 'custom-togglers'
				return Settings.overleaf?
			else
				throw new Error("unknown feature: #{feature}")

Settings = require 'settings-sharelatex'

module.exports = Features =
	externalAuthenticationSystemUsed: ->
		Settings.ldap? or Settings.saml? or Settings.overleaf?.oauth?

	hasFeature: (feature) ->
		switch feature
			when 'homepage'
				return Settings.enableHomepage
			when 'registration'
				return not Features.externalAuthenticationSystemUsed()
			when 'github-sync'
				return Settings.enableGithubSync
			when 'v1-return-message'
				return Settings.accountMerge? and Settings.overleaf?
			when 'publish-modal'
				return Settings.showPublishModal
			when 'custom-togglers'
				return Settings.overleaf?
			when 'templates'
				return !Settings.overleaf?
			else
				throw new Error("unknown feature: #{feature}")

Add `templates` to the `hasFeature` function


# 3rd Party Libraries
immutable = require('immutable')

# Internal Libraries
misc = require('smc-util/misc')
{types} = misc

exports.get_store_def = (name) ->
    name: name

    stateTypes:
        height             : types.number         # 0 means not rendered; otherwise is the height of the chat editor
        input              : types.string         # content of the input box
        is_preview         : types.bool           # currently displaying preview of the main input chat
        last_sent          : types.string         # last sent message
        messages           : types.immutable.Map  # Map of all messages
        offset             : types.number         # information about where on screen the chat editor is located
        position           : types.number         # more info about where chat editor is located
        saved_mesg         : types.string         # The message state before saving and edited message. Potentially broken with mutiple edits
        use_saved_position : types.bool           # whether or not to maintain last saved scroll position (used when unmounting then remounting, e.g., due to tab change)

    getInitialState: =>
        height             : 0
        input              : ''
        is_preview         : undefined
        last_sent          : undefined
        messages           : undefined
        offset             : undefined
        position           : undefined
        saved_mesg         : undefined
        use_saved_position : undefined

# 3rd Party Libraries
immutable = require('immutable')

# Internal Libraries
misc = require('smc-util/misc')
{types} = misc

exports.get_store_def = (name) ->
    name: name

    stateTypes:
        height             : types.number         # 0 means not rendered; otherwise is the height of the chat editor
        input              : types.string         # content of the input box
        is_preview         : types.bool           # currently displaying preview of the main input chat
        last_sent          : types.string         # last sent message
        messages           : types.immutable.Map  # Map of all messages
        offset             : types.number         # information about where on screen the chat editor is located
        position           : types.number         # more info about where chat editor is located
        saved_mesg         : types.string         # The message state before saving and edited message. Potentially broken with mutiple edits
        use_saved_position : types.bool           # whether or not to maintain last saved scroll position (used when unmounting then remounting, e.g., due to tab change)
        saved_position     : types.number

    getInitialState: =>
        height             : 0
        input              : ''
        is_preview         : undefined
        last_sent          : undefined
        messages           : undefined
        offset             : undefined
        position           : undefined
        saved_mesg         : undefined
        use_saved_position : undefined
        saved_position     : undefined

Fix scroll save for chat

Fix scroll save for chat


Walrus = require '../../bin/walrus'

TestHelpers =

  pass : ( specs, suffix='' ) ->

    fs    = require 'fs'
    path  = require 'path'
    exec  = require( 'child_process' ).exec

    for file in fs.readdirSync specs when path.extname( file ) is '.wal'

      do ( file ) ->

        base = path.basename file, '.wal'

        text = fs.readFileSync "#{specs}/#{base}.wal",           'utf8'
        json = fs.readFileSync "#{specs}/#{base}.js",            'utf8'
        html = fs.readFileSync "#{specs}/#{base}#{suffix}.html", 'utf8'

        tmpl = Walrus.Parser.parse text

        it "should pass the #{base}#{suffix} example", ( done ) ->

          comp = tmpl.compile( eval( "(#{json})" ) )

          if comp is html
            done( )
          else

            cmd = """
            printf "#{comp}" | diff --unified #{specs}/#{base}#{suffix}.html -
            """

            exec cmd, ( error, stdout, stderr ) ->

              done new Error "Expected did not match actual:\n" + stdout

module.exports = TestHelpers

Walrus = require '../../bin/walrus'

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

TestHelpers =

  read : ( filename ) -> fs.readFileSync filename, 'utf8' if path.existsSync filename

  pass : ( specs, suffix='' ) ->

    fs    = require 'fs'
    path  = require 'path'
    exec  = require( 'child_process' ).exec

    for file in fs.readdirSync specs when path.extname( file ) is '.wal'

      do ( file ) =>

        base = path.basename file, '.wal'

        text = @read "#{specs}/#{base}.wal"
        json = @read "#{specs}/#{base}.js"
        html = @read "#{specs}/#{base}#{suffix}.html"

        # if we can't find the suffixed version, try and find
        # one without the suffix and use that instead.
        html = @read "#{specs}/#{base}.html" if not html

        # if _that_ one doesn't exist, throw a helpful error.
        throw "Can't find example html at #{specs}/#{base}#{suffix}.html or #{specs}/#{base}.html" if not html

        tmpl = Walrus.Parser.parse text

        it "should pass the #{base}#{suffix} example", ( done ) ->

          comp = tmpl.compile( eval( "(#{json})" ) )

          if comp is html
            done( )
          else

            cmd = """
            printf "#{comp}" | diff --unified #{specs}/#{base}#{suffix}.html -
            """

            exec cmd, ( error, stdout, stderr ) ->

              done new Error "Expected did not match actual:\n" + stdout

module.exports = TestHelpers

Make test helpers smart about checking for suffixed tests


Sprangular.controller 'CheckoutDeliveryAndPaymentCtrl', ($scope, Account, Cart, Checkout) ->
  $scope.order = Cart.current
  $scope.processing = false
  $scope.user = Account.user

  $scope.$watch 'order.state', (state) ->
    $scope.done = state == 'confirm'
    $scope.active = _.contains(['delivery', 'payment'], state)

  $scope.edit = ->
    $scope.order.state = 'delivery'

  $scope.advance = ->
    order = $scope.order
    return if order.shippingAddress.isInvalid() || (!order.billToShipAddress && order.billingAddress.isInvalid())

    $scope.processing = true

    Checkout.setPayment()
      .then ->
          $scope.processing = false
        , ->
          $scope.processing = false

Sprangular.controller 'CheckoutDeliveryAndPaymentCtrl', ($scope, Account, Cart, Checkout) ->
  $scope.order = Cart.current
  $scope.processing = false
  $scope.user = Account.user

  $scope.$watch 'order.state', (state) ->
    $scope.done = state == 'confirm'
    $scope.active = _.contains(['delivery', 'payment'], state)

  $scope.edit = ->
    $scope.order.state = 'delivery'

  $scope.advance = ->
    order = $scope.order
    return if order.creditCard.isInvalid()

    $scope.processing = true

    Checkout.setPayment()
      .then ->
          $scope.processing = false
        , ->
          $scope.processing = false

Check if CC is valid when setting payment


uuid = require 'node-uuid'
ssdp = require './ssdp'
extend = require('./helpers').extend

configDefaults =
    device:
        schema:
            prefix: 'urn:schemas-upnp-org:device'
        uuid: 'uuid:' + uuid()
    network:
        ssdp:
            timeout: 1800
            address: '239.255.255.250'
            port: 1900

upnp = {}
upnp.start = (config, callback) ->
    # add config values recieved from caller
    extend config, configDefaults
    ssdp.start config, (err, msg) ->
        callback err, msg

module.exports = upnp

uuid = require 'node-uuid'
ssdp = require './ssdp'
xmlServer = require './xml-server'

upnp = {}
upnp.createDevice = (type, version, callback) =>
    for arg in arguments
        if typeof arg is 'Function'
            callback = arg

    @config =
        device:
            schema:
                prefix: 'urn:schemas-upnp-org:device'
            uuid: 'uuid:' + uuid()
            type: type ? 'Basic'
            version: version ? '1.0'
        network:
            ssdp:
                timeout: 1800
                address: '239.255.255.250'
                port: 1900
            http:
                address: '192.168.9.3'
                port: 3000

    xmlServer.start @config, (err, msg) ->
        callback err, msg

upnp.announce = (name, version, callback) =>
    for arg in arguments
        if typeof arg is 'Function'
            callback = arg

    @config['app'] =
        name: name ? 'Generic UPnP Device'
        version: version ? '1.0'

    ssdp.start @config, (err, msg) ->
        callback err, msg

module.exports = upnp

Initialize UPnP in a different way

Initialize UPnP in a different way


# 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:
#
# 'atom-text-editor':
#   'enter': 'editor:newline'
#
# 'atom-workspace':
#   'ctrl-shift-p': 'core:move-up'
#   'ctrl-p': 'core:move-down'
#
# You can find more information about keymaps in these guides:
# * https://atom.io/docs/latest/customizing-atom#customizing-key-bindings
# * https://atom.io/docs/latest/advanced/keymaps
#
# This file uses CoffeeScript Object Notation (CSON).
# If you are unfamiliar with CSON, you can read more about it here:
# https://github.com/bevry/cson#what-is-cson

'atom-text-editor':
	'ctrl-cmd-t': 'whitespace:convert-spaces-to-tabs'
	'cmd-l': 'go-to-line:toggle'

Add additional shortcut for go-to-line in Atom


module.exports = (obj, methodName, key, logger) ->
	metrics = require('./metrics')

	if typeof obj[methodName] != 'function'
		throw new Error("[Metrics] expected object property '#{methodName}' to be a function")

	realMethod = obj[methodName]
	key = "methods.#{key}"

	obj[methodName] = (originalArgs...) ->

		[firstArgs..., callback] = originalArgs
		if !callback? || typeof callback != 'function'
			throw new Error(
				"[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback"
			)

		timer = new metrics.Timer(key)
		start = new Date()

		realMethod.call this, firstArgs..., (callbackArgs...) ->
			timer.done()
			elapsedTime = new Date() - start
			if logger?
				logger.log {key, elapsedTime}, "[Metrics] timed async method call"
			callback.apply this, callbackArgs

module.exports = (obj, methodName, key, logger) ->
	metrics = require('./metrics')

	if typeof obj[methodName] != 'function'
		throw new Error("[Metrics] expected object property '#{methodName}' to be a function")

	realMethod = obj[methodName]
	key = "methods.#{key}"

	obj[methodName] = (originalArgs...) ->

		[firstArgs..., callback] = originalArgs
		if !callback? || typeof callback != 'function'
			throw new Error(
				"[Metrics] expected wrapped method '#{methodName}' to be invoked with a callback"
			)

		timer = new metrics.Timer(key)

		realMethod.call this, firstArgs..., (callbackArgs...) ->
			elapsedTime = timer.done()
			if logger?
				logger.log {key, elapsedTime}, "[Metrics] timed async method call"
			callback.apply this, callbackArgs

Clean up, don't allocate an extra date

Clean up, don't allocate an extra date


$              = require 'jquery'
SplitView      = require '../utils/split-view'
StatusListView = require './status-list-view'
DiffView       = require './diff-view'

class ChangesView extends SplitView
  initialize: ({@uri, width}) ->
    @statusListView = new StatusListView
    @diffView       = new DiffView

    @width(width) if width > 0

    @setSubViews
      summaryView: @statusListView
      detailsView: @diffView

    @update()

  update: ->
    @statusListView.update()

  getTitle: ->
    'Commit changes'

  getURI: -> @uri

  serialize: ->
    deserializer: 'GitChangesView'
    uri: @getURI()
    width: @width()

module.exports = document.registerElement 'git-experiment-changes-view',
  prototype: ChangesView.prototype

$              = require 'jquery'
SplitView      = require '../utils/split-view'
StatusListView = require './status-list-view'
DiffView       = require './diff-view'

class ChangesView extends SplitView
  initialize: ({@uri, width}) ->
    @statusListView = new StatusListView
    @diffView       = new DiffView

    @width(width) if width > 0

    @setSubViews
      summaryView: @statusListView
      detailsView: @diffView

    @update()

  update: ->
    @el.trigger('index-updated')

  getTitle: ->
    'Commit changes'

  getURI: -> @uri

  serialize: ->
    deserializer: 'GitChangesView'
    uri: @getURI()
    width: @width()

module.exports = document.registerElement 'git-experiment-changes-view',
  prototype: ChangesView.prototype

Clear cached views on update

Clear cached views on update


Phone = require('../Phone')
PhoneNumber = require('../PhoneNumber')

class Iraq
	constructor: ->
		@countryName = "Iraq"
		@countryNameAbbr = "IRQ"
		@countryCode = '964'
		@regex = /^(?:\+|00)964(7?\d{1,2})\d{7}$/
		@optionalTrunkPrefix = '0'
		@nationalNumberSeparator = ' '
		@nationalDestinationCode =
			['1', '21', '23', '24', '25', '30', '32', '33', '36', '37', '40', '42', '43', '50', '53', '60', '62', '66']

# register
iraq = new Iraq()
Phone.countries['964'] = iraq

# exports
module.exports = iraq

Phone = require('../Phone')
PhoneNumber = require('../PhoneNumber')

class Iraq
	constructor: ->
		@countryName = "Iraq"
		@countryNameAbbr = "IRQ"
		@countryCode = '964'
		@regex = /^(?:\+|00)964(7?\d{1,2})\d{7}$/
		@optionalTrunkPrefix = '0'
		@nationalNumberSeparator = ' '
		@nationalDestinationCode =
			['7(\\d{2})', '1', '21', '23', '24', '25', '30', '32', '33', '36', '37', '40', '42', '43', '50', '53', '60', '62', '66']

	specialRules: (withoutCountryCode, withoutNDC, ndc) =>
		phone = new PhoneNumber(@countryNameAbbr, @countryCode, ndc, withoutNDC)

		if withoutNDC.length is 7
			phone.isMobile = ndc[0] is '7'
			return phone
		else if withoutNDC.length is 7 or withoutNDC.length is 6 then return phone

# register
iraq = new Iraq()
Phone.countries['964'] = iraq

# exports
module.exports = iraq

Add mobile operator codes for Iraq

Add mobile operator codes for Iraq


Bacon = require 'baconjs'
atomStreams = require './streams.coffee'

filteredPathsStream = (pairwisePathsStream, filterFn) ->
  pairwisePathsStream.flatMap (pair) ->
    Bacon.fromArray filterFn(pair)

module.exports = ->
  pathsStream = atomStreams.fromDisposable atom.project, 'onDidChangePaths'
    .merge Bacon.fromArray [ [], atom.project.getPaths() ]
  lastProjectPathsProp = pathsStream.slidingWindow(2, 2)

  addStream = filteredPathsStream lastProjectPathsProp, ([currentPaths, newPaths]) ->
    newPaths.filter (path) -> currentPaths.indexOf(path) < 0

  removeStream = filteredPathsStream lastProjectPathsProp, ([currentPaths, newPaths]) ->
    currentPaths.filter (path) -> newPaths.indexOf(path) < 0

  return {
    addStream: addStream
    removeStream: removeStream
  }

Bacon = require 'baconjs'
atomStreams = require './streams.coffee'

filteredPathsStream = (pairwisePathsStream, filterFn) ->
  pairwisePathsStream.flatMap (pair) ->
    Bacon.sequentially 0, filterFn(pair)

module.exports = ->
  pathsStream = atomStreams.fromDisposable atom.project, 'onDidChangePaths'
    .merge Bacon.sequentially 0, [ [], atom.project.getPaths() ]
  lastProjectPathsProp = pathsStream.slidingWindow(2, 2)

  addStream = filteredPathsStream lastProjectPathsProp, ([currentPaths, newPaths]) ->
    newPaths.filter (path) -> currentPaths.indexOf(path) < 0

  removeStream = filteredPathsStream lastProjectPathsProp, ([currentPaths, newPaths]) ->
    currentPaths.filter (path) -> newPaths.indexOf(path) < 0

  return {
    addStream: addStream
    removeStream: removeStream
  }

Use sequentially instead of fromArray

Use sequentially instead of fromArray

per FAQ recommendation,
https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-subscriber-call
ed


# auto-indent when changing line or inserting at end of line
atom.commands.onDidDispatch (evt) ->
  validCommands = [
    'vim-mode-plus:change',
    'vim-mode-plus:insert-after-end-of-line'
  ]
  return unless evt.type in validCommands
  editor = atom.workspace.getActivePaneItem()
  element = editor.getElement()
  return unless 'insert-mode' in element.classList
  for cursor in editor.getCursors()
    return unless cursor.getBufferColumn() is 0
  editor.autoIndentSelectedRows()

# auto-indent when changing line or inserting at end of line
handleAutoIndentAfterChangeLine = (evt) ->
  validCommands = [
    'vim-mode-plus:change',
    'vim-mode-plus:insert-after-end-of-line'
  ]
  return unless evt.type in validCommands
  editor = atom.workspace.getActivePaneItem()
  element = editor.getElement()
  return unless 'insert-mode' in element.classList
  for cursor in editor.getCursors()
    return unless cursor.getBufferColumn() is 0
  editor.autoIndentSelectedRows()

handleTrimWhitespaceAfterEscape = (evt) ->
  validCommands = [
    'vim-mode-plus:reset-normal-mode'
    'vim-mode-plus:activate-normal-mode'
  ]
  return unless evt.type in validCommands
  editor = atom.workspace.getActivePaneItem()
  for cursor in editor.getCursors()
    row = cursor.getBufferRow()
    text = editor.buffer.getLines()[row]
    if text.match /^\s+$/
      editor.deleteToBeginningOfLine()

atom.commands.onDidDispatch (evt) ->
  handleAutoIndentAfterChangeLine(evt)

atom.commands.onWillDispatch (evt) ->
  handleTrimWhitespaceAfterEscape(evt)

Trim trailing whitespace when exiting insert mode


module.exports = (grunt) ->
	grunt.initConfig
		clean:
			package: ['tasks/gyp.js']
			test: ['test/support/build']
		coffee:
			task:
				options:
					bare: true
				files:
					'tasks/gyp.js': 'tasks/gyp.coffee'
		mochacli:
			options:
				bail: true
				compilers: ['coffee:coffee-script/register']
			files: ['test/']

	grunt.loadNpmTasks 'grunt-contrib-clean'
	grunt.loadNpmTasks 'grunt-contrib-coffee'
	grunt.loadNpmTasks 'grunt-mocha-cli'

	grunt.registerTask 'package', ['coffee:task']
	grunt.registerTask 'test', ['clean:test', 'mochacli']

	grunt.registerTask 'default', []

module.exports = (grunt) ->
	grunt.initConfig
		clean:
			package: ['tasks/gyp.js']
			test: ['test/support/build']
		coffee:
			task:
				options:
					bare: true
				files:
					'tasks/gyp.js': 'tasks/gyp.coffee'
		mochacli:
			options:
				bail: true
				compilers: ['coffee:coffee-script/register']
			files: ['test/']

	grunt.loadNpmTasks 'grunt-contrib-clean'
	grunt.loadNpmTasks 'grunt-contrib-coffee'
	grunt.loadNpmTasks 'grunt-mocha-cli'

	grunt.registerTask 'package', ['coffee:task']
	grunt.registerTask 'test', ['clean', 'mochacli']

	grunt.registerTask 'default', []

Remove tasks/gyp.js before running tests

Otherwise Grunt would prefer tasks/gyp.js over tasks/gyp.coffee and changes in the CoffeeScript source would have no effect.


window.FactlinkAppMode ?= {}
window.FactlinkAppMode.coreInClient = (app) ->
  app.onClientApp = true
  app.startClientRegions()

  annotatedSiteEnvoy = window.initClientCommunicator()

  new ClientRouter controller: new ClientController annotatedSiteEnvoy

  FactlinkApp.clientCloseDiscussionModalInitializer annotatedSiteEnvoy
  app.vent.on 'close_discussion_modal', ->
    mp_track "Discussion Modal: Close (Button)"
    annotatedSiteEnvoy 'closeModal_noAction'

  annotatedSiteEnvoy 'modalFrameReady', Factlink.Global.can_haz

window.FactlinkAppMode ?= {}
window.FactlinkAppMode.coreInClient = (app) ->
  app.onClientApp = true
  app.startClientRegions()

  annotatedSiteEnvoy = window.initClientCommunicator()

  new ClientRouter controller: new ClientController(annotatedSiteEnvoy)

  FactlinkApp.clientCloseDiscussionModalInitializer annotatedSiteEnvoy
  app.vent.on 'close_discussion_modal', ->
    mp_track "Discussion Modal: Close (Button)"
    annotatedSiteEnvoy 'closeModal_noAction'

  annotatedSiteEnvoy 'modalFrameReady', Factlink.Global.can_haz

Add parens to call with return value

Add parens to call with return value


# If this is your first time writing a language grammar, check out:
#   - http://manual.macromates.com/en/language_grammars

'scopeName': 'source.ait'
'name': 'Ait'
'fileTypes': [
  'ait'
]
'patterns': [
  {
    'match': '^#.*$'
    'name': 'comment.ait'
  }
  {
    'captures':
      '1':
        'name': 'keyword.load.ait'
      '2':
        'name': 'constant.path.ait'
      '3':
        'name': 'keyword.semicolon.ait'
    'match': '^(@.+)\\s(.+)(;)$'
  }
  {
    'captures':
      '1':
        'name': 'constant.definition.ait'
      '2':
        'name': 'keyword.colon.ait'
    'match': '^(.*)(:)\\s'
    'name': 'definition.word.ait'
  }
  {
    'match': '[;\\[\\]()]'
    'name': 'keyword.ait'
  }
  {
    'captures':
      '1':
        'name': 'entity.number.ait'
    'match': '(-?\\d+(\\.\\d+)?)(?![\\w<>+-=*%])'
  }
  {
    'match': '[a-zA-Z0-9<>+-=\\\\*%]+'
    'name': 'entity.word.ait'
  }
  {
    'match': '(".*")'
    'name': 'constant.ait'
  }
]

# If this is your first time writing a language grammar, check out:
#   - http://manual.macromates.com/en/language_grammars

'scopeName': 'source.ait'
'name': 'Ait'
'fileTypes': [
  'ait'
]
'patterns': [
  {
    'match': '#.*$'
    'name': 'comment.ait'
  }
  {
    'captures':
      '1':
        'name': 'keyword.load.ait'
      '2':
        'name': 'constant.path.ait'
      '3':
        'name': 'keyword.semicolon.ait'
    'match': '^(@.+)\\s(.+)(;)$'
  }
  {
    'captures':
      '1':
        'name': 'constant.definition.ait'
      '2':
        'name': 'keyword.colon.ait'
    'match': '^(.*)(:)\\s'
    'name': 'definition.word.ait'
  }
  {
    'match': '[;\\[\\]()]'
    'name': 'keyword.ait'
  }
  {
    'captures':
      '1':
        'name': 'entity.number.ait'
    'match': '(-?\\d+(\\.\\d+)?)(?![\\w<>+-=*%])'
  }
  {
    'match': '[a-zA-Z0-9<>+-=\\\\*%]+'
    'name': 'entity.word.ait'
  }
  {
    'match': '(".*")'
    'name': 'constant.ait'
  }
]

Remove start of line from comment regex in syntax highlighting


path = require 'path'

module.exports = (grunt) ->
  {spawn} = require('./task-helpers')(grunt)

  grunt.registerTask 'codesign', 'Codesign the app', ->
    done = @async()

    if process.platform is 'darwin' and process.env.XCODE_KEYCHAIN
      unlockKeychain (error) ->
        if error?
          done(error)
        else
          signApp(done)
    else
      signApp(done)

  unlockKeychain = (callback) ->
    cmd = 'security'
    {XCODE_KEYCHAIN_PASSWORD, XCODE_KEYCHAIN} = process.env
    args = ['unlock-keychain', '-p', XCODE_KEYCHAIN_PASSWORD, XCODE_KEYCHAIN]
    spawn {cmd, args}, (error) -> callback(error)

  signApp = (callback) ->
    switch process.platform
      when 'darwin'
        cmd = 'codesign'
        args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
        spawn {cmd, args}, (error) -> callback(error)
      when 'win32'
        signtool = process.env.JANKY_SIGNTOOL ? 'signtool'
        cmd = 'taskkill /FIM atom.exe & ' + signtool
        args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
        spawn {cmd, args}, (error) -> callback(error)
      else
        callback()

path = require 'path'

module.exports = (grunt) ->
  {spawn} = require('./task-helpers')(grunt)

  grunt.registerTask 'codesign', 'Codesign the app', ->
    done = @async()

    if process.platform is 'darwin' and process.env.XCODE_KEYCHAIN
      unlockKeychain (error) ->
        if error?
          done(error)
        else
          signApp(done)
    else
      signApp(done)

  unlockKeychain = (callback) ->
    cmd = 'security'
    {XCODE_KEYCHAIN_PASSWORD, XCODE_KEYCHAIN} = process.env
    args = ['unlock-keychain', '-p', XCODE_KEYCHAIN_PASSWORD, XCODE_KEYCHAIN]
    spawn {cmd, args}, (error) -> callback(error)

  signApp = (callback) ->
    switch process.platform
      when 'darwin'
        cmd = 'codesign'
        args = ['-f', '-v', '-s', 'Developer ID Application: GitHub', grunt.config.get('atom.shellAppDir')]
        spawn {cmd, args}, (error) -> callback(error)
      when 'win32'
        spawn {cmd: 'taskkill', args: ['/FIM', 'atom.exe']}, ->
          cmd = process.env.JANKY_SIGNTOOL ? 'signtool'
          args = [path.join(grunt.config.get('atom.shellAppDir'), 'atom.exe')]
          spawn {cmd, args}, (error) -> callback(error)
      else
        callback()

Break up commands into two spawns

Break up commands into two spawns


{_, Document} = require 'atom'

SettingsView = null
settingsView = null

configUri = 'atom://config'

createSettingsView = (state) ->
  SettingsView ?= require './settings-view'
  unless state instanceof Document
    state = _.extend({deserializer: deserializer.name, version: deserializer.version}, state)
    state = atom.site.createDocument(state)
  settingsView = new SettingsView(state)

openPanel = (panelName) ->
  atom.workspaceView.open(configUri)
  settingsView.showPanel(panelName)

deserializer =
  acceptsDocuments: true
  name: 'SettingsView'
  version: 1
  deserialize: (state) -> createSettingsView(state)
atom.deserializers.add(deserializer)

module.exports =
  activate: ->
    atom.project.registerOpener (filePath) ->
      createSettingsView({uri: configUri}) if filePath is configUri

    atom.workspaceView.command 'settings-view:toggle', ->
      openPanel('General')

    atom.workspaceView.command 'settings-view:show-keybindings', ->
      openPanel('Keybindings')

    atom.workspaceView.command 'settings-view:change-themes', ->
      openPane('Themes')

    atom.workspaceView.command 'settings-view:install-packages', ->
      openPanel('Packages')

{_, Document} = require 'atom'

SettingsView = null
settingsView = null

configUri = 'atom://config'

createSettingsView = (state) ->
  SettingsView ?= require './settings-view'
  unless state instanceof Document
    state = _.extend({deserializer: deserializer.name, version: deserializer.version}, state)
    state = atom.site.createDocument(state)
  settingsView = new SettingsView(state)

openPanel = (panelName) ->
  atom.workspaceView.open(configUri)
  settingsView.showPanel(panelName)

deserializer =
  acceptsDocuments: true
  name: 'SettingsView'
  version: 1
  deserialize: (state) -> createSettingsView(state)
atom.deserializers.add(deserializer)

module.exports =
  activate: ->
    atom.project.registerOpener (filePath) ->
      createSettingsView({uri: configUri}) if filePath is configUri

    atom.workspaceView.command 'settings-view:toggle', ->
      openPanel('General')

    atom.workspaceView.command 'settings-view:show-keybindings', ->
      openPanel('Keybindings')

    atom.workspaceView.command 'settings-view:change-themes', ->
      openPanel('Themes')

    atom.workspaceView.command 'settings-view:install-packages', ->
      openPanel('Packages')

Call openPanel instead of openPane

Call openPanel instead of openPane


NotificationPlugin = require "../../notification-plugin"

class Campfire extends NotificationPlugin
  @receiveEvent: (config, event) ->
    # Build the message
    if event.error
      message = "#{event.error.exceptionClass}" + (if event.error.message then ": #{event.error.message}" else "") + " (#{event.error.url})"
    else
      message =  "#{event.trigger.message} in #{event.project.name} (#{event.project.url})" + ( if event.error then " in #{event.error.context} (#{event.error.url})" else "")

    # Build the request
    payload =
      message:
        body: message
        type: "TextMessage"

    url = "https://#{config.authToken}:X@#{config.domain}.campfirenow.com/room/#{config.roomId}/speak.xml"

    # Send the request to campfire
    @request
      .post(url)
      .send(payload)
      .end();

module.exports = Campfire

NotificationPlugin = require "../../notification-plugin"

class Campfire extends NotificationPlugin
  @receiveEvent: (config, event) ->
    # Build the message
    if event.error
      message = "#{event.trigger.message} in #{event.project.name}! #{event.error.exceptionClass}" + (if event.error.message then ": #{event.error.message}" else "") + " (#{event.error.url})"
    else
      message =  "#{event.trigger.message} in #{event.project.name} (#{event.project.url})" + ( if event.error then " in #{event.error.context} (#{event.error.url})" else "")

    # Build the request
    payload =
      message:
        body: message
        type: "TextMessage"

    url = "https://#{config.authToken}:X@#{config.domain}.campfirenow.com/room/#{config.roomId}/speak.xml"

    # Send the request to campfire
    @request
      .post(url)
      .send(payload)
      .end();

module.exports = Campfire

Update format for campfire plugin

Update format for campfire plugin


Augury.Views.Parameters.Edit = Backbone.View.extend(
  initialize: (attrs) ->
    @options = attrs

  events:
    'click button#save': 'save'
    'click button#cancel': 'cancel'
    'change :input': 'changed'
    'focusout :input': 'validate'

  render: ->
    @$el.html JST["admin/templates/parameters/edit"](parameter: @model)
    Backbone.Validation.bind @

    @$('#parameter-data-type').val @model.get('data_type')

    $('#content-header').find('.page-title').text(if @model.isNew() then 'New Parameter' else 'Edit Parameter')

    $('#content-header').find('.page-actions').remove()
    $('#content-header').find('.table-cell').after JST["admin/templates/parameters/back_button"]

    @

  save: (e) ->
    e.preventDefault()
    @model.validate()
    if @model.isValid()
      @model.save {}, success: @saved, error: @displayErrors

  cancel: (e) ->
    e.preventDefault()
    if @model.isNew()
      Augury.parameters.remove @model
    Backbone.history.navigate '/parameters', trigger: true

  saved: ->
    Augury.Flash.success "The parameter has been successfully saved."
)

Augury.Views.Parameters.Edit = Backbone.View.extend(
  initialize: (attrs) ->
    @options = attrs

  events:
    'click button#save': 'save'
    'click button#cancel': 'cancel'
    'change :input': 'changed'
    'focusout :input': 'validate'

  render: ->
    @$el.html JST["admin/templates/parameters/edit"](parameter: @model)
    Backbone.Validation.bind @

    @$('#parameter-data-type').val @model.get('data_type')
    @$('#parameter-data-type').select2()

    $('#content-header').find('.page-title').text(if @model.isNew() then 'New Parameter' else 'Edit Parameter')

    $('#content-header').find('.page-actions').remove()
    $('#content-header').find('.table-cell').after JST["admin/templates/parameters/back_button"]

    @

  save: (e) ->
    e.preventDefault()
    @model.validate()
    if @model.isValid()
      @model.save {}, success: @saved, error: @displayErrors

  cancel: (e) ->
    e.preventDefault()
    if @model.isNew()
      Augury.parameters.remove @model
    Backbone.history.navigate '/parameters', trigger: true

  saved: ->
    Augury.Flash.success "The parameter has been successfully saved."
)

Use select2 for data_type select

Use select2 for data_type select


class window.UserPopoverContentView extends StatisticsPopoverContentView

  templateHelpers: ->
    heading: @model.get('name')

  onRender: ->
    @statisticsRegion.show new UserStatisticsView model: @model
    @ui.buttonRegion.addClass 'statistics-popover-content-button-hidden'

    @_showFollowButton()

  _showFollowButton: ->
    return if @model.is_current_user()

    @buttonRegion.show new FollowUserButtonView user: @model, mini: true
    @ui.buttonRegion.removeClass 'statistics-popover-content-button-hidden'

UserPopoverContentView.makeTooltip = (view, user, options={}) ->
  Backbone.Factlink.makeTooltipForView view,
      positioning: {align: 'left', side: 'bottom'}
      selector: options.selector || '.js-user-link'
      $offsetParent: options.$offsetParent
      tooltipViewFactory: -> new UserPopoverContentView model: user.clone()

Use cloned model for UserPopoverContentView to not run into trouble with urls for following/unfollowing


{WorkspaceView} = require 'atom'
CodeContext = require '../lib/code-context'

describe 'CodeContext', ->
  beforeEach ->
    atom.workspaceView = new WorkspaceView
    textSource = atom.workspace.getActiveEditor()
    @codeContext = new CodeContext('test.txt', '/tmp/test.txt', null)

  describe 'fileColonLine when lineNumber is not set', ->
    it 'returns the full filepath when fullPath is truthy', ->
      expect(@codeContext.fileColonLine()).toMatch("/tmp/test.txt");
      expect(@codeContext.fileColonLine(true)).toMatch("/tmp/test.txt");

    it 'returns only the filename and line number when fullPath is falsy', ->
      expect(@codeContext.fileColonLine(false)).toMatch("test.txt");

  describe 'fileColonLine when lineNumber is set', ->
    it 'returns the full filepath when fullPath is truthy', ->
      @codeContext.lineNumber = 42
      expect(@codeContext.fileColonLine()).toMatch("/tmp/test.txt");
      expect(@codeContext.fileColonLine(true)).toMatch("/tmp/test.txt");

    it 'returns only the filename and line number when fullPath is falsy', ->
      @codeContext.lineNumber = 42
      expect(@codeContext.fileColonLine(false)).toMatch("test.txt");

  describe 'getCode', ->
    it 'returns undefined if no textSource is available', ->
      expect(@codeContext.getCode()).toBe(undefined)

CodeContext = require '../lib/code-context'

describe 'CodeContext', ->
  beforeEach ->
    @codeContext = new CodeContext('test.txt', '/tmp/test.txt', null)

  describe 'fileColonLine when lineNumber is not set', ->
    it 'returns the full filepath when fullPath is truthy', ->
      expect(@codeContext.fileColonLine()).toMatch("/tmp/test.txt");
      expect(@codeContext.fileColonLine(true)).toMatch("/tmp/test.txt");

    it 'returns only the filename and line number when fullPath is falsy', ->
      expect(@codeContext.fileColonLine(false)).toMatch("test.txt");

  describe 'fileColonLine when lineNumber is set', ->
    it 'returns the full filepath when fullPath is truthy', ->
      @codeContext.lineNumber = 42
      expect(@codeContext.fileColonLine()).toMatch("/tmp/test.txt");
      expect(@codeContext.fileColonLine(true)).toMatch("/tmp/test.txt");

    it 'returns only the filename and line number when fullPath is falsy', ->
      @codeContext.lineNumber = 42
      expect(@codeContext.fileColonLine(false)).toMatch("test.txt");

  describe 'getCode', ->
    it 'returns undefined if no textSource is available', ->
      expect(@codeContext.getCode()).toBe(undefined)

    it 'returns the text from the textSource when available', ->
      # TODO: Test using an actual editor or a selection?
      dummyTextSource = {}
      dummyTextSource.getText = ->
        "print 'hello world!'"
      @codeContext.textSource = dummyTextSource
      code = @codeContext.getCode()

      expect(typeof code).toEqual('string')
      expect(code).toMatch("print 'hello world!'")

Add a new spec for testing getCode()

Add a new spec for testing getCode()


{View} = require 'atom'
MarkerView = require './marker-view'
module.exports =
class MinimapSelectionView extends View
  markers: []
  @content: ->
    @div class: 'minimap-selection'

  initialize: (@minimapView) ->
    @subscribe @minimapView.editorView, "selection:changed", @handleSelection

  attach: ->
    @minimapView.miniUnderlayer.append(this)
    @handleSelection()

  destroy: ->
    @detach()
    @unsubscribe()
    @minimapView = null

  handleSelection: =>
    @removeMarkers()

    {editor} = @minimapView

    return if editor.getSelection().isEmpty()

    for selection in editor.getSelections()
      marker = new MarkerView(editorView: @minimapView, marker: selection.marker)
      @markers.push marker
      @append marker.element

  removeMarkers: ->
    return unless @markers?
    return if @markers.length is 0
    marker.element.remove() for marker in @markers
    marker = null
    @markers = []

{View} = require 'atom'
MarkerView = require './marker-view'
module.exports =
class MinimapSelectionView extends View
  decorations: []
  @content: ->
    @div class: 'minimap-selection'

  initialize: (@minimapView) ->
    @subscribe @minimapView.editorView, "selection:changed", @handleSelection
    @subscribe @minimapView.editorView, "cursor-added", @handleSelection
    @subscribe @minimapView.editorView, "cursor-moved", @handleSelection
    @subscribe @minimapView.editorView, "cursor-removed", @handleSelection

  attach: ->
    @minimapView.miniUnderlayer.append(this)
    @handleSelection()

  destroy: ->
    @detach()
    @unsubscribe()
    @minimapView = null

  handleSelection: =>
    @removeDecorations()

    {editor} = @minimapView

    return if editor.getSelection().isEmpty()

    for selection in editor.getSelections()
      @decorations.push @minimapView.decorateMarker(selection.marker, type: 'highlight-under', scope: '.editor .selection .region')

  removeDecorations: ->
    return if @decorations.length is 0
    decoration.destroy() for decoration in @decorations
    @decorations = []

Implement support for the new minimap decoration API


angular.module('doubtfire.units.states.task-inbox', [
  # 'doubtfire.units.states.task-inbox.task-commenter'
  # 'doubtfire.units.states.task-inbox.task-submission'
])

#
# Teacher child state for units
#
.config(($stateProvider) ->
  $stateProvider.state 'units#tasks', {
    parent: 'units#index'
    url: '/tasks/:taskId'
    views:
      unitIndex:
        templateUrl: "units/states/task-inbox/task-inbox.tpl.html"
        controller: "UnitTaskInboxFeedback"
    data:
      task: "Task Inbox"
      pageTitle: "_Home_"
      roleWhitelist: ['Tutor', 'Convenor', 'Admin']
   }
)

.controller('UnitTaskInboxFeedback', ($scope) ->

)

angular.module('doubtfire.units.states.task-inbox', [
  # 'doubtfire.units.states.task-inbox.task-commenter'
])

#
# Teacher child state for units
#
.config(($stateProvider) ->
  $stateProvider.state 'units#tasks', {
    parent: 'units#index'
    url: '/tasks/:taskId'
    views:
      unitIndex:
        templateUrl: "units/states/task-inbox/task-inbox.tpl.html"
        controller: "UnitTaskInboxFeedback"
    data:
      task: "Task Inbox"
      pageTitle: "_Home_"
      roleWhitelist: ['Tutor', 'Convenor', 'Admin']
   }
)

.controller('UnitTaskInboxFeedback', ($scope, $state, $stateParams) ->
  setTaskIdUrlParm = (taskId) ->
    # Change URL of new task without notify
    $state.go('.', {taskId: taskId}, {notify: false})

  if _.isNumber($stateParams.taskId)
    $scope.selectedTask = _.find($scope.unit.tasks, {id: $stateParams.taskId})

  $scope.$watch 'selectedTask', (newTask) ->
    if newTask?
      setTaskIdUrlParm(newTask.id)
    else
      setTaskIdUrlParm(null)
)

ENHANCE: Allow usage of task inbox task ID URL parameter


angular.module('browser').
factory('Browser', ->
  return class Browser
    @prefixs:  ['webkit', 'Moz', 'ms', 'o', 'khtml']

    @window:   window
    @element:  window.document.documentElement
    @body:     window.document.getElementsByTagName('body')[0]

    @height: ->
      @window.innerHeight   or
      @element.clientHeight or
      @body.clientHeight

    @width: ->
      @window.innerWidth   or
      @element.clientWidth or
      @body.clientWidth

    @haveTransform: ->
      return @testCSSProp('transform')

    @title: (string)->
      return string[0].toUpperCase() + string[1..].toLowerCase()

    @testCSSProp: (name)->
      if @body.style[name]?
        return true

      name = @title(name)

      if @body.style[name]?
        return true

      for prefix in @prefixs
        if @body.style["#{prefix}#{name}"]?
          return true
      return false
)

angular.module('browser').
factory('Browser', ->
  return class Browser
    @prefixs:  ['webkit', 'Moz', 'ms', 'o', 'khtml']

    @window:   window
    @element:  window.document.documentElement
    @body:     window.document.getElementsByTagName('body')[0]

    @_height: ->
      @window.innerHeight   or
      @element.clientHeight or
      @body.clientHeight

    @height: ->
      if window.screen? and window.screen.availHeight?
        return window.screen.availHeight
      else
        return @_height()

    @_width: ->
      @window.innerWidth   or
      @element.clientWidth or
      @body.clientWidth

    @width: ->
      if window.screen? and window.screen.availWidth?
        return window.screen.availWidth
      else
        return @_width()

    @haveTransform: ->
      return @testCSSProp('transform')

    @title: (string)->
      return string[0].toUpperCase() + string[1..].toLowerCase()

    @testCSSProp: (name)->
      if @body.style[name]?
        return true

      name = @title(name)

      if @body.style[name]?
        return true

      for prefix in @prefixs
        if @body.style["#{prefix}#{name}"]?
          return true
      return false
)

Improve width and height detection.

Improve width and height detection.


module.exports = (grunt) ->
  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')

    coffee:
      glob_to_multiple:
        expand: true
        cwd: 'src'
        src: ['**/*.coffee']
        dest: 'lib'
        ext: '.js'

    coffeelint:
      options:
        no_empty_param_list:
          level: 'error'
        max_line_length:
          level: 'ignore'
        indentation:
          level: 'ignore'

      src: ['src/*.coffee']
      test: ['spec/*.coffee']
      gruntfile: ['Gruntfile.coffee']

    shell:
      test:
        command: 'node --harmony_collections node_modules/.bin/jasmine-focused --coffee --captureExceptions spec'
        options:
          stdout: true
          stderr: true
          failOnError: true

  grunt.loadNpmTasks('grunt-contrib-coffee')
  grunt.loadNpmTasks('grunt-shell')
  grunt.loadNpmTasks('grunt-coffeelint')

  grunt.registerTask 'clean', -> require('rimraf').sync('lib')
  grunt.registerTask('lint', ['coffeelint'])
  grunt.registerTask('default', ['coffee', 'lint'])
  grunt.registerTask('test', ['coffee', 'lint', 'shell:test'])

module.exports = (grunt) ->
  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')

    coffee:
      glob_to_multiple:
        expand: true
        cwd: 'src'
        src: ['**/*.coffee']
        dest: 'lib'
        ext: '.js'

    coffeelint:
      options:
        no_empty_param_list:
          level: 'error'
        max_line_length:
          level: 'ignore'
        indentation:
          level: 'ignore'

      src: ['src/*.coffee']
      test: ['spec/*.coffee']
      gruntfile: ['Gruntfile.coffee']

    shell:
      test:
        command: 'node --harmony_collections node_modules/.bin/jasmine-focused --coffee --captureExceptions --forceexit spec'
        options:
          stdout: true
          stderr: true
          failOnError: true

  grunt.loadNpmTasks('grunt-contrib-coffee')
  grunt.loadNpmTasks('grunt-shell')
  grunt.loadNpmTasks('grunt-coffeelint')

  grunt.registerTask 'clean', -> require('rimraf').sync('lib')
  grunt.registerTask('lint', ['coffeelint'])
  grunt.registerTask('default', ['coffee', 'lint'])
  grunt.registerTask('test', ['coffee', 'lint', 'shell:test'])

Add forceexit argument to test command

Add forceexit argument to test command


{View} = require 'atom'

# View to show the grammar name in the status bar.
module.exports =
class GrammarStatusView extends View
  @content: ->
    @a href: '#', class: 'grammar-name inline-block'

  initialize: (@statusBar) ->
    @subscribe @statusBar, 'active-buffer-changed', @updateGrammarText
    @subscribe atom.workspaceView, 'editor:grammar-changed', @updateGrammarText

    @subscribe this, 'click', =>
      atom.workspaceView.trigger('grammar-selector:show')
      false

  attach: ->
    @statusBar.appendLeft(this)

  afterAttach: ->
    @updateGrammarText()

  updateGrammarText: =>
    grammar = atom.workspace.getActiveEditor()?.getGrammar?()
    if grammar?
      if grammar is atom.syntax.nullGrammar
        grammarName = 'Plain Text'
      else
        grammarName = grammar.name
      @text(grammarName).show()
    else
      @hide()

{View} = require 'atom'

# View to show the grammar name in the status bar.
module.exports =
class GrammarStatusView extends View
  @content: ->
    @a href: '#', class: 'grammar-name inline-block'

  initialize: (@statusBar) ->
    @subscribe @statusBar, 'active-buffer-changed', =>
      @updateGrammarText()

    @subscribe atom.workspaceView, 'editor:grammar-changed', =>
      @updateGrammarText()

    @subscribe this, 'click', ->
      atom.workspaceView.trigger('grammar-selector:show')
      false

  attach: ->
    @statusBar.appendLeft(this)

  afterAttach: ->
    @updateGrammarText()

  updateGrammarText: ->
    grammar = atom.workspace.getActiveEditor()?.getGrammar?()
    if grammar?
      if grammar is atom.syntax.nullGrammar
        grammarName = 'Plain Text'
      else
        grammarName = grammar.name
      @text(grammarName).show()
    else
      @hide()

Use skinny arrows in instance methods for consistency


chai = require 'chai'
sinon = require 'sinon'
chai.use require 'sinon-chai'

expect = chai.expect

describe 'jira-linkifier', ->
  beforeEach ->
    @robot =
      respond: sinon.spy()
      hear: sinon.spy()

    require('../src/jira-linkifier')(@robot)

  it 'registers a respond listener', ->
    expect(@robot.respond).to.have.been.calledWith(/hello/)

  it 'registers a hear listener', ->
    expect(@robot.hear).to.have.been.calledWith(/orly/)

chai  = require 'chai'
sinon = require 'sinon'
chai.use require 'sinon-chai'

expect = chai.expect

describe 'jira-linkifier', ->

  beforeEach ->
    @robot =
      respond: sinon.spy()
      hear:    sinon.spy()

    @prefixes = process.env.HUBOT_JIRA_LINKIFIER_PROJECT_PREFIXES = "XXX,YYY,ZZZ"
    @jiraUrl  = process.env.HUBOT_JIRA_LINKIFIER_JIRA_URL         = "https://foo.jira.com/browse"

    require('../src/jira-linkifier')(@robot)

  # TODO: figure out how to test the config here?

  # it "reads HUBOT_JIRA_LINKIFIER_JIRA_URL env variable for the base Jira URL", ->
  #   expect(@robot.jiraUrl).to.equal(@jiraUrl)

  # it "reads HUBOT_JIRA_LINKIFIER_PROJECT_PREFIXES env variable for a list of prefixes to match", ->
  #   expect(@robot.jiraUrl).to.equal(@prefixes)

  it "registers a hear to listener for matching patterns like '<prefix>-<numbers>'", ->
    ticketRegExp = new RegExp "(^|\\s+)(XXX|YYY|ZZZ)-[0-9]+($|\\s+)", "gi"
    expect(@robot.hear).to.have.been.calledWith(ticketRegExp)

  it "registers a respond listener for 'jl url", ->
    expect(@robot.respond).to.have.been.calledWith(/jl url/i)

  it "registers a respond listener for 'jl prefixes", ->
    expect(@robot.respond).to.have.been.calledWith(/jl prefixes/i)

Add basic unit tests for the hear & respond handlers

Basic tests to make sure that the listerners for the various
commands are registered.

Trying to see about testing that the config env vars are loaded
as expected, but that's not quite right?  Left some commented
lines in to remind myself to look into it.


express = require 'express'
assets = require 'connect-assets'
stylus = require 'stylus'
session = require 'express-session'
cookieParser = require 'cookie-parser'
bodyParser = require 'body-parser'
db = require './models'

#### Basic application initialization
# Create app instance
app = express()

# Define port to listen
app.port = process.env.PORT or process.env.VMC_APP_PORT or 3000

#### Database connection
db.sequelize
  .sync force: no
  .complete (err) ->
    throw err if err?

# Store database connection in shared variable
app.set 'models', db

#### View initialization
# Add Connect Assets.
#app.use assets(paths: ["assets/js"
#                       "assets/css"
#                       "public/vendor/bootstrap-stylus/stylus"
#                       "public/vendor"])

# Set the public folder as static assets.
app.use express.static(process.cwd() + '/public')

# Express Session
console.log "setting session/cookie"
app.use cookieParser()
app.use session(
  secret: "** CHANGE ** ME **"
  key: "sid"
  cookie:
    secure: true
)

# Set View Engine.
app.set 'view engine', 'jade'

# Parses JSON or XML bodies into `req.body` object
app.use bodyParser()

#### Finalization
# Initialize routes
routes = require './routes'
routes app

# Export application object
module.exports = app

express = require 'express'
assets = require 'connect-assets'
stylus = require 'stylus'
session = require 'express-session'
cookieParser = require 'cookie-parser'
bodyParser = require 'body-parser'
db = require './models'

#### Basic application initialization
# Create app instance
app = express()

# Define port to listen
app.port = process.env.PORT or process.env.VMC_APP_PORT or 3000

#### Database connection
db.sequelize
  .sync force: no
  .complete (err) ->
    throw err if err?

# Store database connection in shared variable
app.set 'models', db

#### View initialization
# Add Connect Assets.
#app.use assets(paths: ["assets/js"
#                       "assets/css"
#                       "public/vendor/bootstrap-stylus/stylus"
#                       "public/vendor"])

# Set the public folder as static assets.
app.use express.static(process.cwd() + '/public')

# Express Session
console.log "setting session/cookie"
app.use cookieParser()
app.use session(
  secret: "** CHANGE ** ME **"
  key: "sid"
  cookie:
    secure: true
)

# Set View Engine.
app.set 'view engine', 'jade'

# Parses JSON or XML bodies into `req.body` object
app.use bodyParser.json()

#### Finalization
# Initialize routes
routes = require './routes'
routes app

# Export application object
module.exports = app

Fix deprecation warning with bodyParser middleware


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$ ->
  $(".report_reason input").removeAttr("required")
  do update_reason = ->
    if $(".report_greens input:checked").val() == "Summer"
      $(".report_reason").hide()
    else
      $(".report_reason").show()

  $(".report_greens input").on "change", update_reason

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
$ ->
  $(".report_reason input, .report_greens input").removeAttr("required")

  do toggle_fields_for_greens = ->
    if $(".report_greens input:checked").val() == "Summer" or $(".report_greens").is(":hidden")
      $(".report_reason").hide()
    else
      $(".report_reason").show()

  do toggle_fields_for_status = ->
    if $(".report_status input:checked").val() == "Closed"
      $(".report_greens").hide()
    else
      $(".report_greens").show()

  $(".report_status input").on "change", ->
    toggle_fields_for_status()
    toggle_fields_for_greens()
  $(".report_greens input").on "change", toggle_fields_for_greens

Change UI to only require weather if closed.

Which greens are in play doesn't apply if the course isn't open, so stop
asking for it.


module.exports =
  findMisspellings: (text) ->
    wordRegex = /(?:^|\s)([a-zA-Z]+)(?=\s|\.|$)/g
    row = 0
    misspellings = []
    for line in text.split('\n')
      while matches = wordRegex.exec(line)
        word = matches[1]
        continue unless $native.isMisspelled(word)
        startColumn = matches.index + matches[0].length - word.length
        endColumn = startColumn + word.length
        misspellings.push([[row, startColumn], [row, endColumn]])
      row++
    callTaskMethod('misspellingsFound', misspellings)

module.exports =
  findMisspellings: (text) ->
    wordRegex = /(?:^|\s)([a-zA-Z']+)(?=\s|\.|$)/g
    row = 0
    misspellings = []
    for line in text.split('\n')
      while matches = wordRegex.exec(line)
        word = matches[1]
        continue unless $native.isMisspelled(word)
        startColumn = matches.index + matches[0].length - word.length
        endColumn = startColumn + word.length
        misspellings.push([[row, startColumn], [row, endColumn]])
      row++
    callTaskMethod('misspellingsFound', misspellings)

Include apostrophe in word regex

Include apostrophe in word regex


'use strict'

{Document, utils} = Neft

VIEWS_CACHE_FILE = 'tmp/views.json'

loaded = false

exports.uid = do (i = 0) -> -> "index_#{i++}.html"

exports.createView = do ->
    getViewPath = (viewUid) ->
        "tmp/views/#{viewUid}.json"

    if utils.isNode
        (html, viewUid = exports.uid()) ->
            loaded = true
            view = Document.fromHTML viewUid, html
            Document.parse view
            view
    else
        cache = require VIEWS_CACHE_FILE
        if utils.isClient and modules?
            Document.Scripts.scriptFiles = modules
        for _, json of cache
            Document.fromJSON json
        (html, viewUid = exports.uid()) ->
            unless loaded
                loaded = true
            view = Document._files[viewUid]
            view

exports.renderParse = (view, opts) ->
    view.render opts?.props, opts?.storage, opts?.source
    view.revert()
    view.render opts?.props, opts?.storage, opts?.source

if utils.isNode
    process.on 'exit', ->
        unless loaded
            return
        fs = require 'fs-extra'
        try
            fs.outputFileSync VIEWS_CACHE_FILE, JSON.stringify(Document._files)
        catch err
            console.error err

'use strict'

{Document, utils} = Neft

VIEWS_CACHE_FILE = 'tmp/views.json'

loaded = false

exports.uid = do (i = 0) -> -> "index_#{i++}.html"

exports.createView = do ->
    getViewPath = (viewUid) ->
        "tmp/views/#{viewUid}.json"

    if utils.isNode
        (html, viewUid = exports.uid()) ->
            loaded = true
            view = Document.fromHTML viewUid, html
            Document.parse view
            json = JSON.stringify view
            Document.fromJSON json
    else
        cache = require VIEWS_CACHE_FILE
        if utils.isClient and modules?
            Document.Scripts.scriptFiles = modules
        for _, json of cache
            Document.fromJSON json
        (html, viewUid = exports.uid()) ->
            unless loaded
                loaded = true
            view = Document._files[viewUid]
            view

exports.renderParse = (view, opts) ->
    view.render opts?.props, opts?.storage, opts?.source
    view.revert()
    view.render opts?.props, opts?.storage, opts?.source

if utils.isNode
    process.on 'exit', ->
        unless loaded
            return
        fs = require 'fs-extra'
        try
            fs.outputFileSync VIEWS_CACHE_FILE, JSON.stringify(Document._files)
        catch err
            console.error err

Document toJSON unit tests added

Document toJSON unit tests added


###
    Copyright 2015, Quixey Inc.
    All rights reserved.

    Licensed under the Modified BSD License found in the
    LICENSE file in the root directory of this source tree.
###

Tinytest.add "denormalization A -> B", (test) ->
    bar = new $$.Bar
    foo = new $$.Foo
    foo.insert()

    console.log 1
    try
        console.log 'n =', bar.numberOfFoosWithAEqualTo4()
        console.log 2
        foo.a(4)
        foo.save()
        console.log 'n =', bar.numberOfFoosWithAEqualTo4()
        console.log 3
    catch e
        console.error e

###
    Copyright 2015, Quixey Inc.
    All rights reserved.

    Licensed under the Modified BSD License found in the
    LICENSE file in the root directory of this source tree.
###

cleanUp = ->
    if Meteor.isServer
        $$.Foo.fetch().forEach (foo) -> foo.remove()
        $$.Bar.fetch().forEach (bar) -> bar.remove()
    else
        a = new J.AutoVar -> $$.Foo.fetch()
        a.get().forEach (foo) ->
            foo.remove()
        a = new J.AutoVar -> $$.Bar.fetch()
        a.get().forEach (bar) ->
            bar.remove()

Tinytest.add "Denormalization - A -> B", (test) ->
    bar = new $$.Bar
    if Meteor.isServer
        foo = new $$.Foo
        foo.insert()

        beforeCount = bar.numberOfFoosWithAEqualTo4()
        foo.a(4)
        foo.save()
        test.equals bar.numberOfFoosWithAEqualTo4(), beforeCount + 1, "should have 1 more Foo instance with a == 4"
    else
        a = new J.AutoVar -> bar.numberOfFoosWithAEqualTo4()
        foo = new $$.Foo
        foo.insert()

        beforeCount =  a.get()
        foo.a(4)
        foo.save()
        test.equals a.get(), beforeCount + 1, "should have 1 more Foo instance with a == 4"
    foo.remove()

Tinytest.add "Model - static field bindings", (test) ->
    if Meteor.isServer
        foo = new $$.Foo
        a = foo.a
        a()
        foo.a()
        test.equals a(), foo.a()

Tinytest.add "Model - reactive field bindings", (test) ->
    if Meteor.isServer
        bar = new $$.Bar
        n = bar.numberOfFoosWithAEqualTo4
        bar.numberOfFoosWithAEqualTo4()
        n()
        test.equals bar.numberOfFoosWithAEqualTo4(), n()

Add some more basic tests on denorm and field bindings


Declaration = require('../declaration')

class Filter extends Declaration
  @names = ['filter']

  # Check is it Internet Explorer filter
  check: (decl) ->
    v = decl.value
    v.toLowerCase().indexOf('alpha(') == -1 and v.indexOf('DXImageTransform.Microsoft') == -1

module.exports = Filter

Fix Holy 80 columns line

Fix Holy 80 columns line


module.exports = (grunt) ->
  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')

    coffee:
      glob_to_multiple:
        expand: true
        cwd: 'src'
        src: ['*.coffee']
        dest: 'lib'
        ext: '.js'

    coffeelint:
      options:
        no_empty_param_list:
          level: 'error'
        max_line_length:
          level: 'ignore'

      src: ['src/*.coffee']
      test: ['spec/*.coffee']
      gruntfile: ['Gruntfile.coffee']

    shell:
      test:
        command: 'node_modules/.bin/jasmine-focused --coffee --captureExceptions spec'
        options:
          stdout: true
          stderr: true
          failOnError: true

  grunt.loadNpmTasks('grunt-contrib-coffee')
  grunt.loadNpmTasks('grunt-shell')
  grunt.loadNpmTasks('grunt-coffeelint')

  grunt.registerTask 'clean', ->
    rm = (pathToDelete) ->
      grunt.file.delete(pathToDelete) if grunt.file.exists(pathToDelete)
    rm('lib')

  grunt.registerTask('lint', ['coffeelint'])
  grunt.registerTask('test', ['default', 'shell:test'])
  grunt.registerTask('default', ['coffee', 'lint'])
  grunt.registerTask('prepublish', ['clean', 'coffee', 'lint'])

path = require('path')

module.exports = (grunt) ->
  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')

    coffee:
      glob_to_multiple:
        expand: true
        cwd: 'src'
        src: ['*.coffee']
        dest: 'lib'
        ext: '.js'

    coffeelint:
      options:
        no_empty_param_list:
          level: 'error'
        max_line_length:
          level: 'ignore'

      src: ['src/*.coffee']
      test: ['spec/*.coffee']
      gruntfile: ['Gruntfile.coffee']

    shell:
      test:
        command: "#{path.resolve('node_modules/.bin/jasmine-focused')} --coffee --captureExceptions spec"
        options:
          stdout: true
          stderr: true
          failOnError: true

  grunt.loadNpmTasks('grunt-contrib-coffee')
  grunt.loadNpmTasks('grunt-shell')
  grunt.loadNpmTasks('grunt-coffeelint')

  grunt.registerTask 'clean', ->
    rm = (pathToDelete) ->
      grunt.file.delete(pathToDelete) if grunt.file.exists(pathToDelete)
    rm('lib')

  grunt.registerTask('lint', ['coffeelint'])
  grunt.registerTask('test', ['default', 'shell:test'])
  grunt.registerTask('default', ['coffee', 'lint'])
  grunt.registerTask('prepublish', ['clean', 'coffee', 'lint'])

Switch appveyor from apm to npm

Switch appveyor from apm to npm


angular.module('kassa').service('SessionService',[
  '$http'
  '$q'
  '$window'
  'UserService'
  ($http, $q, $window, User)->
    currentUser = null

    equal = angular.equals

    setUser = (user)-> currentUser = user

    checkStatus = -> User.find('me').then(setUser)

    signIn = (email, password, rememberMe=true)->
      $http.post('/user/sign_in', user: {email, password, rememberMe}).then checkStatus()

    signOut = ->
      $http.delete('/user/sign_out').then ->
        currentUser = null
        #hacky way of redirecting since base-tag supported routing will hijack this via $location
        $window.location.href = '/user/sign_in'

    #load the current user if signed in and set to promise that will be resolved and watched automatically
    currentUser = checkStatus()

    isCurrentUser = (user)-> equal(currentUser, user)

    {
      checkStatus: checkStatus
      signIn: signIn
      signOut: signOut
      currentUser: (ensurePromise=true)->
        if ensurePromise then $q.when(currentUser) else currentUser
      isCurrentUser: isCurrentUser
    }
])

angular.module('kassa').service('SessionService',[
  '$http'
  '$q'
  '$window'
  'UserService'
  ($http, $q, $window, User)->
    authenticatedUser = null

    equal = angular.equals

    setUser = (user)-> authenticatedUser = user

    checkStatus = -> User.find('me').then(setUser)

    signIn = (email, password, rememberMe=true)->
      $http.post('/user/sign_in', user: {email, password, rememberMe}).then checkStatus()

    signOut = ->
      $http.delete('/user/sign_out').then ->
        authenticatedUser = null
        #hacky way of redirecting since base-tag supported routing will hijack this via $location
        $window.location.href = '/user/sign_in'

    isCurrentUser = (user)-> equal(authenticatedUser, user)

    currentUser = (ensurePromise=true)->
      if ensurePromise then $q.when(authenticatedUser) else authenticatedUser

    isAdmin = -> authenticatedUser.admin

    #load the current user if signed in and set to promise that will be resolved and watched automatically
    authenticatedUser = checkStatus()

    {checkStatus, signIn, signOut, isCurrentUser, currentUser, isAdmin}
])

Refactor session service, add isAdmin() to check for admin status of current authenticated user


should = require('chai').should()

describe 'grunt-node-gyp', ->
	describe 'configure', ->
		it 'should configure a release build by default', ->
			;

		it 'should configure a debug build if the debug option is passed', ->
			;

		it 'should fail if there is no binding.gyp', ->
			;

	describe 'build', ->
		it 'should build a release build by default', ->
			;

		it 'should build a debug build if the debug option is passed', ->
			;

		it 'should fail if there are no build files', ->
			;

	describe 'clean', ->
		it 'should remove the build directory', ->
			;

	describe 'rebuild', ->
		it 'should rebuild a release build by default', ->
			;

		it 'should rebuild a debug build if the debug option is passed', ->
			;

		it 'should fail if there is no binding.gyp', ->
			;

	describe 'default (no command passed)', ->
		it 'should rebuild a release build by default', ->
			;

		it 'should rebuild a debug build if the debug option is passed', ->
			;

		it 'should fail if there is no binding.gyp', ->
			;

should = require('chai').should()
grunt = require 'grunt'

gruntOptions =
	gruntfile: __dirname + '/support/Gruntfile.coffee'

execGruntTask = (task, callback) ->
	grunt.tasks 'gyp:' + task, gruntOptions, ->
		callback()

describe 'grunt-node-gyp', ->
	describe 'configure', ->
		it 'should configure a release build by default', ->
			;

		it 'should configure a debug build if the debug option is passed', ->
			;

		it 'should fail if there is no binding.gyp', ->
			;

	describe 'build', ->
		it 'should build a release build by default', ->
			;

		it 'should build a debug build if the debug option is passed', ->
			;

		it 'should fail if there are no build files', ->
			;

	describe 'clean', ->
		it 'should remove the build directory', ->
			;

	describe 'rebuild', ->
		it 'should rebuild a release build by default', ->
			;

		it 'should rebuild a debug build if the debug option is passed', ->
			;

		it 'should fail if there is no binding.gyp', ->
			;

	describe 'default (no command passed)', ->
		it 'should rebuild a release build by default', ->
			;

		it 'should rebuild a debug build if the debug option is passed', ->
			;

		it 'should fail if there is no binding.gyp', ->
			;

Add helper function execGruntTask(task, callback)


define [
  'marionette'
  'cs!collections/content'
  'hbs!templates/workspace/menu/add'
  'hbs!templates/workspace/menu/add-item'
  'bootstrapDropdown'
], (Marionette, allContent, addTemplate, addItemTemplate) ->

  class AddItemView extends Marionette.ItemView
    tagName: 'li'

    template: addItemTemplate

    events:
      'click .add-content-item': 'addItem'

    initialize: (options) ->
      # Remember where this new content should be added
      @context = options.context

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

      # No context means we are adding to the workspace and all content is allowed
      if @context
        if not (@model.id in @context.accept) # @model.id is a mediaType
          throw new Error 'BUG: Trying to add a type of content that is not allowed to be in this thing'

      model = new (@model.get('modelType'))()
      allContent.add(model)

      # Add the model to the context
      if @context
        @context.addChild(model)

      # Begin editing certain media as soon as they are added.
      model.addAction?()

  return class AddView extends Marionette.CompositeView
    initialize: (options) ->
      # Remember where this new content should be added
      @context = options.context

    template: addTemplate
    itemView: AddItemView
    itemViewContainer: '.btn-group > ul'
    tagName: 'span'

    itemViewOptions: (model, index) ->
      return {context: @context}

define [
  'marionette'
  'cs!collections/content'
  'hbs!templates/workspace/menu/add'
  'hbs!templates/workspace/menu/add-item'
  'bootstrapDropdown'
], (Marionette, allContent, addTemplate, addItemTemplate) ->

  class AddItemView extends Marionette.ItemView
    tagName: 'li'

    template: addItemTemplate

    events:
      'click .add-content-item': 'addItem'

    initialize: (options) ->
      # Remember where this new content should be added
      @context = options.context

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

      # No context means we are adding to the workspace and all content is allowed
      if @context
        if not (@model.id in @context.accept) # @model.id is a mediaType
          throw new Error 'BUG: Trying to add a type of content that is not allowed to be in this thing'

      model = new (@model.get('modelType'))()
      model.set('title', 'Untitled Content')
      allContent.add(model)

      # Add the model to the context
      if @context
        @context.addChild(model)

      # Begin editing certain media as soon as they are added.
      model.addAction?()

  return class AddView extends Marionette.CompositeView
    initialize: (options) ->
      # Remember where this new content should be added
      @context = options.context

    template: addTemplate
    itemView: AddItemView
    itemViewContainer: '.btn-group > ul'
    tagName: 'span'

    itemViewOptions: (model, index) ->
      return {context: @context}

Add a default title for new books or content


angular.module('doubtfire.admin.states.users', [])

#
# Administration panel for all doubtfire users
#
.config((headerServiceProvider) ->
  usersAdminViewStateData =
    url: "/admin/users"
    views:
      main:
        controller: "AdministerUsersCtrl"
        templateUrl: "users/states/users/users.tpl.html"
    data:
      pageTitle: "_Users Administration_"
      roleWhitelist: ['Admin', 'Convenor']
  headerServiceProvider.state "admin/users", usersAdminViewStateData
)

.controller("AdministerUsersCtrl", ($scope, $modal, User, ExternalName, alertService, CsvResultModal, UserSettingsModal) ->
  $scope.file_data =
    onBatchUserSuccess: (response) ->
      CsvResultModal.show "User CSV import results", response
      $scope.users = User.query()
    batchUserUrl: User.csvUrl()
    batchUserFiles: { file: { name: 'CSV File', type: 'csv' } }

  $scope.users = User.query()

  # Table sort details
  $scope.sortOrder = "id"

  # Pagination details
  $scope.currentPage = 1
  $scope.maxSize = 5
  $scope.pageSize = 15

  # Get the confugurable, external name of Doubtfire
  $scope.externalName = ExternalName

  # User settings/create modal
  $scope.showUserModal = (user) ->
    # If we're given a user, show that user, else create a new one
    userToShow = if user? then user else new User { }
    UserSettingsModal.show userToShow
)

angular.module('doubtfire.admin.states.users', [])

#
# Administration panel for all doubtfire users
#
.config((headerServiceProvider) ->
  usersAdminViewStateData =
    url: "/admin/users"
    views:
      main:
        controller: "AdministerUsersCtrl"
        templateUrl: "admin/states/users/users.tpl.html"
    data:
      pageTitle: "_Users Administration_"
      roleWhitelist: ['Admin', 'Convenor']
  headerServiceProvider.state "admin/users", usersAdminViewStateData
)

.controller("AdministerUsersCtrl", ($scope, $modal, User, ExternalName, alertService, CsvResultModal, UserSettingsModal) ->
  $scope.file_data =
    onBatchUserSuccess: (response) ->
      CsvResultModal.show "User CSV import results", response
      $scope.users = User.query()
    batchUserUrl: User.csvUrl()
    batchUserFiles: { file: { name: 'CSV File', type: 'csv' } }

  $scope.users = User.query()

  # Table sort details
  $scope.sortOrder = "id"

  # Pagination details
  $scope.currentPage = 1
  $scope.maxSize = 5
  $scope.pageSize = 15

  # Get the confugurable, external name of Doubtfire
  $scope.externalName = ExternalName

  # User settings/create modal
  $scope.showUserModal = (user) ->
    # If we're given a user, show that user, else create a new one
    userToShow = if user? then user else new User { }
    UserSettingsModal.show userToShow
)

Fix incorrect template for user admin

FIX: Fix incorrect template for user admin


# it's critical that these bindings be loaded after those snippets-1 so they
# are later in the cascade, hence breaking the keymap into 2 files

'atom-text-editor:not([mini])':
  'tab': 'snippets:next-tab-stop'
  'shift-tab': 'snippets:previous-tab-stop'
  'alt-shift-s': 'snippets:available'

'.available-snippets atom-text-editor[mini]':
  'alt-shift-s': 'snippets:available'

Remove alt-shift-s bindings that conflict with typing AltGraph chars

Signed-off-by: Max Brunsfeld <78036c9b69b887700d5846f26a788d53b201ffbb@github.com>


AppMenu         = require "./AppMenu"
AppWindow       = require "./AppWindow"

fs              = require "fs"
ipc             = require "ipc"
EventEmitter    = require "eventemitter3"
{Disposable}    = require "event-kit"

assign          = (dest, objects...) ->
    for o in objects
        dest[k] = v for k, v of o
    dest
module.exports = class Application extends EventEmitter

    windows         : null
    options         : null
    packageJson     : null

    constructor     : (options = {}) ->
        super()

        @windows        = []
        @options        = options
        @packageJson    = require "../package.json"

        new AppWindow assign {}, options,
            url     : "file://#{__dirname}/../renderer/index.html"

        @handleEvents()

    addWindow       : (window) ->
        @windows.push window
        return

    removeWindow    : (window) ->
        @windows.splice index, 1 for index, w of @windows when w is window
        return

    handleEvents    : ->
        ipc.on "open", (e, options) ->
            options ?= @_opts
            new AppWindow(options)

AppMenu         = require "./AppMenu"
AppWindow       = require "./AppWindow"

fs              = require "fs"
ipc             = require "ipc"
EventEmitter    = require "eventemitter3"
{Disposable}    = require "event-kit"

assign          = (dest, objects...) ->
    for o in objects
        dest[k] = v for k, v of o
    dest
module.exports = class Application extends EventEmitter

    windows         : null
    options         : null
    packageJson     : null

    constructor     : (options = {}) ->
        super()

        @windows        = []
        @options        = options
        @packageJson    = require "../package.json"

        new AppWindow assign {}, options,
            url     : "file://#{__dirname}/../renderer/index.html"

        @handleEvents()

    handleEvents    : ->
        ipc.on "open", (e, options) ->
            options ?= @options
            new AppWindow(options)

    addWindow       : (window) ->
        @windows.push window
        return

    removeWindow    : (window) ->
        @windows.splice index, 1 for index, w of @windows when w is window
        return

:lipstick: Move `handleEvents` method definition  under the `constructor`

Method grouping


`import Ember from 'ember'`

manager = (headTag) ->
  @headTag = headTag if headTag

  return this

manager.prototype.getHeadTag = ->
  @headTag || document.getElementsByTagName('head')[0]

manager.prototype.setFavicon = (href) ->
  head = @getHeadTag()

  if oldLink = @getLinkTag()
    head.removeChild(oldLink)

  link = @createLinkTag()
  head.appendChild(link)
  link.setAttribute('href', href)

manager.prototype.getLinkTag = ->
  links = @getHeadTag().getElementsByTagName('link')
  if links.length
    for link in links
      if (link.getAttribute('rel') || '').trim() == 'icon'
        return link

manager.prototype.createLinkTag = ->
  link = document.createElement('link')
  link.setAttribute('rel', 'icon')
  link.setAttribute('type', 'image/png')
  @getHeadTag().appendChild(link)

`export default manager`

`import Ember from 'ember'`

manager = (headTag) ->
  @headTag = headTag if headTag

  return this

manager.prototype.getHeadTag = ->
  @headTag || document.getElementsByTagName('head')[0]

manager.prototype.setFavicon = (href) ->
  head = @getHeadTag()

  if oldLink = @getLinkTag()
    head.removeChild(oldLink)

  link = @createLinkTag()
  head.appendChild(link)

  link.setAttribute('href', href)
  setTimeout ->
    link.setAttribute('href', href)
  , 1

manager.prototype.getLinkTag = ->
  links = @getHeadTag().getElementsByTagName('link')
  if links.length
    for link in links
      if (link.getAttribute('rel') || '').trim() == 'icon'
        return link

manager.prototype.createLinkTag = ->
  link = document.createElement('link')
  link.setAttribute('rel', 'icon')
  link.setAttribute('type', 'image/png')
  @getHeadTag().appendChild(link)

`export default manager`

Set href on favicon <link> tag second time in a timeout

This somehow fixes chrome inconsistencies when changing favicon