grammarListView = null
grammarStatusView = null

module.exports =
  config:
    showOnRightSideOfStatusBar:
      type: 'boolean'
      default: true

  activate: ->
    @commandDisposable = atom.commands.add('atom-text-editor', 'grammar-selector:show', createGrammarListView)
    atom.packages.onDidActivateAll(createGrammarStatusView)

  deactivate: ->
    @commandDisposable.dispose()
    grammarStatusView?.destroy()
    grammarStatusView = null
    grammarListView?.destroy()
    grammarListView = null

createGrammarListView = ->
  editor = atom.workspace.getActiveTextEditor()
  if editor?
    GrammarListView = require './grammar-list-view'
    grammarListView ?= new GrammarListView(editor)
  grammarListView.attach()

createGrammarStatusView = ->
  statusBar = atom.views.getView(atom.workspace).querySelector("status-bar")
  if statusBar?
    GrammarStatusView = require './grammar-status-view'
    grammarStatusView = new GrammarStatusView().initialize(statusBar)
    grammarStatusView.attach()

commandDisposable = null
grammarListView = null
grammarStatusView = null

module.exports =
  config:
    showOnRightSideOfStatusBar:
      type: 'boolean'
      default: true

  activate: ->
    commandDisposable = atom.commands.add('atom-text-editor', 'grammar-selector:show', createGrammarListView)
    atom.packages.onDidActivateAll(createGrammarStatusView)

  deactivate: ->
    commandDisposable?.dispose()
    commandDisposable = null

    grammarStatusView?.destroy()
    grammarStatusView = null

    grammarListView?.destroy()
    grammarListView = null

createGrammarListView = ->
  editor = atom.workspace.getActiveTextEditor()
  if editor?
    GrammarListView = require './grammar-list-view'
    grammarListView ?= new GrammarListView(editor)
  grammarListView.toggle()

createGrammarStatusView = ->
  statusBar = atom.views.getView(atom.workspace).querySelector("status-bar")
  if statusBar?
    GrammarStatusView = require './grammar-status-view'
    grammarStatusView = new GrammarStatusView().initialize(statusBar)
    grammarStatusView.attach()

Call toggle each time command is dispatched


angular.module('impac.filters.moment-date', []).filter('momentDate', ($translate, ImpacTheming) ->
  (date, component) ->

    moment.locale($translate.use().toLowerCase())

    validPeriods = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly', 'default']
    if !_.isEmpty(component) && validPeriods.includes(component.toLowerCase())
      component = 'period-' + component.toLowerCase()

    settings = ImpacTheming.get()
    format = settings.dateFormatterSettings.default
    if settings.dateFormatterSettings.formats && settings.dateFormatterSettings.formats[component]
      format = settings.dateFormatterSettings.formats[component]

    return moment(date).format(format)
)

angular.module('impac.filters.moment-date', []).filter('momentDate', ($translate, ImpacTheming) ->
  (date, component) ->

    moment.locale($translate.use().toLowerCase())

    validPeriods = ['daily', 'weekly', 'monthly', 'quarterly', 'yearly', 'default']
    if !_.isEmpty(component) && _.includes(validPeriods, component.toLowerCase())
      component = 'period-' + component.toLowerCase()

    settings = ImpacTheming.get()
    format = settings.dateFormatterSettings.default
    if settings.dateFormatterSettings.formats && settings.dateFormatterSettings.formats[component]
      format = settings.dateFormatterSettings.formats[component]

    return moment(date).format(format)
)

Refactor using lodash for ie11

Refactor using lodash for ie11


Sprangular.directive 'addressSelection', ->
  restrict: 'E'
  templateUrl: 'addresses/selection.html'
  scope:
    address: '='
    addresses: '='
    countries: '='
    disabled: '=disabledFields'
    submitted: '='
    existingAddress: '='
  controller: ($scope) ->
    $scope.$watch 'addresses', (addresses) ->
      return unless addresses && addresses.length > 0

      found = _.find addresses, (existing) ->
        existing.same($scope.address)

      $scope.toggleExistingAddress() if found

    $scope.toggleExistingAddress = ->
      $scope.existingAddress = !$scope.existingAddress

      if $scope.existingAddress
        $scope.address = $scope.addresses[0]
      else
        $scope.address = new Sprangular.Address()

  link: (element, attrs) ->
    attrs.disabled = false unless attrs.disabled?
    attrs.existingAddress = false unless attrs.existingAddress?

Sprangular.directive 'addressSelection', ->
  restrict: 'E'
  templateUrl: 'addresses/selection.html'
  scope:
    address: '='
    addresses: '='
    countries: '='
    disabled: '=disabledFields'
    submitted: '='
    existingAddress: '='
  controller: ($scope) ->
    $scope.$watch 'addresses', (addresses) ->
      return unless addresses && addresses.length > 0

      found = _.find addresses, (existing) ->
        existing.same($scope.address)

      $scope.toggleExistingAddress() if found

    $scope.toggleExistingAddress = ->
      $scope.existingAddress = !$scope.existingAddress

      if $scope.existingAddress
        $scope.address = $scope.addresses[0]
      else
        $scope.address = new Sprangular.Address()

  compile: (element, attrs) ->
    attrs.existingAddress = 'false' if !attrs.exisitingAddress?

  link: (scope, element, attrs) ->
    attrs.disabled = false unless attrs.disabled?

Add default value for existingAddress attribute in compile stage


# Implements global `ajaxBeforeSend` event.
#
# jQuery already provides a handful of global AJAX events. However,
# there is no global version of `beforeSend`, so `ajaxBeforeSend` is
# added to complement it.
#
# Reference: http://docs.jquery.com/Ajax_Events

# Skip for Zepto which doesn't have ajaxSetup but does already support
# `ajaxBeforeSend`. It'd be better to feature test for the event and
# see if we need to install it.
return unless $.ajaxSetup

# One caveat about using `$.ajaxSetup` is that its easily clobbered.
# If anything else tries to register another global `beforeSend`
# handler, ours will be overriden.
#
# To work around this, register your global `beforeSend` handler with:
#
#     $(document).bind('ajaxBeforeSend', function() {})
#
$.ajaxSetup
  beforeSend: (xhr, settings) ->
    # Skip if global events are disabled
    return unless settings.global

    # Default to document if context isn't set
    element = settings.context || document

    # Provide a global version of the `beforeSend` callback
    event = $.Event 'ajaxBeforeSend'
    $(element).trigger event, [xhr, settings]
    event.result

# Implements global `ajaxBeforeSend` event.
#
# jQuery already provides a handful of global AJAX events. However,
# there is no global version of `beforeSend`, so `ajaxBeforeSend` is
# added to complement it.
#
# Reference: http://docs.jquery.com/Ajax_Events

# Skip for Zepto which doesn't have ajaxSetup but does already support
# `ajaxBeforeSend`. It'd be better to feature test for the event and
# see if we need to install it.
if $.ajaxSetup

  # One caveat about using `$.ajaxSetup` is that its easily clobbered.
  # If anything else tries to register another global `beforeSend`
  # handler, ours will be overriden.
  #
  # To work around this, register your global `beforeSend` handler with:
  #
  #     $(document).bind('ajaxBeforeSend', function() {})
  #
  $.ajaxSetup
    beforeSend: (xhr, settings) ->
      # Skip if global events are disabled
      return unless settings.global

      # Default to document if context isn't set
      element = settings.context || document

      # Provide a global version of the `beforeSend` callback
      event = $.Event 'ajaxBeforeSend'
      $(element).trigger event, [xhr, settings]
      event.result

Make compatible with coffee 1.1.3 bug

Make compatible with coffee 1.1.3 bug


'menu': [
  'label': 'Find'
  'submenu': [
    { 'label': 'Find in Buffer', 'command': 'find-and-replace:show'}
    { 'label': 'Replace in Buffer', 'command': 'find-and-replace:show-replace'}
    { 'label': 'Select Next', 'command': 'find-and-replace:select-next'}
    { 'label': 'Select All', 'command': 'find-and-replace:select-all'}
    { 'type': 'separator' }
    { 'label': 'Find in Project', 'command': 'project-find:show'}
    { 'type': 'separator' }
    { 'label': 'Find Next', 'command': 'find-and-replace:find-next'}
    { 'label': 'Find Previous', 'command': 'find-and-replace:find-previous'}
    { 'label': 'Replace Next', 'command': 'find-and-replace:replace-next'}
    { 'label': 'Replace All', 'command': 'find-and-replace:replace-all'}
    { 'type': 'separator' }
  ]
]

'context-menu':
  '.tree-view > li.directory':
    'Search in this directory': 'project-find:show-in-current-directory'

'menu': [
  'label': 'Find'
  'submenu': [
    { 'label': 'Find in Buffer', 'command': 'find-and-replace:show'}
    { 'label': 'Replace in Buffer', 'command': 'find-and-replace:show-replace'}
    { 'label': 'Select Next', 'command': 'find-and-replace:select-next'}
    { 'label': 'Select All', 'command': 'find-and-replace:select-all'}
    { 'label': 'Toggle Find in Buffer', 'command': 'find-and-replace:toggle'}
    { 'type': 'separator' }
    { 'label': 'Find in Project', 'command': 'project-find:show'}
    { 'label': 'Toggle Find in Project', 'command': 'project-find:toggle'}
    { 'type': 'separator' }
    { 'label': 'Find Next', 'command': 'find-and-replace:find-next'}
    { 'label': 'Find Previous', 'command': 'find-and-replace:find-previous'}
    { 'label': 'Replace Next', 'command': 'find-and-replace:replace-next'}
    { 'label': 'Replace All', 'command': 'find-and-replace:replace-all'}
    { 'type': 'separator' }
  ]
]

'context-menu':
  '.tree-view > li.directory':
    'Search in this directory': 'project-find:show-in-current-directory'

Add toggle menu item for panels

Add toggle menu item for panels

Refs #164


# Description:
#   When you get some bad news sometimes you got to let it out.
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   sheeeit - Display an image or animated gif
#
# Author:
#   danishkhan

sheits = [
  "http://www.circlenoir.com/forums/attachment.php?attachmentid=478&stc=1#.jpg",
  "http://media.skateboard.com.au/forum/images/davis_sheeeit.jpg",
  "http://www.gifsoup.com/webroot/animatedgifs1/2019075_o.gif",
  "http://i417.photobucket.com/albums/pp258/reddreadrevolver/sheeeit.gif",
  "http://behance.vo.llnwd.net/profiles3/111050/projects/252777/1110501249152745.jpg"
]

module.exports = (robot) ->
  robot.hear /sh(e+)(i+)(t+)/, (msg) ->
  msg.send msg.random sheits

Indent msg.send so that we all can Clay. Sheeeeeeeeeit.


{CompositeDisposable} = require 'atom'

module.exports =
class MinimapPigmentsBinding
  constructor: ({@editor, @minimap, @colorBuffer}) ->
    @displayedMarkers = []
    @subscriptions = new CompositeDisposable

    @colorBuffer.initialize().then => @updateMarkers()

    @subscriptions.add @colorBuffer.onDidUpdateColorMarkers => @updateMarkers()

  updateMarkers: ->
    markers = @colorBuffer.findValidColorMarkers()

    for m in @displayedMarkers when m not in markers
      @minimap.removeAllDecorationsForMarker(m.marker)

    for m in markers when m.color?.isValid() and m not in @displayedMarkers
      @minimap.decorateMarker(m.marker, type: 'highlight', color: m.color.toCSS())

    @displayedMarkers = markers

  destroy: ->
    @subscriptions.dispose()

{CompositeDisposable} = require 'atom'

module.exports =
class MinimapPigmentsBinding
  constructor: ({@editor, @minimap, @colorBuffer}) ->
    @displayedMarkers = []
    @subscriptions = new CompositeDisposable

    @colorBuffer.initialize().then => @updateMarkers()

    @subscriptions.add @colorBuffer.editor.displayBuffer.onDidTokenize =>
      @updateMarkers()
    @subscriptions.add @colorBuffer.onDidUpdateColorMarkers =>
      @updateMarkers()

  updateMarkers: ->
    markers = @colorBuffer.findValidColorMarkers()

    for m in @displayedMarkers when m not in markers
      @minimap.removeAllDecorationsForMarker(m.marker)

    for m in markers when m.color?.isValid() and m not in @displayedMarkers
      @minimap.decorateMarker(m.marker, type: 'highlight', color: m.color.toCSS())

    @displayedMarkers = markers

  destroy: ->
    @subscriptions.dispose()

:bug: Fix markers persisting after tokenisation when they should have been hidden


webpackConfig = require('./webpack.config.coffee')
webpackConfig.entry = {}

module.exports = (config)  ->
  config.set
    frameworks: ['jasmine']
    browsers: ['Chrome']

    files: [
      './spec/**/*.coffee'
    ]

    preprocessors:
      './spec/**/*spec.coffee': ['webpack']

    webpack: webpackConfig

    webpackMiddleware:
      noInfo: true

webpackConfig = require('./webpack.config.coffee')
webpackConfig.entry = {}

module.exports = (config)  ->
  config.set
    frameworks: ['jasmine']
    browsers: ['Chrome']

    files: [
      './spec/**/*.coffee'
    ]

    preprocessors:
      './spec/**/*': ['webpack']

    webpack: webpackConfig

    webpackMiddleware:
      noInfo: true

Simplify spec files regex since webpack should be doing all the heavy lifting


Router.configure
	layoutTemplate: 'Layout'

Router.route '/', ->
	return @redirect '/course/si'

Router.route '/si', ->
	return @redirect '/course/si'

Router.route '/tsi', ->
	return @redirect '/course/tsi'

Router.route '/course/:course',
	name: 'course'

	waitOn: ->
		return [
			Meteor.subscribe 'Grade'
			Meteor.subscribe 'userGradeInfo'
		]

	action: ->
		course = @params.course.toLowerCase()
		if course not in ['si', 'tsi']
			return @redirect '/course/si'

		Session.set 'grade', course

		Session.set 'grade-filter-status', @params.query.status

		@render 'Grade'

	fastRender: true

Router.route '/my/:course/:email',
	name: 'my'

	waitOn: ->
		return [
			Meteor.subscribe 'Grade'
			Meteor.subscribe 'userGradeInfo'
		]

	action: ->
		course = @params.course.toLowerCase()
		if course not in ['si', 'tsi']
			return @redirect "/course/si/#{params.email}"

		Session.set 'grade', course

		Session.set 'grade-filter-status', @params.query.status

		@render 'Grade',
		data:
			email: @params.email

	fastRender: true

Router.configure
	layoutTemplate: 'Layout'

Router.route '/', ->
	return @redirect '/course/si'

Router.route '/si', ->
	return @redirect '/course/si'

Router.route '/tsi', ->
	return @redirect '/course/tsi'

Router.route '/course/:course',
	name: 'course'

	waitOn: ->
		return [
			Meteor.subscribe 'Grade'
			Meteor.subscribe 'userGradeInfo'
		]

	action: ->
		course = @params.course.toLowerCase()
		if course not in ['si', 'tsi']
			return @redirect '/course/si'

		Session.set 'grade', course

		Session.set 'grade-filter-status', @params.query.status

		@render 'Grade'

	fastRender: true

Router.route '/my/:course/:email',
	name: 'my'

	waitOn: ->
		return [
			Meteor.subscribe 'Grade'
			Meteor.subscribe 'userGradeInfo', @params.email
		]

	action: ->
		course = @params.course.toLowerCase()
		if course not in ['si', 'tsi']
			return @redirect "/course/si/#{@params.email}"

		Session.set 'grade', course

		Session.set 'grade-filter-status', @params.query.status

		@render 'Grade',
			data:
				email: @params.email

	fastRender: true

Fix bugs with shared url

Fix bugs with shared url


define (require) ->

  Piece = require 'Piece'
  ranks = require 'ranks'

  describe 'Piece', ->

    for rank of ranks
      do (rank) ->
        it "should not throw if rank #{rank}", ->
          expect(->
            new Piece
              rank: rank
              side: 0
          ).to.not.throw()

    it 'should throw if rank is not valid', ->
      expect(->
        new Piece
          rank: 'abc'
          side: 0
      ).to.throw()

    it 'should not throw if side 0 or 1', ->
      expect(->
        new Piece
          rank: '1'
          side: 0
      ).to.not.throw()

      expect(->
        new Piece
          rank: '1'
          side: 1
      ).to.not.throw()

    it 'should throw if side not valid', ->
      expect(->
        new Piece
          rank: '1'
          side: 2
      ).to.throw()

      expect(->
        new Piece
          rank: '1'
          side: -1
      ).to.throw()

define (require) ->

  Piece = require 'Piece'
  ranks = require 'ranks'

  describe 'Piece', ->

    it 'should not throw if rank is valid', ->
      for rank of ranks
        expect(->
          new Piece
            rank: rank
            side: 0
        ).to.not.throw()

    it 'should throw if rank is not valid', ->
      expect(->
        new Piece
          rank: 'abc'
          side: 0
      ).to.throw()

    it 'should not throw if side 0 or 1', ->
      expect(->
        new Piece
          rank: '1'
          side: 0
      ).to.not.throw()

      expect(->
        new Piece
          rank: '1'
          side: 1
      ).to.not.throw()

    it 'should throw if side not valid', ->
      expect(->
        new Piece
          rank: '1'
          side: 2
      ).to.throw()

      expect(->
        new Piece
          rank: '1'
          side: -1
      ).to.throw()

Break tests down into one

[master] Break tests down into one


require 'window'

measure 'spec suite require time', ->
  fsUtils = require 'fs-utils'
  path = require 'path'
  require 'spec-helper'

  requireSpecs = (directoryPath, specType) ->
    for specPath in fsUtils.listTreeSync(path.join(directoryPath, 'spec')) when /-spec\.coffee$/.test specPath
      require specPath

  setSpecType = (specType) ->
    for spec in jasmine.getEnv().currentRunner().specs() when not spec.specType?
      spec.specType = specType

  # Run core specs
  requireSpecs(window.resourcePath)
  setSpecType('core')

  # Run bundled package specs
  for packagePath in fsUtils.listTreeSync(config.nodeModulesDirPath) when atom.isInternalPackage(packagePath)
    requireSpecs(packagePath, 'bundled')
  setSpecType('bundled')

  # Run user package specs
  for packagePath in fsUtils.listTreeSync(config.userPackagesDirPath)
    requireSpecs(packagePath, 'user')
  setSpecType('user')

fs = require 'fs'

require 'window'

measure 'spec suite require time', ->
  fsUtils = require 'fs-utils'
  path = require 'path'
  require 'spec-helper'

  requireSpecs = (directoryPath, specType) ->
    for specPath in fsUtils.listTreeSync(path.join(directoryPath, 'spec')) when /-spec\.coffee$/.test specPath
      require specPath

  setSpecType = (specType) ->
    for spec in jasmine.getEnv().currentRunner().specs() when not spec.specType?
      spec.specType = specType

  # Run core specs
  requireSpecs(window.resourcePath)
  setSpecType('core')

  # Run bundled package specs
  if fsUtils.isDirectorySync(config.nodeModulesDirPath)
    for packageName in fs.readdirSync(config.nodeModulesDirPath)
      packagePath = path.join(config.nodeModulesDirPath, packageName)
      requireSpecs(packagePath, 'bundled') if atom.isInternalPackage(packagePath)
    setSpecType('bundled')

  # Run user package specs
  if fsUtils.isDirectorySync(config.userPackagesDirPath)
    for packageName in fs.readdirSync(config.userPackagesDirPath)
      requireSpecs(path.join(config.userPackagesDirPath, packageName))
    setSpecType('user')

Use fs.readdirSync() for listing package directories

Previously fsUtils.listTreeSync() was used which returns every path
in the tree, not just paths directly underneath the root path.

This speeds up the spec suite require time by not stat'ing the entire
node_modules directory.


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

		user = Meteor.user()

		file = new FS.File image
		file.attachData image, ->
			file.name user.username

			Avatars.insert file, (err, fileObj) ->
				Meteor.users.update {_id: user._id}, {$set: {avatarOrigin: service}}

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

		user = Meteor.user()

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

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

Add method to reset avatar

Add method to reset avatar


angular.module("hyperadmin")
  .controller "FormCtrl", ($scope, Restangular) ->
    @submit = =>
      target = @meta.target
      method = @meta.method

      onError = (response) =>
        errors = response.data

      onSuccess = (resource) =>
        # Do nothing yet

      if method == "post"
        Restangular.all(target).post(@resource).then onSuccess, onError
      else if method == "patch"
        Restangular.one(target).patch(@resource).then onSuccess, onError

    this

angular.module("hyperadmin")
  .controller "FormCtrl", ($scope, Restangular) ->
    @submit = =>
      target = @meta.target
      method = @meta.method

      onError = (response) =>
        @errors = response.data

      onSuccess = (resource) =>
        # Do nothing yet

      if method == "post"
        Restangular.all(target).post(@resource).then onSuccess, onError
      else if method == "patch"
        Restangular.one(target).patch(@resource).then onSuccess, onError

    this

Fix displaying error messages from forms


_ = require 'underscore'
{ isTouchDevice } = require '../util/device.coffee'

module.exports =
  firstVisibleInput: ($el) ->
    $el.find('input:visible, textarea:visible').first()

  moveCursorToEnd: ($input) ->
    val = $input.val()
    $input.val('').val val

  autofocus: ($input, defer = false) ->
    return if isTouchDevice()

    focus = =>
      $input.focus()
      @moveCursorToEnd $input

    if defer then _.defer(focus) else focus()

_ = require 'underscore'
{ isTouchDevice } = require '../util/device.coffee'

module.exports =
  firstVisibleInput: ($el) ->
    $el.find('input:visible, textarea:visible').first()

  moveCursorToEnd: ($input) ->
    val = $input.val()
    $input.val('').val val

  isFocusable: ($el) ->
    $el.is('input') or $el.is('textarea')

  autofocus: ($el, defer = false) ->
    return if isTouchDevice()

    focus = =>
      if not @isFocusable $el
        $el = @firstVisibleInput $el

      $el.focus()
      @moveCursorToEnd $el

    if defer then _.defer(focus) else focus()

Allow autofocus to accept a container element


noflo = require("noflo")
uuid = require("node-uuid")

class RandomUuid extends noflo.Component

  description: "Generate a random UUID token"

  constructor: ->
    @inPorts =
      in: new noflo.Port
    @outPorts =
      out: new noflo.Port

    @inPorts.in.on "disconnect", =>
      token = uuid.v4()
      @outPorts.out.send(token)
      @outPorts.out.disconnect()

exports.getComponent = -> new RandomUuid

noflo = require('noflo')
uuid = require('node-uuid')

class RandomUuid extends noflo.Component

  description: 'Generate a random UUID token'

  constructor: ->
    @inPorts =
      in: new noflo.Port
    @outPorts =
      out: new noflo.Port

    @inPorts.in.on 'begingroup', (group) =>
      @outPorts.out.beginGroup group
    @inPorts.in.on 'endgroup', =>
      @outPorts.out.endGroup()
    @inPorts.in.on 'disconnect', =>
      @outPorts.out.disconnect()

    @inPorts.in.on 'data', =>
      @outPorts.out.send uuid.v4()

exports.getComponent = -> new RandomUuid

Send UUID on 'data' rather than 'disconnect'


require 'js-yaml'
socket = require 'socket.io'

solid = require 'solid'

{Engine} = require './engine'
engine = new Engine
  moves: require './data/bw/moves.yml'

io = socket.listen solid (app) ->
  app.get '/', @render ->
    @doctype 5
    @html ->
      @head ->
        @js '/socket.io/socket.io.js'
        @script @html_safe '''
          var socket = io.connect('http://localhost');
          socket.on('newuser', function (data) {
            console.log(data);
            document.write(data);
          });
        '''

io.sockets.on 'connection', (socket) ->
  socket.emit 'newuser', 'you joined!'

require 'js-yaml'
socket = require 'socket.io'

solid = require 'solid'

{Engine} = require './engine'
engine = new Engine
  moves: require './data/bw/moves.yml'

io = socket.listen solid (app) ->
  app.get '/jquery.js', @jquery
  app.get '/', @render ->
    @doctype 5
    @html ->
      @head ->
        @js '/jquery.js'
        @js '/socket.io/socket.io.js'
        @script @html_safe '''
          var socket = io.connect('http://localhost');
          socket.on('newuser', function (data) {
            console.log(data);
            $("#messages").append(data);
          });
        '''
      @body ->
        @p JSON.stringify(engine.moves)
        @p '#messages'

io.sockets.on 'connection', (socket) ->
  socket.emit 'newuser', 'you joined!'

Add jQuery and show move data.

Add jQuery and show move data.


'fileTypes': [
  'gitattributes'
  'gitignore'
  'conf'
  'ctags'
  'hgignore'
  'mailmap'
  'stylelintignore'
  'cfg'
]
'name': 'Generic Configuration'
'patterns': [
  {
    'include': '#comment'
  }
]
'repository':
  'comment':
    'captures':
      '1':
        'name': 'comment.line.number-sign.generic-config'
      '2':
        'name': 'punctuation.definition.comment.generic-config'
      '3':
        'name': 'comment.line.semi-colon.generic-config'
      '4':
        'name': 'punctuation.definition.comment.generic-config'
    'match': '((#).*$\\n?)|((;).*$\\n?)'
'scopeName': 'text.generic-config'

'fileTypes': [
  'gitattributes'
  '.config/git/ignore'
  '.git/info/exclude'
  'gitignore'
  'conf'
  'ctags'
  'hgignore'
  'mailmap'
  'stylelintignore'
  'cfg'
]
'name': 'Generic Configuration'
'patterns': [
  {
    'include': '#comment'
  }
]
'repository':
  'comment':
    'captures':
      '1':
        'name': 'comment.line.number-sign.generic-config'
      '2':
        'name': 'punctuation.definition.comment.generic-config'
      '3':
        'name': 'comment.line.semi-colon.generic-config'
      '4':
        'name': 'punctuation.definition.comment.generic-config'
    'match': '((#).*$\\n?)|((;).*$\\n?)'
'scopeName': 'text.generic-config'

Add support for gitignores other than .gitignore


client  = require 'nack/client'
process = require 'nack/process'

config = __dirname + "/fixtures/echo.ru"

exports.testClientRequest = (test) ->
  test.expect 8

  p = process.createProcess config
  p.on 'ready', () ->
    c = client.createConnection p.sockPath
    test.ok c

    request = c.request 'GET', '/foo', {}
    test.ok request
    test.same "GET", request.method
    test.same "/foo", request.path
    test.same "/foo", request.headers['PATH_INFO']

    request.end()

    request.on "response", (response) ->
      test.ok response
      test.same 200, response.statusCode

      p.quit()
      p.on 'exit', () ->
        test.ok true
        test.done()

client  = require 'nack/client'
process = require 'nack/process'

config = __dirname + "/fixtures/echo.ru"

exports.testClientRequest = (test) ->
  test.expect 10

  p = process.createProcess config
  p.on 'ready', () ->
    c = client.createConnection p.sockPath
    test.ok c

    request = c.request 'GET', '/foo', {}
    test.ok request
    test.same "GET", request.method
    test.same "/foo", request.path
    test.same "/foo", request.headers['PATH_INFO']

    test.ok request.writeable

    request.end()

    request.on 'close', () ->
      test.ok true

    request.on 'response', (response) ->
      test.ok response
      test.same 200, response.statusCode

      p.quit()
      p.on 'exit', () ->
        test.ok true
        test.done()

Test client request is a writable stream


DefaultFileIcons = require '../lib/default-file-icons'
FileIcons = require '../lib/file-icons'

describe 'FileIcons', ->
  afterEach ->
    FileIcons.setService(new DefaultFileIcons)

  it 'provides a default', ->
    expect(FileIcons.getService()).toBeDefined()
    expect(FileIcons.getService()).not.toBeNull()

  it 'allows the default to be overridden', ->
    service = new Object
    FileIcons.setService(service)

    expect(FileIcons.getService()).toBe(service)

  it 'allows the service to be reset to the default easily', ->
    service = new Object
    FileIcons.setService(service)
    FileIcons.resetService()

    expect(FileIcons.getService()).not.toBe(service)

  describe 'Class handling', ->
    workspaceElement = null

    beforeEach ->
      workspaceElement = atom.views.getView(atom.workspace)

      waitsForPromise ->
        atom.workspace.open('sample.js')

      waitsForPromise ->
        atom.packages.activatePackage('tabs')

    it 'allows multiple classes to be passed', ->
      service =
        iconClassForPath: (path) -> 'first second'

      FileIcons.setService(service)
      tab = workspaceElement.querySelector('.tab')
      tab.updateIcon()
      expect(tab.itemTitle.className).toBe('title icon first second')

    it 'allows an array of classes to be passed', ->
      service =
        iconClassForPath: (path) -> ['first', 'second']

      FileIcons.setService(service)
      tab = workspaceElement.querySelector('.tab')
      tab.updateIcon()
      expect(tab.itemTitle.className).toBe('title icon first second')

Add a spec for class-list enhancements

Add a spec for class-list enhancements


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

OUT.registerCreatedHandler "todo_list", (selector) ->
  $(selector).find("a.new").click()

$ ->
  # Remove links to todo-list from todo-lists in content area
  $('.content h2 a[rel="todo-list"]').each ->
    $(this).parent().html $(this).html()
    # TODO: doesnot work with live added data

  OUT.contentItems.highlightQueryIn ".content-items .content-item-todo-list h2, .content-items .todo-title", (chain) ->
    matched_lists = $(".content-items .content-item-todo-list h2 span.highlight").parents('.content-item-todo-list')
    matched_lists.find('.content-item').show()

$(window).load ->
  $('.content-todo-list.sortable').sortable
    connectWith: ".content-todo-list.sortable"

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

OUT.registerCreatedHandler "todo_list", (selector) ->
  $(selector).find("a.new").click()

$ ->
  # Remove links to todo-list from todo-lists in content area
  $('.content h2 a[rel="todo-list"]').each ->
    $(this).replaceWith $(this).html()
    # TODO: doesnot work with live added data

  OUT.contentItems.highlightQueryIn ".content-items .content-item-todo-list h2, .content-items .todo-title", (chain) ->
    matched_lists = $(".content-items .content-item-todo-list h2 span.highlight").parents('.content-item-todo-list')
    matched_lists.find('.content-item').show()

$(window).load ->
  $('.content-todo-list.sortable').sortable
    connectWith: ".content-todo-list.sortable"

Fix bug in transforming linked todo_list titles into plain text


angular.module('loomioApp').factory 'StanceModel', (DraftableModel, AppConfig, MentionLinkService) ->
  class StanceModel extends DraftableModel
    @singular: 'stance'
    @plural: 'stances'
    @indices: ['pollId', 'authorId']
    @serializableAttributes: AppConfig.permittedParams.stance
    @draftParent: 'poll'

    defaultValues: ->
      reason: ''
      stanceChoicesAttributes: []
      visitorAttributes: {}

    relationships: ->
      @belongsTo 'poll'
      @hasMany 'stanceChoices'

    participant: ->
      @recordStore.users.find(@userId) or @recordStore.visitors.find(@visitorId)

    stanceChoice: ->
      _.first @stanceChoices()

    pollOption: ->
      @stanceChoice().pollOption() if @stanceChoice()

    pollOptionId: ->
      (@pollOption() or {}).id

    pollOptions: ->
      @recordStore.pollOptions.find(@pollOptionIds())

    stanceChoiceNames: ->
      _.pluck(@pollOptions(), 'name')

    pollOptionIds: ->
      _.pluck @stanceChoices(), 'pollOptionId'

    choose: (optionIds) ->
      _.each @recordStore.stanceChoices.find(stanceId: @id), (stanceChoice) ->
        stanceChoice.remove()

      _.each _.flatten([optionIds]), (optionId) =>
        @recordStore.stanceChoices.create(pollOptionId: parseInt(optionId), stanceId: @id)
      @

    # prepareForForm: ->
    #   @stanceChoicesAttributes = _.map(@pollOptionIds(), (id) -> { pollOptionId: id })

angular.module('loomioApp').factory 'StanceModel', (DraftableModel, AppConfig, MentionLinkService) ->
  class StanceModel extends DraftableModel
    @singular: 'stance'
    @plural: 'stances'
    @indices: ['pollId', 'authorId']
    @serializableAttributes: AppConfig.permittedParams.stance
    @draftParent: 'poll'

    afterConstruction: ->
      @visitorAttributes =
        name:  @participant().name
        email: @participant().email

    defaultValues: ->
      reason: ''
      stanceChoicesAttributes: []
      visitorAttributes: {}

    relationships: ->
      @belongsTo 'poll'
      @hasMany 'stanceChoices'

    participant: ->
      @recordStore.users.find(@userId) or @recordStore.visitors.find(@visitorId)

    stanceChoice: ->
      _.first @stanceChoices()

    pollOption: ->
      @stanceChoice().pollOption() if @stanceChoice()

    pollOptionId: ->
      (@pollOption() or {}).id

    pollOptions: ->
      @recordStore.pollOptions.find(@pollOptionIds())

    stanceChoiceNames: ->
      _.pluck(@pollOptions(), 'name')

    pollOptionIds: ->
      _.pluck @stanceChoices(), 'pollOptionId'

    choose: (optionIds) ->
      _.each @recordStore.stanceChoices.find(stanceId: @id), (stanceChoice) ->
        stanceChoice.remove()

      _.each _.flatten([optionIds]), (optionId) =>
        @recordStore.stanceChoices.create(pollOptionId: parseInt(optionId), stanceId: @id)
      @

    # prepareForForm: ->
    #   @stanceChoicesAttributes = _.map(@pollOptionIds(), (id) -> { pollOptionId: id })

Set visitor attributes on stance construction


# This file contains utilities to deal with prototype extensions.

#### def

# Defines a non-enumerable property on the specified constructor's `prototype`.
#
#     def Object, merge: (o) ->
#       # merge implementation
#
#     {foo: 10}.merge bar: 20 # {foo: 10, bar: 20}
def = (ctor, o) ->
  for name, value of o
    unless ctor.prototype[name]?
      Object.defineProperty? ctor.prototype,
                             name,
                             enumerable: false, value: value

module.exports = {def}

# This file contains utilities to deal with prototype extensions.

#### def

# Defines a non-enumerable property on the specified constructor's `prototype`.
#
#     def Object, merge: (o) ->
#       # merge implementation
#
#     {foo: 10}.merge bar: 20 # {foo: 10, bar: 20}
def = (ctor, o) ->
  for name, value of o
    Object.defineProperty? ctor.prototype,
                           name,
                           enumerable: false, value: value, writable: true

module.exports = {def}

Remove existence check in def and set defined properties as writable.


define [
  'jquery'
  'underscore'
  'backbone'
  'marionette'
  'cs!collections/media-types'
  'cs!views/workspace/menu/auth'
  'cs!views/workspace/menu/add'
  'cs!views/workspace/menu/toolbar-search'
  'hbs!templates/layouts/workspace/menu'
], ($, _, Backbone, Marionette, mediaTypes, AuthView, AddView, toolbarView, menuTemplate) ->

  _toolbar = null

  return new class MenuLayout extends Marionette.Layout
    template: menuTemplate

    regions:
      add: '#workspace-menu-add'
      auth: '#workspace-menu-auth'
      toolbar: '#workspace-menu-toolbar'

    onRender: () ->
      @showView(_toolbar)

    showView: (view) ->
      _toolbar = view or toolbarView

      @add.show(new AddView {collection:mediaTypes})
      @auth.show(new AuthView())
      @toolbar.show(_toolbar)

    showToolbar: (view) ->
      @showView(view or toolbarView)

define [
  'jquery'
  'underscore'
  'backbone'
  'marionette'
  'cs!collections/media-types'
  'cs!session'
  'cs!views/workspace/menu/auth'
  'cs!views/workspace/menu/add'
  'cs!views/workspace/menu/toolbar-search'
  'hbs!templates/layouts/workspace/menu'
], ($, _, Backbone, Marionette, mediaTypes, session, AuthView, AddView, toolbarView, menuTemplate) ->

  _toolbar = null

  return new class MenuLayout extends Marionette.Layout
    template: menuTemplate

    regions:
      add: '#workspace-menu-add'
      auth: '#workspace-menu-auth'
      toolbar: '#workspace-menu-toolbar'

    onRender: () ->
      @showView(_toolbar)

    showView: (view) ->
      _toolbar = view or toolbarView

      @add.show(new AddView {collection:mediaTypes})
      @auth.show(new AuthView {model: session})
      @toolbar.show(_toolbar)

    showToolbar: (view) ->
      @showView(view or toolbarView)

Include session in AuthView constructor

Include session in AuthView constructor


Meteor.methods
	updateRoom: (rid, name, users, accessPermissions) ->

		if not Meteor.userId()
			throw new Meteor.Error('invalid-user', "[methods] updateRoom -> Invalid user")

		room = ChatRoom.findOne rid

		if room.t not in ['d'] and name? and name isnt room.name
			Meteor.call 'saveRoomName', rid, name
		Meteor.call 'relabelRoom', rid, accessPermissions
		if users?
			# remove the current users
			users = _.without.apply _,room.usernames.concat users
			for user in users
				Meteor.call 'addUserToRoom', rid, user
		return true

Meteor.methods
	updateRoom: (rid, name, usernames, accessPermissions) ->

		console.log '[method] updateRoom -> arguments', arguments

		if not Meteor.userId()
			throw new Meteor.Error('invalid-user', "[methods] updateRoom -> Requires authenticated user")

		# validate params exist
		unless rid and name and usernames and accessPermissions
			throw new Meteor.Error 'invalid-argument', 'Missing required values'

		room = ChatRoom.findOne rid

		# don't allow the room creator to be removed
		unless room.u.username in usernames
			throw new Meteor.Error 'invalid-argument', 'You cannot remove the room creator'

		if room.t not in ['d'] and name? and name isnt room.name
			Meteor.call 'saveRoomName', rid, name

		# relabel room if permissions changed
		if _.difference( room.accessPermissions, accessPermissions ).length > 0
			Meteor.call 'relabelRoom', rid, accessPermissions

		# add users to the room that weren't previously in the room
		usersToAdd = _.difference( usernames, room.usernames)
		for username in usersToAdd
			Meteor.call 'addUserToRoom', {rid: rid, username: username}

		# remove users from the room that were previously in the room
		usersToRemove = _.difference( room.usernames, usernames)
		for username in usersToRemove
			Meteor.call 'removeUserFromRoom', {rid: rid, username: username}

		return {rid:rid}

Validate parameters, and: 1. check that room creator is not removed 2. relabel room if access permissions changed 3. add new members that we're previously in the room 4. remove existing members that should no longer be in the room


class Trix.ImageAttachmentView
  constructor: (@attachment) ->
    @attachment.delegate = this
    @image = document.createElement("img")

  render: ->
    @loadPreview() if @attachment.isPending()
    @updateImageAttributes()
    @image

  loadPreview: ->
    reader = new FileReader
    reader.onload = (event) =>
      @image.setAttribute("src", event.target.result)
    reader.readAsDataURL(@attachment.file)

  attributeNames = "src width height class".split(" ")

  updateImageAttributes: ->
    attributes = {}
    attributes[key] = value for key, value of @attachment.attributes
    attributes.src = attributes.url
    attributes.class = "pending-attachment" if @attachment.isPending()

    for key in attributeNames
      if value = attributes[key]
        @image.setAttribute(key, value)
      else
        @image.removeAttribute(key)

  # Attachment delegate

  attachmentDidUpdate: (@attachment) ->
    @updateImageAttributes()

class Trix.ImageAttachmentView
  constructor: (@attachment) ->
    @attachment.delegate = this
    @image = document.createElement("img")

  render: ->
    @loadFile() if @attachment.isPending()
    @updateImageAttributes()
    @image

  loadFile: ->
    reader = new FileReader
    reader.onload = (event) =>
      if @attachment.isPending()
        @image.setAttribute("src", event.target.result)
        @attachment.update(width: @image.offsetWidth, height: @image.offsetHeight)
    reader.readAsDataURL(@attachment.file)

  attributeNames = "url width height class".split(" ")

  updateImageAttributes: ->
    attributes = {}

    for key in attributeNames
      attributes[key] = @attachment.attributes[key]

    if attributes.url
      attributes.src = attributes.url
      delete attributes.url

    if @attachment.isPending()
      attributes.class = "pending-attachment"

    for key, value of attributes
      if value?
        @image.setAttribute(key, value)
      else
        @image.removeAttribute(key)

  # Attachment delegate

  attachmentDidUpdate: ->
    @updateImageAttributes()

Set image dimensions after loading the File


'menu': [
  {
    'label': 'Packages'
    'submenu': [
      'label': 'Bracket Matcher'
      'submenu': [
        { 'label': 'Go To Matching Bracket', 'command': 'bracket-matcher:go-to-matching-bracket' }
        { 'label': 'Select Inside Brackets', 'command': 'bracket-matcher:select-inside-brackets' }
        { 'label': 'Remove Brackets From Selection', 'command': 'bracket-matcher:remove-brackets-from-selection' }
        { 'label': 'Close Current Tag', 'command': 'bracket-matcher:close-tag'}
        { 'label': 'Remove Matching Brackets', 'command': 'bracket-matcher:remove-matching-brackets'}
      ]
    ]
  }
]

'menu': [
  {
    'label': 'Packages'
    'submenu': [
      'label': 'Bracket Matcher'
      'submenu': [
        { 'label': 'Go To Matching Bracket', 'command': 'bracket-matcher:go-to-matching-bracket' }
        { 'label': 'Select Inside Brackets', 'command': 'bracket-matcher:select-inside-brackets' }
        { 'label': 'Remove Brackets From Selection', 'command': 'bracket-matcher:remove-brackets-from-selection' }
        { 'label': 'Close Current Tag', 'command': 'bracket-matcher:close-tag' }
        { 'label': 'Remove Matching Brackets', 'command': 'bracket-matcher:remove-matching-brackets' }
      ]
    ]
  },
  {
    'label': 'Selection'
    'submenu': [
        { 'label': 'Select Inside Brackets', 'command': 'bracket-matcher:select-inside-brackets' }
    ]
  }
]

Add Select Inside Brackets to Selection menu


module.exports = (robot) ->
  robot.hear /the more you know/, (msg) ->
    msg.reply "http://www.youtube.com/watch?v=v3rhQc666Sg"

module.exports = (robot) ->
  robot.hear /the more you know/, (msg) ->
    msg.send "http://www.youtube.com/watch?v=v3rhQc666Sg"

Change to post in channel not reply.

Change to post in channel not reply.


define ['lib/amd/Backbone','neo4j/webadmin/modules/databrowser/views/PropertyContainerView'], (Backbone, PropertyContainerView) ->

  # TODO: Refactor out the "shouldBeConvertedToString" into it's own class
  describe "PropertyContainerView", ->
    pcv = new PropertyContainerView(template:null)

    it "recognizes ascii characters as strings", ->
      expect(pcv.shouldBeConvertedToString "a").toBe(true)
      expect(pcv.shouldBeConvertedToString "abcd123 ").toBe(true)

    it "recognizes swedish characters as strings", ->
      expect(pcv.shouldBeConvertedToString "åäö").toBe(true)
      expect(pcv.shouldBeConvertedToString "åäö #$ asd  ").toBe(true)

    it "recognizes strings containing odd characters as strings", ->
      expect(pcv.shouldBeConvertedToString ";åäö #$ asd  ").toBe(true)

    it "recognizes valid JSON values as not being strings", ->
      expect(pcv.shouldBeConvertedToString "1").toBe(false)
      expect(pcv.shouldBeConvertedToString "12").toBe(false)
      expect(pcv.shouldBeConvertedToString "12.523").toBe(false)

      expect(pcv.shouldBeConvertedToString "['1','2','3']").toBe(false)
      expect(pcv.shouldBeConvertedToString "[1,2,3]").toBe(false)

      expect(pcv.shouldBeConvertedToString '"a quoted string"').toBe(false)

define ['lib/amd/Backbone','neo4j/webadmin/modules/databrowser/views/PropertyContainerView'], (Backbone, PropertyContainerView) ->

  # TODO: Refactor out the "shouldBeConvertedToString" into it's own class
  describe "PropertyContainerView", ->
    pcv = new PropertyContainerView(template:null)

    it "recognizes ascii characters as strings", ->
      expect(pcv.shouldBeConvertedToString "a").toBe(true)
      expect(pcv.shouldBeConvertedToString "abcd123 ").toBe(true)

    it "recognizes strings containing odd characters as strings", ->
      expect(pcv.shouldBeConvertedToString ";åäö #$ asd  ").toBe(true)

    it "recognizes valid JSON values as not being strings", ->
      expect(pcv.shouldBeConvertedToString "1").toBe(false)
      expect(pcv.shouldBeConvertedToString "12").toBe(false)
      expect(pcv.shouldBeConvertedToString "12.523").toBe(false)

      expect(pcv.shouldBeConvertedToString "['1','2','3']").toBe(false)
      expect(pcv.shouldBeConvertedToString "[1,2,3]").toBe(false)

      expect(pcv.shouldBeConvertedToString '"a quoted string"').toBe(false)

Remove a test that fails in TeamCity.

Remove a test that fails in TeamCity.

There is no obvious reason why this test should fail, but since
Webadmin has been replaced by the Browser, there doesn't seem to be any
point trying to work out what is going on.


reqr              = if global.GENTLY then GENTLY.hijack(require) else require
stream            = reqr "stream"

class PaginationStream extends stream.Readable
  constructor: (fetchPage) ->
    super objectMode: true
    @_fetchPage = fetchPage
    @_pageno = 0
    @_items = []
    @_itemsRead = 0

  _read: ->
    if @_items.length > 0
      @_itemsRead++
      return process.nextTick => @push @_items.pop()

    if @_nitems? && @_itemsRead >= @_nitems
      return process.nextTick => @push null

    @_fetchPage ++@_pageno, (err, result) =>
      if err?
        return @emit "error", err

      @_nitems = result.count

      @_items = (result.items[i] for i in [result.items.length-1 .. 0])

      return @_read()

module.exports = PaginationStream

reqr              = if global.GENTLY then GENTLY.hijack(require) else require
TransloaditClient = reqr "./TransloaditClient"
stream            = reqr "stream"

class PaginationStream extends stream.Readable
  constructor: (@_fetchPage) ->
    super objectMode: true
    @_pageno = 0
    @_items = []
    @_itemsRead = 0

  _read: ->
    if @_items.length > 0
      @_itemsRead++
      return process.nextTick => @push @_items.pop()

    if @_nitems? && @_itemsRead >= @_nitems
      return process.nextTick => @push null

    @_fetchPage ++@_pageno, (err, result) =>
      if err?
        return @emit "error", err

      @_nitems = result.count

      @_items = (result.items[i] for i in [result.items.length-1 .. 0])

      return @_read()

module.exports = PaginationStream

Revert "Some nice warnings away"

Revert "Some nice warnings away"

This reverts commit 1e04dc556af840e0e4571e287135e510245524d7.


###
Use intersection observer to lazy load.  Not using vue-in-viewport-mixin since
needs are simpler and I want more control.
###
export default

	props:
		intersectionOptions:
			type: Object
			default: -> {}

	data: -> inViewport: false

	mounted: ->
		return unless @shouldObserve and IntersectionObserver?
		@observer = new IntersectionObserver @onInViewport,
			@makeIntersectionOptions()
		@observer.observe @$el

	computed:

		# Conditions where the viewport is watched
		shouldObserve: -> @lazyload or @autopause

		# Conditions where we observe only once
		shouldObserveOnce: -> not @autopause

	watch:

		# Trigger load when in viewport
		inViewport: (visible) -> @load() if visible

	methods:

		# Parse interesection options
		makeIntersectionOptions: ->
			options = @intersectionOptions
			if options.root and typeof options.root == 'string'
				options.root = document.querySelector options.root
			return options

		# Store when in viewport
		onInViewport: (entries) ->
			@inViewport = entries[0].isIntersecting
			@observer?.disconnect() if @inViewport and @shouldObserveOnce

###
Use intersection observer to lazy load.  Not using vue-in-viewport-mixin since
needs are simpler and I want more control.
###
export default

	props:
		intersectionOptions:
			type: Object
			default: -> {}

	data: -> inViewport: false

	# Start observing on init
	mounted: -> @startObserving()

	computed:

		# Conditions where the viewport is watched
		shouldObserve: -> @lazyload or @autopause

		# Conditions where we observe only once
		shouldObserveOnce: -> not @autopause

	watch:

		# Trigger load when in viewport
		inViewport: (visible) -> @load() if visible

	methods:

		# Start observing if appropriate
		startObserving: ->
			return unless @shouldObserve and IntersectionObserver?
			return if @observer # Don't make multiple observers
			@observer = new IntersectionObserver @onInViewport,
				@makeIntersectionOptions()
			@observer.observe @$el

		# Parse interesection options
		makeIntersectionOptions: ->
			options = @intersectionOptions
			if options.root and typeof options.root == 'string'
				options.root = document.querySelector options.root
			return options

		# Store when in viewport
		onInViewport: (entries) ->
			@inViewport = entries[0].isIntersecting
			if @inViewport and @shouldObserveOnce
				@observer?.disconnect()
				delete @observer

Move initializing of observing into a method


{Testing, expect, sinon, _} = require 'openstax-react-components/test/helpers'

User = require 'user/model'

describe 'User', ->

  it 'defaults to not logged in', ->
    expect(User.isLoggedIn()).to.be.false

  it 'resets courses when destroy is called, but still emits signals', ->
    fakeCourse =
      destroy: -> true
    sinon.stub(fakeCourse, 'destroy')
    User.courses = [fakeCourse]
    logoutSpy = sinon.spy()
    User.channel.on 'logout.received', logoutSpy
    User.destroy()
    expect(User.courses).to.be.empty
    expect(fakeCourse.destroy).to.have.been.called
    expect(logoutSpy).not.to.have.been.called

    User._signalLogoutCompleted()
    expect(logoutSpy).to.have.been.called

Test logout signal is emitted after destroy


module.exports =
  observeConfig: (keyPath, args...) ->
    @configSubscriptions ?= {}
    @configSubscriptions[keyPath] = config.observe(keyPath, args...)

  unobserveConfig: ->
    for keyPath, subscription of @configSubscriptions ? {}
      subscription.cancel()

module.exports =
  observeConfig: (keyPath, args...) ->
    @configSubscriptions ?= {}
    @configSubscriptions[keyPath] = config.observe(keyPath, args...)

  unobserveConfig: ->
    if @configSubscriptions?
      subscription.cancel() for keyPath, subscription of @configSubscriptions
      @configSubscriptions = null

:non-potable_water: Clear config subscriptions when unobserving


class window.DatabaseItemView extends Backbone.View
  tagName: 'li'
  className: 'databaseItem'

  events:
    'click .databaseItem span': 'gotoDatabase',
    'click .databaseItem a': 'toggleCollections'

  initialize: ->
    @template = _.template $('#databaseItemTemplate').html()

  render: ->
    id = @model.get '_id'
    $(@el).html @template({ id: id, name: @model.get('name'), url: "databases/#{id}" })
    this

  toggleCollections: (event) =>
    console.log 'toggleCollections'
    @collectionsView = new CollectionsView(this, @model) unless @collectionsView
    icon = $('a.treeIcon', @el)
    if @collectionsView.isVisible
      icon.removeClass 'expanded'
      @collectionsView.hide()
    else
      icon.addClass 'expanded'
      @collectionsView.show()

  gotoDatabase: (event) =>
    console.log 'gotoDatabase'

Remove function to open collections when clicking on the database label in the tree


# USE
# If the element is not a component, add full-height-header attribute to the tag.
# With a component, add 'full_height_header: true' to the persisted options
class @MC.Utils.FullHeightHeader
  @autoInit: ->
    $('[full-height-header]').each (i, el) => new @($(el))

  constructor: (@el) ->
    @component = @el.data('component')

    if @component
      @inner = @component.inner
    else
      @inner = @el

    @lastWidth = null
    @offset = @inner.offset().top

    @compute()
    $(window).on 'resize', @compute

  compute: =>
    return false if @lastWidth == $(window).width()
    @inner.css('height', $(window).height() - @offset)
    @lastWidth = $(window).width()
    @el.trigger 'compute.fullHeightHeader.MC'

# USE
# If the element is not a component, add full-height-header attribute to the tag.
# With a component, add 'full_height_header: true' to the persisted options
class @MC.Utils.FullHeightHeader
  @autoInit: ->
    $('[full-height-header]').each (i, el) => new @($(el))

  constructor: (@el) ->
    @el.data('fullHeightHeader', @)

    @component = @el.data('component')

    if @component
      @inner = @component.inner
    else
      @inner = @el

    @lastWidth = null

    @compute()

    $(window).on 'resize', =>
      @compute() unless @lastWidth == $(window).width()
      @lastWidth = $(window).width()

  compute: =>
    @inner.css('height', $(window).height() - @inner.offset().top)
    @el.trigger 'compute.fullHeightHeader.MC'

Update Utils.FullHeightHeader. Put instance into @el so @el can access @compute()


$ ->
  GlobalHeader = React.createClass
    propTypes:
      imagePath: React.PropTypes.string.isRequired
      imageTitle: React.PropTypes.string.isRequired
    render: ->

  globalHeader = document.querySelector('.GlobalHeader')
  imagePath = globalHeader.dataset.headerImagePath
  imageTitle = globalHeader.dataset.headerImageTitle
  React.render(<GlobalHeader imagePath={imagePath} imageTitle={imageTitle} />, globalHeader)

Add link to global header

Add link to global header


#= require_self
#= require_tree .

window.Neighborly =
  Common:
    initPage: ->
      that = this
      unless window.Turbolinks is undefined
        $(document).bind "page:fetch", ->
          that.Loading.show()

        $(document).bind "page:restore", ->
          that.Loading.hide()

        $(document).bind "page:change", ->
          $(window).scrollTop(0)

          try
            FB.XFBML.parse()
          try
            twttr.widgets.load()

    init: ->
      $(document).foundation('reveal', {animation: 'fadeIn', animationSpeed: 100})
      $(document).foundation()

    finish: ->

    Loading:
      show: ->
        $('#loading #back-overlay, #loading #front-overlay').fadeIn(2)
      hide: ->
        $('#loading #back-overlay, #loading #front-overlay').fadeOut(2)

#= require_self
#= require_tree .

window.Neighborly =
  Common:
    initPage: ->
      that = this
      unless window.Turbolinks is undefined
        $(document).bind "page:fetch", ->
          that.Loading.show()

        $(document).bind "page:restore", ->
          that.Loading.hide()

        $(document).bind "page:change", ->
          $(window).scrollTop(0)

          try
            FB.XFBML.parse()
          try
            twttr.widgets.load()

    init: ->
      $(document).foundation('reveal', {animation: 'fadeIn', animationSpeed: 100})
      $(document).foundation()
      $('.search-button').click ->
        if $('.discover-form-input').val() != ''
          $('form.discover-form').submit()
        else
          $('.discover-form-input').toggleClass('show').focus()

        return false

    finish: ->

    Loading:
      show: ->
        $('#loading #back-overlay, #loading #front-overlay').fadeIn(2)
      hide: ->
        $('#loading #back-overlay, #loading #front-overlay').fadeOut(2)

Add javascript for search button

Add javascript for search button


describe "RequireJS", ->
  beforeEach ->
    @addMatchers
      requirejsTobeUndefined: ->
        typeof requirejs is "undefined"

      requireTobeUndefined: ->
        typeof require is "undefined"

      defineTobeUndefined: ->
        typeof define is "undefined"

  it "check that the RequireJS object is present in the global namespace", ->
    expect(RequireJS).toEqual jasmine.any(Object)
    expect(window.RequireJS).toEqual jasmine.any(Object)

  it "check that requirejs(), require(), and define() are not in the global namespace", ->
    expect({}).requirejsTobeUndefined()
    expect({}).requireTobeUndefined()
    expect({}).defineTobeUndefined()
    expect(window.requirejs).not.toBeDefined()
    expect(window.require).not.toBeDefined()
    expect(window.define).not.toBeDefined()

  it "check that the RequireJS has requirejs(), require(), and define() functions as its properties", ->
    expect(RequireJS.requirejs).toEqual jasmine.any(Function)
    expect(RequireJS.require).toEqual jasmine.any(Function)
    expect(RequireJS.define).toEqual jasmine.any(Function)

Work on RequireJS Jasmine test.

Work on RequireJS Jasmine test.


_ = require "underscore-plus"

module.exports =
class Builder
  constructor: ->
    @envPathKey = switch process.env.platform
      when "win32" then "Path"
      else "PATH"

  run: -> null
  constructArgs: -> null
  parseLogFile: (texFilePath) -> null

  constructChildProcessOptions: ->
    env = _.clone(process.env)
    path = @constructPath()
    env[@envPathKey] = path if path?.length
    options = env: env

  constructPath: ->
    texPath = atom.config.get("latex.texPath")
    texPath?.replace("$PATH", process.env[@envPathKey])

  resolveLogFilePath: (texFilePath) ->
    outputDirectory = atom.config.get("latex.outputDirectory") ? ""
    currentDirectory = path.dirname(texFilePath)
    fileName = path.basename(texFilePath).replace(/\.tex$/, ".log")
    logFilePath = path.join(currentDirectory, outputDirectory, fileName)

_ = require "underscore-plus"

module.exports =
class Builder
  constructor: ->
    @envPathKey = switch process.env.platform
      when "win32" then "Path"
      else "PATH"

  run: (args, callback) -> null
  constructArgs: (filePath) -> null
  parseLogFile: (texFilePath) -> null

  constructChildProcessOptions: ->
    env = _.clone(process.env)
    path = @constructPath()
    env[@envPathKey] = path if path?.length
    options = env: env

  constructPath: ->
    texPath = atom.config.get("latex.texPath")
    texPath?.replace("$PATH", process.env[@envPathKey])

  resolveLogFilePath: (texFilePath) ->
    outputDirectory = atom.config.get("latex.outputDirectory") ? ""
    currentDirectory = path.dirname(texFilePath)
    fileName = path.basename(texFilePath).replace(/\.tex$/, ".log")
    logFilePath = path.join(currentDirectory, outputDirectory, fileName)

Adjust `Builder` signature to match implementations


_ = require "underscore-plus"

module.exports =
class Builder
  constructor: ->
    @envPathKey = switch process.env.platform
      when "win32" then "Path"
      else "PATH"

  run: (args, callback) -> null
  constructArgs: (filePath) -> null
  parseLogFile: (texFilePath) -> null

  constructChildProcessOptions: ->
    env = _.clone(process.env)
    path = @constructPath()
    env[@envPathKey] = path if path?.length
    options = env: env

  constructPath: ->
    texPath = atom.config.get("latex.texPath")
    texPath?.replace("$PATH", process.env[@envPathKey])

  resolveLogFilePath: (texFilePath) ->
    outputDirectory = atom.config.get("latex.outputDirectory") ? ""
    currentDirectory = path.dirname(texFilePath)
    fileName = path.basename(texFilePath).replace(/\.tex$/, ".log")
    logFilePath = path.join(currentDirectory, outputDirectory, fileName)

_ = require "underscore-plus"
path = require "path"

module.exports =
class Builder
  constructor: ->
    @envPathKey = switch process.env.platform
      when "win32" then "Path"
      else "PATH"

  run: (args, callback) -> null
  constructArgs: (filePath) -> null
  parseLogFile: (texFilePath) -> null

  constructChildProcessOptions: ->
    env = _.clone(process.env)
    childPath = @constructPath()
    env[@envPathKey] = childPath if childPath?.length
    options = env: env

  constructPath: ->
    texPath = atom.config.get("latex.texPath")
    texPath?.replace("$PATH", process.env[@envPathKey])

  resolveLogFilePath: (texFilePath) ->
    outputDirectory = atom.config.get("latex.outputDirectory") ? ""
    currentDirectory = path.dirname(texFilePath)
    fileName = path.basename(texFilePath).replace(/\.tex$/, ".log")
    logFilePath = path.join(currentDirectory, outputDirectory, fileName)

Fix bug due to accidental use of `path` module

The function `Builder::resolveLogFilePath` uses `path` module rather than
the `path` variable. Changes variable name to `childPath` and requires
the `path` module.

Closes #28


settings =
  # to customize, set environmental var BASE_URL when building or running webpack-dev-server
  # Currently is set on an endpoint by endpoint basis until all are implemented by BE
  # baseUrl: process?.env?.BASE_URL

  endpoints:
    'exercise.*.send.save':
      url: 'api/steps/{id}'
      method: 'PATCH'
      completedEvent: 'exercise.{id}.receive.save'

    'exercise.*.send.complete':
      url: 'api/steps/{id}/completed'
      method: 'PUT'
      completedEvent: 'exercise.{id}.receive.complete'

    'exercise.*.send.fetch':
      url: 'api/steps/{id}'
      method: 'GET'
      completedEvent: 'exercise.{id}.receive.fetch'

    'task.*.send.fetch':
      url: 'api/tasks/{id}'
      method: 'GET'
      completedEvent: 'task.{id}.receive.fetch'

    'task.*.send.fetchByModule':
      url: 'api/cc/tasks/{collectionUUID}/{moduleUUID}'
      method: 'GET'
      baseUrl: process?.env?.BASE_URL
      completedEvent: 'task.{collectionUUID}/{moduleUUID}.receive.fetchByModule'

    'user.send.statusUpdate':
      url: 'auth/status.json'
      method: 'GET'
      failureEvent: 'user.recieve.loadFailure'
      baseUrl: process?.env?.BASE_URL
      completedEvent: 'user.receive.statusUpdate'

module.exports = settings

settings =
  # to customize, set environmental var BASE_URL when building or running webpack-dev-server
  # Currently is set on an endpoint by endpoint basis until all are implemented by BE
  # baseUrl: process?.env?.BASE_URL

  endpoints:
    'exercise.*.send.save':
      url: 'api/steps/{id}'
      method: 'PATCH'
      completedEvent: 'exercise.{id}.receive.save'

    'exercise.*.send.complete':
      url: 'api/steps/{id}/completed'
      method: 'PUT'
      completedEvent: 'exercise.{id}.receive.complete'

    'exercise.*.send.fetch':
      url: 'api/steps/{id}'
      method: 'GET'
      completedEvent: 'exercise.{id}.receive.fetch'

    'task.*.send.fetch':
      url: 'api/tasks/{id}'
      method: 'GET'
      completedEvent: 'task.{id}.receive.fetch'

    'task.*.send.fetchByModule':
      url: 'api/cc/tasks/{collectionUUID}/{moduleUUID}'
      method: 'GET'
      baseUrl: process?.env?.BASE_URL
      completedEvent: 'task.{collectionUUID}/{moduleUUID}.receive.fetchByModule'

    'user.send.statusUpdate':
      url: 'auth/status.json'
      method: 'GET'
      useCredentials: true
      failureEvent: 'user.recieve.loadFailure'
      baseUrl: process?.env?.BASE_URL
      completedEvent: 'user.receive.statusUpdate'

module.exports = settings

Allow /auth/status to use credentials (cookies)


{Testing, expect, sinon, _} = require 'openstax-react-components/test/helpers'

Menu = require 'user/menu'
User = require 'user/model'
Course = require 'course/model'
sandbox = null

describe 'User menu component', ->
  beforeEach ->
    @props =
      course: new Course(ecosystem_book_uuid: 'test-collection-uuid')
    sandbox = sinon.sandbox.create()
  afterEach ->
    sandbox.restore()

  describe 'course options', ->

    beforeEach ->
      sandbox.stub(User, 'isLoggedIn').returns(true)

    it 'renders for registration when course is not registered', ->
      sinon.stub(@props.course, 'isRegistered').returns(false)
      Testing.renderComponent( Menu, props: @props ).then ({dom}) ->
        expect(dom.textContent).to.match(/Register for Course/)

    it 'renders modification when registered', ->
      sinon.stub(@props.course, 'isRegistered').returns(true)
      Testing.renderComponent( Menu, props: @props ).then ({dom}) ->
        expect(dom.textContent).to.match(/Change Course and ID/)

{Testing, expect, sinon, _} = require 'openstax-react-components/test/helpers'

Menu = require 'user/menu'
User = require 'user/model'
Course = require 'course/model'
sandbox = null

describe 'User menu component', ->
  beforeEach ->
    @props =
      course: new Course(ecosystem_book_uuid: 'test-collection-uuid')
    sandbox = sinon.sandbox.create()
  afterEach ->
    sandbox.restore()

  describe 'course options', ->

    beforeEach ->
      sandbox.stub(User, 'isLoggedIn').returns(true)

    it 'renders for registration when course is not registered', ->
      sinon.stub(@props.course, 'isRegistered').returns(false)
      Testing.renderComponent( Menu, props: @props ).then ({dom}) ->
        expect(dom.textContent).to.match(/Register for Course/)

    it 'renders modification when registered', ->
      sinon.stub(@props.course, 'isRegistered').returns(true)
      Testing.renderComponent( Menu, props: @props ).then ({dom}) ->
        expect(dom.textContent).to.match(/Change Course/)
        expect(dom.textContent).to.match(/Change student ID/)

Update menu test to match new options

Update menu test to match new options


FactlinkJailRoot.showShouldSelectTextNotification = ->
  showNotification
    message: 'To create an annotation, select a statement and click the Factlink button.'
    type_classes: 'fl-message-icon-add'

FactlinkJailRoot.showLoadedNotification = ->
  showNotification
    message: 'Factlink is loaded!'
    type_classes: 'fl-message-icon-time fl-message-success'

in_screen_time = 3000
removal_delay = 1000 # Should be larger than notification_transition_time
content = """

""".trim()

showNotification = (options) ->
  $el = $(content)

  setMessage = -> $el.find('.fl-js-message').text(options.message)

  render = ->
    $el.addClass(options.type_classes)
    setMessage()
    FactlinkJailRoot.$factlinkCoreContainer.append($el)
    positionElement()

    $el.addClass 'factlink-control-visible'
    setTimeout(remove, in_screen_time)

  positionElement = ->
    $el.css
      top: '65px',
      left: '50%',
      marginLeft: "-#{$el.width()/2}px"

  remove = ->
    $el.removeClass 'factlink-control-visible'
    setTimeout (-> $el.remove()), removal_delay

  render()
  return

FactlinkJailRoot.showShouldSelectTextNotification = ->
  showNotification
    message: 'To create an annotation, select a statement and click the Factlink button.'
    type_classes: 'fl-message-icon-add'

FactlinkJailRoot.showLoadedNotification = ->
  showNotification
    message: 'Factlink is loaded!'
    type_classes: 'fl-message-icon-time fl-message-success'

in_screen_time = 3000
removal_delay = 350 # Should be larger than notification_transition_time
content = """

""".trim()

showNotification = (options) ->
  $el = $(content)

  setMessage = -> $el.find('.fl-js-message').text(options.message)

  render = ->
    $el.addClass(options.type_classes)
    setMessage()
    FactlinkJailRoot.$factlinkCoreContainer.append($el)
    positionElement()

    $el.addClass 'factlink-control-visible'
    setTimeout(remove, in_screen_time)

  positionElement = ->
    $el.css
      top: '65px',
      left: '50%',
      marginLeft: "-#{$el.width()/2}px"

  remove = ->
    $el.removeClass 'factlink-control-visible'
    setTimeout (-> $el.remove()), removal_delay

  render()
  return

Trim remove_delay down closer to transition duration


# 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/
$ ->
  $('#starts-at-datetime-picker').datetimepicker
    locale: 'de'
  $('#ends-at-datetime-picker').datetimepicker
    locale: 'de'

$(document).on "fields_added.nested_form_fields", (event, param) ->
  $(dateField).datetimepicker(
    locale: 'de'
  ) for dateField in $(event.target).find('.date')

Fix added shifts' datetimepickers not working


# Description:
#   Get the CI status reported to GitHub for a repo and pull request
#
# Dependencies:
#   "githubot": "0.4.x"
#
# Configuration:
#   HUBOT_GITHUB_TOKEN
#   HUBOT_GITHUB_USER
#   HUBOT_GITHUB_API
#
# Commands:
#   hubot repo show <repo> - shows activity of repository
#
# Notes:
#   HUBOT_GITHUB_API allows you to set a custom URL path (for Github enterprise users)
#
# Author:
#   mattr-

module.exports = (robot) ->
  github = require("githubot")(robot)
  robot.respond /status (\w+\/\w+)?\s*#?(\d+)/i, (msg) ->
    repo = github.qualified_repo msg.match[1]
    pr_number = msg.match[2]
    base_url = process.env.HUBOT_GITHUB_API || 'https://api.github.com'
    pull_url = "#{base_url}/repos/#{repo}/pulls/#{pr_number}"

    github.get pull_url, (pull) ->
      github.get pull.statuses_url, (status) ->
        last_status = status[0]
        msg.send "#{last_status.state} - #{last_status.target_url}"

# Description:
#   Get the CI status reported to GitHub for a repo and pull request
#
# Dependencies:
#   "githubot": "0.4.x"
#
# Configuration:
#   HUBOT_GITHUB_TOKEN
#   HUBOT_GITHUB_USER
#   HUBOT_GITHUB_API
#
# Commands:
#   hubot status jekyll/jekyll 2004
#   hubot status 2004
#
# Notes:
#   HUBOT_GITHUB_API allows you to set a custom URL path (for Github enterprise users)
#
# Author:
#   mattr-

module.exports = (robot) ->
  github = require("githubot")(robot)
  robot.respond /status (\w+\/\w+)?\s*#?(\d+)/i, (msg) ->
    repo = github.qualified_repo msg.match[1]
    pr_number = msg.match[2]
    base_url = process.env.HUBOT_GITHUB_API || 'https://api.github.com'
    pull_url = "#{base_url}/repos/#{repo}/pulls/#{pr_number}"

    github.get pull_url, (pull) ->
      github.get pull.statuses_url, (status) ->
        last_status = status[0]
        msg.send "#{last_status.state} - #{last_status.target_url}"

Update Commands section of header

Update Commands section of header


angular.module("admin.orders").controller "bulkInvoiceCtrl", ($scope, $http, $timeout) ->
  $scope.createBulkInvoice = ->
    $scope.invoice_id = null
    $scope.poll = 1
    $scope.loading = true
    $scope.message = null
    $scope.error = null

    $http.post('/admin/orders/invoices', {order_ids: $scope.selected_orders}).success (data) ->
      $scope.invoice_id = data
      $scope.pollBulkInvoice()

  $scope.pollBulkInvoice = ->
    $timeout($scope.nextPoll, 5000)

  $scope.nextPoll = ->
    $http.get('/admin/orders/invoices/'+$scope.invoice_id+'/poll').success (data) ->
      $scope.loading = false
      $scope.message = t('js.admin.orders.index.bulk_invoice_created')

    .error (data) ->
      $scope.poll++

      if $scope.poll > 10
        $scope.loading = false
        $scope.error = t('js.admin.orders.index.bulk_invoice_failed')
        return

      $scope.pollBulkInvoice()

angular.module("admin.orders").controller "bulkInvoiceCtrl", ($scope, $http, $timeout) ->
  $scope.createBulkInvoice = ->
    $scope.invoice_id = null
    $scope.poll = 1
    $scope.loading = true
    $scope.message = null
    $scope.error = null

    $http.post('/admin/orders/invoices', {order_ids: $scope.selected_orders}).success (data) ->
      $scope.invoice_id = data
      $scope.pollBulkInvoice()

  $scope.pollBulkInvoice = ->
    $timeout($scope.nextPoll, 5000)

  $scope.nextPoll = ->
    $http.get('/admin/orders/invoices/'+$scope.invoice_id+'/poll').success (data) ->
      $scope.loading = false
      $scope.message = t('js.admin.orders.index.bulk_invoice_created')

    .error (data) ->
      $scope.poll++

      if $scope.poll > 30
        $scope.loading = false
        $scope.error = t('js.admin.orders.index.bulk_invoice_failed')
        return

      $scope.pollBulkInvoice()

Increase polling to 150 seconds maximum before showing error message.


describe 'helpers', ->
  helpers = require('../lib/helpers')
  beforeEach ->
    atom.notifications.clear()

  describe '::error', ->
    it 'adds an error notification', ->
      helpers.error(new Error())
      expect(atom.notifications.getNotifications().length).toBe(1)

  describe '::shouldTriggerLinter', ->
    normalLinter =
      grammarScopes: ['*']
      scope: 'file'
      lintOnFly: false
      lint: ->
    lintOnFly =
      grammarScopes: ['*']
      scope: 'file'
      lintOnFly: true
      lint: ->
    bufferModifying =
      grammarScopes: ['*']
      scope: 'file'
      lintOnFly: false
      lint: ->
    it 'accepts a wildcard grammarScope', ->
      expect(helpers.shouldTriggerLinter(normalLinter, false, ['*'])).toBe(true)
    it 'runs lintOnFly ones on both save and lintOnFly', ->
      expect(helpers.shouldTriggerLinter(lintOnFly, false, ['*'])).toBe(true)
      expect(helpers.shouldTriggerLinter(lintOnFly, true, ['*'])).toBe(true)
    it "doesn't run save ones on fly", ->
      expect(helpers.shouldTriggerLinter(normalLinter, true, ['*'])).toBe(false)

describe 'helpers', ->
  helpers = require('../lib/helpers')
  beforeEach ->
    atom.notifications.clear()

  describe '::showError', ->
    it 'adds an error notification', ->
      helpers.showError(new Error())
      expect(atom.notifications.getNotifications().length).toBe(1)

  describe '::shouldTriggerLinter', ->
    normalLinter =
      grammarScopes: ['*']
      scope: 'file'
      lintOnFly: false
      lint: ->
    lintOnFly =
      grammarScopes: ['*']
      scope: 'file'
      lintOnFly: true
      lint: ->
    bufferModifying =
      grammarScopes: ['*']
      scope: 'file'
      lintOnFly: false
      lint: ->
    it 'accepts a wildcard grammarScope', ->
      expect(helpers.shouldTriggerLinter(normalLinter, false, ['*'])).toBe(true)
    it 'runs lintOnFly ones on both save and lintOnFly', ->
      expect(helpers.shouldTriggerLinter(lintOnFly, false, ['*'])).toBe(true)
      expect(helpers.shouldTriggerLinter(lintOnFly, true, ['*'])).toBe(true)
    it "doesn't run save ones on fly", ->
      expect(helpers.shouldTriggerLinter(normalLinter, true, ['*'])).toBe(false)

:arrow_up: Upgrade helper specs to match latest module


do (_=_, $ = jQuery || null, JEFRi = JEFRi) ->
	JEFRi.Template.rendered.entity :> ([entity, $render]) ->
		definition = entity._definition()
		for field, property of definition.properties
			behaviors.editField entity, field, property, $render

	behaviors =
		editField: (entity, field, property, $parent) ->
			$view = $parent.find(".#{entity._type()}._property.#{field}:first")
			$edit = JEFRi.Template.render.property(entity._type(), field, entity[field](), 'edit')

			$edit.find('input').blur blur = (e) ->
				$edit.replaceWith $view
				$view.click click
				null

			$view.click click = (e) ->
				$view.replaceWith $edit
				$input = $edit.find('input')
				$input.blur blur
				$input.focus()
				null

			null
	null

do (_=_, $ = jQuery || null, JEFRi = JEFRi) ->
	JEFRi.Template.rendered.entity :> ([entity, $render]) ->
		definition = entity._definition()
		for field, property of definition.properties
			behaviors.editField entity, field, property, $render

	behaviors =
		editField: (entity, field, property, $parent) ->
			$view = $parent.find(".#{entity._type()}._property.#{field}:first")
			$edit = JEFRi.Template.render.property(entity._type(), field, entity[field](), 'edit')

			$edit.find('input').blur blur = (e) ->
				newValue = $edit.find('input').val();
				$view = JEFRi.Template.render.property(entity._type(), field, newValue, 'view')
				entity[field](newValue)
				$edit.replaceWith $view
				$view.click click
				null

			$view.click click = (e) ->
				$view.replaceWith $edit
				$input = $edit.find('input')
				$input.blur blur
				$input.focus()
				null

			null
	null

Update view and entity on value change.

Update view and entity on value change.


#= require leaflet
$ ->
  map = L.map('map').setView [51.505, -0.09], 2
  L.tileLayer('http://{s}.tile.cloudmade.com/aff7873cf13349fe803e6a003f5c62bc/997/256/{z}/{x}/{y}.png', {
    attribution: "Metadata Census",
    maxZoom: 18
  }).addTo(map)

#= require leaflet
$ ->

  map = L.map('map').setView [51.505, -0.09], 2
  L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/{type}/{z}/{x}/{y}.png', {
    attribution: null,
    subdomains: '1234',
    type: 'osm',
  }).addTo(map)

Replace Leaflet tile with MapQuest tile

Replace Leaflet tile with MapQuest tile

I have replaced the Leaflet tile with the MaoQuest-OSM Tile.

Signed-off-by: Konrad Reiche <4ff0213f56e2082fcd8c882d04c546881c579ce4@gmail.com>


window.keymap.bindKeys '.editor'
  'meta-j': 'outline-view:toggle'
  'f3': 'outline-view:jump-to-declaration'

window.keymap.bindKeys '.editor'
  'meta-j': 'outline-view:toggle'
  'meta-.': 'outline-view:jump-to-declaration'

Use meta-. to jump to declaration

Use meta-. to jump to declaration


NotificationPlugin = require "../../notification-plugin"
url = require "url"
qs = require 'qs'

class BitbucketIssue extends NotificationPlugin
  @receiveEvent: (config, event, callback) ->

    query_object =
      "title": @title(event)
      "content": @markdownBody(event)
      "kind": config.kind
      "priority": config.priority

    # Send the request
    @request
      .post(url.resolve(config.url, "/api/1.0/repositories/#{config.repo}/issues"))
      .timeout(4000)
      .auth(config.username, config.password)
      .set('Accept', 'application/json')
      .send(qs.stringify(query_object))
      .on "error", (err) ->
        callback(err)
      .end (res) ->
        return callback({status: res.error.status, message: res.error.message, body: res.body}) if res.error

        callback null,
          id: res.body.local_id
          url: url.resolve(config.url, "#{res.body.resource_uri}")

module.exports = BitbucketIssue

NotificationPlugin = require "../../notification-plugin"
url = require "url"
qs = require 'qs'

class BitbucketIssue extends NotificationPlugin
  BASE_URL = "https://bitbucket.org"
  @receiveEvent: (config, event, callback) ->

    query_object =
      "title": @title(event)
      "content": @markdownBody(event)
      "kind": config.kind
      "priority": config.priority

    # Send the request
    @request
      .post(url.resolve(BASE_URL, "/api/1.0/repositories/#{config.repo}/issues"))
      .timeout(4000)
      .auth(config.username, config.password)
      .set('Accept', 'application/json')
      .send(qs.stringify(query_object))
      .on "error", (err) ->
        callback(err)
      .end (res) ->
        return callback({status: res.error.status, message: res.error.message, body: res.body}) if res.error

        callback null,
          id: res.body.local_id
          url: url.resolve(BASE_URL, "#{res.body.resource_uri}")

module.exports = BitbucketIssue

Fix Bitbucket to use url

Fix Bitbucket to use url


#= require ../object
#= require ./set

class Batman.SetProxy extends Batman.Object
  constructor: (@base) ->
    super()
    @length = @base.length
    @base.on 'itemsWereAdded', (items...) =>
      @set 'length', @base.length
      @fire('itemsWereAdded', items...)
    @base.on 'itemsWereRemoved', (items...) =>
      @set 'length', @base.length
      @fire('itemsWereRemoved', items...)

  Batman.extend @prototype, Batman.Enumerable

  filter: (f) ->
    r = new Batman.Set()
    @reduce(((r, e) -> r.add(e) if f(e); r), r)

  replace: ->
    length = @property('length')
    length.isolate()
    result = @base.replace.apply(@, arguments)
    length.expose()
    result

  for k in ['add', 'remove', 'find', 'clear', 'has', 'merge', 'toArray', 'isEmpty', 'indexedBy', 'indexedByUnique', 'sortedBy']
    do (k) =>
      @::[k] = -> @base[k](arguments...)

  Batman.Set._applySetAccessors(@)

  @accessor 'length',
    get: ->
      @registerAsMutableSource()
      @length
    set: (_, v) -> @length = v

#= require ../object
#= require ./set

class Batman.SetProxy extends Batman.Object
  constructor: (@base) ->
    super()
    @length = @base.length
    @base.on 'itemsWereAdded', (items...) =>
      @set 'length', @base.length
      @fire('itemsWereAdded', items...)
    @base.on 'itemsWereRemoved', (items...) =>
      @set 'length', @base.length
      @fire('itemsWereRemoved', items...)

  Batman.extend @prototype, Batman.Enumerable

  filter: (f) ->
    r = new Batman.Set()
    @reduce(((r, e) -> r.add(e) if f(e); r), r)

  replace: ->
    length = @property('length')
    length.isolate()
    result = @base.replace.apply(@, arguments)
    length.expose()
    result

  Batman.Set._applySetAccessors(@)

  for k in ['add', 'remove', 'find', 'clear', 'has', 'merge', 'toArray', 'isEmpty', 'indexedBy', 'indexedByUnique', 'sortedBy']
    do (k) =>
      @::[k] = -> @base[k](arguments...)

  @accessor 'length',
    get: ->
      @registerAsMutableSource()
      @length
    set: (_, v) -> @length = v

Apply setAccessors to SetSort before we override them.


assert = require("assert")
SpyReader = require "./helpers/spy_reader"
ts = require("..")
{ repeat, seq } = ts.rules

grammar = ts.grammar
  name: 'trivial_grammar'
  start: 'paragraph'
  rules:
    paragraph: -> repeat(@sentence)
    sentence: -> seq repeat(@word), "."
    word: -> /\w+/

cCode = ts.compile(grammar)
libPath = ts.buildParser(grammar.name, cCode)
parser = ts.loadParserLib(libPath, grammar.name)

describe "documents", ->
  doc = null

  beforeEach ->
    doc = new ts.Document()
    doc.setParser(parser)

  it "reads the entire input", ->
    reader = new SpyReader("see spot run. spot runs fast.", 3)
    doc.setInput(reader)
    assert.deepEqual(reader.chunksRead, [
      "see", " sp", "ot ", "run",
      ". s", "pot", " ru", "ns ", "fas", "t.", "", ""
    ])

  it "parses the input", ->
    reader = new SpyReader("see spot run. spot runs fast.", 3)
    doc.setInput(reader)
    assert.equal(doc.toString(), "Document: (paragraph (sentence (word) (word) (word)) (sentence (word) (word) (word)))")

assert = require("assert")
SpyReader = require "./helpers/spy_reader"
ts = require("..")
{ repeat, seq } = ts.rules

grammar = ts.grammar
  name: 'trivial_grammar'
  rules:
    paragraph: -> repeat(@sentence)
    sentence: -> seq repeat(@word), "."
    word: -> /\w+/

cCode = ts.compile(grammar)
libPath = ts.buildParser(grammar.name, cCode)
parser = ts.loadParserLib(libPath, grammar.name)

describe "documents", ->
  doc = null

  beforeEach ->
    doc = new ts.Document()
    doc.setParser(parser)

  it "reads the entire input", ->
    reader = new SpyReader("see spot run. spot runs fast.", 3)
    doc.setInput(reader)
    assert.deepEqual(reader.chunksRead, [
      "see", " sp", "ot ", "run",
      ". s", "pot", " ru", "ns ", "fas", "t.", "", ""
    ])

  it "parses the input", ->
    reader = new SpyReader("see spot run. spot runs fast.", 3)
    doc.setInput(reader)
    assert.equal(doc.toString(), "Document: (paragraph (sentence (word) (word) (word)) (sentence (word) (word) (word)))")

Remove unused grammar property in runtime test


Sprangular.service "Status", ($rootScope, $translate) ->

  status =
    initialized: false
    pageTitle: "Home"
    bodyClasses: {default: true}
    requestedPath: null
    httpLoading: false
    routeChanging: false
    cachedProducts: []
    meta: {}

    isLoading: ->
      @httpLoading || @routeChanging

    cacheProducts: (list) ->
      status.cachedProducts = status.cachedProducts.concat(list)

    findCachedProduct: (slug) ->
      _.find status.cachedProducts, (product) ->
        product.slug == slug

    setPageTitle: (translation_key) ->
      $translate(translation_key).then (text) ->
        status.pageTitle = text

    # addBodyClass('open', 'focused')
    addBodyClass: ->
      @_eachClass arguments, (classes, klass) ->
        classes[klass] = true

    # removeBodyClass('open', 'focused')
    removeBodyClass: ->
      @_eachClass arguments, (classes, klass) ->
        classes[klass] = false

    # toggleBodyClass('open', 'focused')
    toggleBodyClass: ->
      @_eachClass arguments, (classes, klass) ->
        classes[klass] = !classes[klass]

    _eachClass: (args, fn) ->
      self = this
      _.each args, (klass) -> fn(self.bodyClasses, klass)

  $rootScope.$on '$routeChangeSuccess', ->
    status.bodyClasses = {default: true}

  $rootScope.$watch (-> status.isLoading()), (loading) ->
    event = if loading then 'start' else 'end'
    $rootScope.$broadcast("loading.#{event}")

  status

Sprangular.service "Status", ($rootScope, $translate) ->

  status =
    initialized: false
    pageTitle: "Home"
    bodyClasses: {default: true}
    requestedPath: null
    httpLoading: false
    routeChanging: false
    cachedProducts: []
    meta: {}

    isLoading: ->
      @httpLoading || @routeChanging

    cacheProducts: (list) ->
      status.cachedProducts = status.cachedProducts.concat(list)

    findCachedProduct: (slug) ->
      _.find status.cachedProducts, (product) ->
        product.slug == slug

    setPageTitle: (translation_key) ->
      $translate(translation_key).then (text) ->
        status.pageTitle = text

    # addBodyClass('open', 'focused')
    addBodyClass: ->
      @_eachClass arguments, (classes, klass) ->
        classes[klass] = true

    # removeBodyClass('open', 'focused')
    removeBodyClass: ->
      @_eachClass arguments, (classes, klass) ->
        classes[klass] = false

    # toggleBodyClass('open', 'focused')
    toggleBodyClass: ->
      @_eachClass arguments, (classes, klass) ->
        classes[klass] = !classes[klass]

    _eachClass: (args, fn) ->
      self = this
      _.each args, (klass) -> fn(self.bodyClasses, klass)

  $rootScope.$on '$routeChangeSuccess', ->
    status.bodyClasses = {default: true}

  $rootScope.$watch (-> status.isLoading()), (loading) ->
    if loading
      status.addBodyClass('loading')
      $rootScope.$broadcast("loading.start")
    else
      status.removeBodyClass('loading')
      $rootScope.$broadcast("loading.end")

  status

Add `.loading` class to body when `Status.isLoading`


express = require 'express'
adminOnly = require '../../lib/middleware/admin_only'
JSONPage = require '../../components/json_page'

app = module.exports = express()
app.set 'views', __dirname
app.set 'view engine', 'jade'

page = new JSONPage
  name: 'professional-buyer',
  paths:
    show: '/professional-buyer'
    edit: '/professional-buyer/edit'

{ data, edit, upload } = require('../../components/json_page/routes')(page)
{ get, middleware } = require('./routes')(page)

app.get page.paths.show, adminOnly, get.landing
app.get page.paths.show + '/data', adminOnly, data
app.get page.paths.edit, adminOnly, edit
app.post page.paths.edit, adminOnly, upload
app.get page.paths.show + '/complete', adminOnly, middleware, get.complete

express = require 'express'
adminOnly = require '../../lib/middleware/admin_only'
JSONPage = require '../../components/json_page'

app = module.exports = express()
app.set 'views', __dirname
app.set 'view engine', 'jade'

page = new JSONPage
  name: 'professional-buyer',
  paths:
    show: '/professional-buyer'
    edit: '/professional-buyer/edit'

{ data, edit, upload } = require('../../components/json_page/routes')(page)
{ get, middleware } = require('./routes')(page)

app.get page.paths.show, get.landing
app.get "#{page.paths.show}/data", adminOnly, data
app.get page.paths.edit, adminOnly, edit
app.post page.paths.edit, adminOnly, upload
app.get "#{page.paths.show}/complete", middleware.isLoggedIn, get.complete

Update naming and remove admin restrictions


request             = require("request-json")
fs                  = require('fs')
slugify             = require 'cozy-slug'
{AppManager}        = require '../lib/paas'
spawn               = require('child_process').spawn
log                 = require('printit')
    prefix: "applications"

StackApplication    = require '../models/stack_application'
localizationManager = require '../helpers/localization_manager'

sendError = (res, err, code=500) ->
    err ?=
        stack:   null
        message: localizationManager.t "server error"

    console.log "Sending error to client:"
    console.log err.stack

    res.send code,
        error: true
        success: false
        message: err.message
        stack: err.stack

module.exports =

    get: (req, res, next) ->
        StackApplication.all (err, apps) ->
            if err then next err
            else res.send rows: apps

    update: (req, res, next) ->
        manager = new AppManager()
        manager.updateStack (err, result) ->
            if err?
                log.error err
                sendError res, err
            else
                res.send 200

    reboot: (req, res, next) ->
        manager = new AppManager()
        manager.restartController (err, result) ->
            if err?
                log.error err
                sendError res, err
            else
                res.send 200

request             = require("request-json")
fs                  = require('fs')
slugify             = require 'cozy-slug'
spawn               = require('child_process').spawn
log                 = require('printit')
    prefix: "applications"

{AppManager}        = require '../lib/paas'
StackApplication    = require '../models/stack_application'
localizationManager = require '../helpers/localization_manager'

sendError = (res, err, code=500) ->
    err ?=
        stack:   null
        message: localizationManager.t "server error"

    console.log "Sending error to client:"
    console.log err.stack

    res.send code,
        error: true
        success: false
        message: err.message
        stack: err.stack

module.exports =

    get: (req, res, next) ->
        StackApplication.all (err, apps) ->
            if err then next err
            else res.send rows: apps

    update: (req, res, next) ->
        manager = new AppManager()
        manager.updateStack (err, result) ->
            if err?
                log.error err
                sendError res, err
            else
                res.send 200

    reboot: (req, res, next) ->
        manager = new AppManager()
        manager.restartController (err, result) ->
            if err?
                log.error err
                sendError res, err
            else
                res.send 200

Clean requires in stack application module (server)


should = require 'should'
{wd40, browser} = require('../wd40')

url = 'http://localhost:3001'

describe 'Home page (not logged in)', ->
  before (done) ->
    wd40.init ->
      browser.get url, done

  before (done) =>
    wd40.getText 'body', (err, text) =>
      @bodyText = text
      done()

  it 'tells me about the platform for data science', =>
    @bodyText.toLowerCase().should.include 'data science'

  it 'gives me a link to sign up for an account', (done) ->
    browser.elementByPartialLinkText 'Sign up', (err, link) ->
      should.exist link
      link.getAttribute 'href', (err, href) ->
        href.should.include '/pricing'
        done()

  it 'tells me about ScraperWiki Data Services', =>
    @bodyText.toLowerCase().should.include 'data services'

  after (done) ->
    browser.quit ->
      done()

should = require 'should'
{wd40, browser} = require('../wd40')

url = 'http://localhost:3001'

describe 'Home page (not logged in)', ->
  before (done) ->
    wd40.init ->
      browser.get url, done

  before (done) =>
    wd40.getText 'body', (err, text) =>
      @bodyText = text
      done()

  it 'tells me about the platform for data science', =>
    @bodyText.toLowerCase().should.include 'data science'

  it 'gives me a link to sign up for an account', (done) ->
    browser.elementByPartialLinkText 'Sign up', (err, link) ->
      should.exist link
      link.getAttribute 'href', (err, href) ->
        href.should.include '/pricing'
        done()

  it 'tells me about ScraperWiki Data Services', =>
    @bodyText.toLowerCase().should.include 'services'

  after (done) ->
    browser.quit ->
      done()

Fix home not logged in test

Fix home not logged in test


# Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

helpers = require('./helpers')
AWS = helpers.AWS
MockClient = helpers.MockClient

describe 'AWS.NodeHttpClient', ->
  http = new AWS.NodeHttpClient()

  describe 'handleRequest', ->
    it 'emits httpError in error event', ->
      done = false
      req = new AWS.Request(endpoint: 'invalid', config: region: 'empty')
      resp = new AWS.Response(req)
      req.on 'httpError', (cbErr, cbResp) ->
        expect(cbErr instanceof Error).toBeTruthy()
        expect(cbResp).toBe(resp)
        done = true

      runs -> http.handleRequest(req, resp)
      waitsFor -> done

# Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
#     http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

helpers = require('./helpers')
AWS = helpers.AWS
MockClient = helpers.MockClient

describe 'AWS.NodeHttpClient', ->
  http = new AWS.NodeHttpClient()

  describe 'handleRequest', ->
    it 'emits httpError in error event', ->
      done = false
      endpoint = new AWS.Endpoint('http://invalid')
      req = new AWS.Request(endpoint: endpoint, config: region: 'empty')
      resp = new AWS.Response(req)
      req.on 'httpError', (cbErr, cbResp) ->
        expect(cbErr instanceof Error).toBeTruthy()
        expect(cbResp).toBe(resp)
        done = true

      runs -> http.handleRequest(req, resp)
      waitsFor -> done

Build correct endpoint in NodeHttpClient test


fs = require 'fs'
$ = require 'jquery'
ScrollView = require 'scroll-view'
{$$$} = require 'space-pen'

module.exports =
class MarkdownPreviewView extends ScrollView
  registerDeserializer(this)

  @deserialize: ({path}) ->
    new MarkdownPreviewView(project.bufferForPath(path))

  @content: ->
    @div class: 'markdown-preview', tabindex: -1

  initialize: (@buffer) ->
    super
    @fetchRenderedMarkdown()

  serialize: ->
    deserializer: 'MarkdownPreviewView'
    path: @buffer.getPath()

  getTitle: ->
    "Markdown Preview – #{@buffer.getBaseName()}"

  getUri: ->
    "markdown-preview:#{@buffer.getPath()}"

  setErrorHtml: ->
    @html $$$ ->
      @h2 'Previewing Markdown Failed'
      @h3 'Possible Reasons'
      @ul =>
        @li =>
          @span 'You aren\'t online or are unable to reach '
          @a 'github.com', href: 'https://github.com'
          @span '.'

  setLoading: ->
    @html($$$ -> @div class: 'markdown-spinner', 'Loading Markdown...')

  fetchRenderedMarkdown: (text) ->
    @setLoading()
    $.ajax
      url: 'https://api.github.com/markdown'
      type: 'POST'
      dataType: 'html'
      contentType: 'application/json; charset=UTF-8'
      data: JSON.stringify
        mode: 'markdown'
        text: @buffer.getText()
      success: (html) => @html(html)
      error: => @setErrorHtml()

fs = require 'fs'
$ = require 'jquery'
ScrollView = require 'scroll-view'
{$$$} = require 'space-pen'

module.exports =
class MarkdownPreviewView extends ScrollView
  registerDeserializer(this)

  @deserialize: ({path}) ->
    new MarkdownPreviewView(project.bufferForPath(path))

  @content: ->
    @div class: 'markdown-preview', tabindex: -1

  initialize: (@buffer) ->
    super
    @fetchRenderedMarkdown()
    @on 'core:move-up', => @scrollUp()
    @on 'core:move-down', => @scrollDown()

  serialize: ->
    deserializer: 'MarkdownPreviewView'
    path: @buffer.getPath()

  getTitle: ->
    "Markdown Preview – #{@buffer.getBaseName()}"

  getUri: ->
    "markdown-preview:#{@buffer.getPath()}"

  setErrorHtml: ->
    @html $$$ ->
      @h2 'Previewing Markdown Failed'
      @h3 'Possible Reasons'
      @ul =>
        @li =>
          @span 'You aren\'t online or are unable to reach '
          @a 'github.com', href: 'https://github.com'
          @span '.'

  setLoading: ->
    @html($$$ -> @div class: 'markdown-spinner', 'Loading Markdown...')

  fetchRenderedMarkdown: (text) ->
    @setLoading()
    $.ajax
      url: 'https://api.github.com/markdown'
      type: 'POST'
      dataType: 'html'
      contentType: 'application/json; charset=UTF-8'
      data: JSON.stringify
        mode: 'markdown'
        text: @buffer.getText()
      success: (html) => @html(html)
      error: => @setErrorHtml()

Allow markdown preview view to be scrolled with core:move-up/move-down


{ isListAscending } = require './is-list-ascending.coffee'

_binarySearch = (sortedList, needle)->
  return -1 if sortedList.length is 0

  mid = Math.floor (sortedList.length / 2)
  return mid if sortedList[mid] is needle

  if sortedList[mid] > needle
    return _binarySearch sortedList[0..mid - 1], needle
  else
    res = _binarySearch sortedList[mid+1..sortedList.length], needle
    return (if res is -1 then -1 else res + mid + 1)

@binarySearch = (sortedList, needle)->
  throw new Error 'Unsorted List' unless isListAscending sortedList
  return _binarySearch sortedList, needle

{ isListAscending } = require './is-list-ascending.coffee'

_binarySearch = (sortedList, needle, start, end)->

  return -1 if end < start

  mid = Math.floor (start + ((end - start) / 2))

  return mid if sortedList[mid] is needle

  if sortedList[mid] > needle

    return _binarySearch sortedList, needle, start, mid - 1

  else

    return _binarySearch sortedList, needle, mid + 1, end

@binarySearch = (sortedList, needle)->
  throw new Error 'Unsorted List' unless isListAscending sortedList
  return _binarySearch sortedList, needle, 0, sortedList.length-1

Revert "CHECKPOINT re-implemented binarySearch using slices"

This reverts commit 4454540a3858f512861e376414f8ab41e9da7662.