define (require) ->
  $ = require('jquery')
  BaseView = require('cs!helpers/backbone/views/base')
  template = require('hbs!./legacy-template')
  require('less!./legacy')

  return class LegacyModal extends BaseView
    template: template

    events:
      'submit': 'onSubmit'

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

      if $(e.currentTarget).find('.checkbox input').is(':checked')
        document.cookie = "legacy; max-age=#{60*60*24*30*365*4}; path=/;"

      location.href = @$el.children().data('href') # HACK to pass href value to modal view

define (require) ->
  $ = require('jquery')
  BaseView = require('cs!helpers/backbone/views/base')
  template = require('hbs!./legacy-template')
  require('less!./legacy')
  require('bootstrapTransition')
  require('bootstrapModal')

  return class LegacyModal extends BaseView
    template: template

    events:
      'submit': 'onSubmit'

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

      if $(e.currentTarget).find('.checkbox input').is(':checked')
        document.cookie = "legacy; max-age=#{60*60*24*30*365*4}; path=/;"

      location.href = @$el.children().data('href') # HACK to pass href value to modal view

Add bootstrap modal and transition dependencies


class NavigationMachineItem extends JView

  {Running, Stopped} = Machine.State

  stateClasses  = ''
  stateClasses += "#{state.toLowerCase()} " for state in Object.keys Machine.State

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

    machine            = data
    @alias             = machine.label
    path               = KD.utils.groupifyLink "/IDE/VM/#{machine.uid}"

    options.tagName    = 'a'
    options.cssClass   = "vm #{machine.status.state.toLowerCase()} #{machine.provider}"
    options.attributes =
      href             : path
      title            : "Open IDE for #{@alias}"

    super options, data

    @machine = @getData()
    @progress = new KDProgressBarView
      cssClass : 'hidden'
      # initial  : Math.floor Math.random() * 100

    { computeController } = KD.singletons

    computeController.on "public-#{@machine._id}", (event)=>

      {percentage, status} = event

      if percentage?

        if @progress.bar

          @progress.show()
          @progress.updateBar percentage

          if percentage is 100
            KD.utils.wait 1000, @progress.bound 'hide'

      else

        @progress.hide()

      if status?

        @unsetClass stateClasses
        @setClass status.toLowerCase()

  pistachio:->

    """

#{@alias}
    {{> @progress}}
    """

class NavigationMachineItem extends JView

  {Running, Stopped} = Machine.State

  stateClasses  = ''
  stateClasses += "#{state.toLowerCase()} " for state in Object.keys Machine.State

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

    machine            = data
    @alias             = machine.getName()
    path               = KD.utils.groupifyLink "/IDE/VM/#{machine.uid}"

    options.tagName    = 'a'
    options.cssClass   = "vm #{machine.status.state.toLowerCase()} #{machine.provider}"
    options.attributes =
      href             : path
      title            : "Open IDE for #{@alias}"

    super options, data

    @machine = @getData()
    @progress = new KDProgressBarView
      cssClass : 'hidden'
      # initial  : Math.floor Math.random() * 100

    { computeController } = KD.singletons

    computeController.on "public-#{@machine._id}", (event)=>

      {percentage, status} = event

      if percentage?

        if @progress.bar

          @progress.show()
          @progress.updateBar percentage

          if percentage is 100
            KD.utils.wait 1000, @progress.bound 'hide'

      else

        @progress.hide()

      if status?

        @unsetClass stateClasses
        @setClass status.toLowerCase()

  pistachio:->

    """

#{@alias}
    {{> @progress}}
    """

NavigationMachineItem: Use `machine.getName()` instead of `machine.label`


module.exports = (robot) ->
  names = ['Dana', 'Freia', 'Jhishan', 'Kyle', 'Brenton', 'Terri', 'Abhi', 'Drew']
  robot.hear /Resume queen, who is next\?/i, (res) ->
    res.send res.random names

module.exports = (robot) ->
  names = ['Dana', 'Freia', 'Jhishan', 'Kyle', 'Brenton', 'Terri', 'Abhi', 'Drew']
  names = ['@danagilliann', '@flobot', '@jhishan', '@kwhughes', '@brentdur', '@terriburns', '@abhiagarwal', '@nydrewreynolds']
  robot.hear /Resume queen, who is next\?/i, (res) ->
    res.send res.random names

Change first names to slack handles

Change first names to slack handles


class window.ArgumentVotes extends Backbone.Model
  defaults:
    believes: 0
    disbelieves: 0

  isNew: -> @_argument.isNew()

  initialize: (attributes, options) ->
    @_argument = options.argument

  url: ->
    @_argument.url() + '/opinion'

  setCurrentUserOpinion: (newOpinion) ->
    previousOpinion = @get('current_user_opinion')
    @set previousOpinion, @get(previousOpinion)-1 if previousOpinion != 'no_vote'
    @set newOpinion, @get(newOpinion)+1 if newOpinion != 'no_vote'
    @set 'current_user_opinion', newOpinion

  saveCurrentUserOpinion: (opinion_type) ->
    @previous_opinion_type = @get('current_user_opinion')

    @setCurrentUserOpinion opinion_type
    @save {},
      success: =>
        mp_track "Argument: Vote", url: @url(), opinion: opinion_type
      error: =>
        @setCurrentUserOpinion @previous_opinion_type

  relevance: -> @get('believes') - @get('disbelieves')

class window.ArgumentVotes extends Backbone.Model
  defaults:
    believes: 0
    disbelieves: 0

  isNew: -> @_argument.isNew()

  initialize: (attributes, options) ->
    @_argument = options.argument

    @_argument.on 'change:argument_votes', =>
      @set @_argument.get('argument_votes')

  url: ->
    @_argument.url() + '/opinion'

  setCurrentUserOpinion: (newOpinion) ->
    previousOpinion = @get('current_user_opinion')
    @set previousOpinion, @get(previousOpinion)-1 if previousOpinion != 'no_vote'
    @set newOpinion, @get(newOpinion)+1 if newOpinion != 'no_vote'
    @set 'current_user_opinion', newOpinion

  saveCurrentUserOpinion: (opinion_type) ->
    @previous_opinion_type = @get('current_user_opinion')

    @setCurrentUserOpinion opinion_type
    @save {},
      success: =>
        mp_track "Argument: Vote", url: @url(), opinion: opinion_type
      error: =>
        @setCurrentUserOpinion @previous_opinion_type

  relevance: -> @get('believes') - @get('disbelieves')

Update ArgumentVotes when the argument changes


Settings = require "settings-sharelatex"
logger = require "logger-sharelatex"
logger.initialize("track-changes")

HttpController = require "./app/js/HttpController"
express = require "express"
app = express()

app.use express.logger()

app.post "/doc/:doc_id/flush", HttpController.flushUpdatesWithLock

app.use (error, req, res, next) ->
	logger.error err: error, "an internal error occured"
	res.send 500

port = Settings.internal?.trackchanges?.port or 3014
host = Settings.internal?.trackchanges?.host or "localhost"
app.listen port, host, (error) ->
	if error?
		logger.error err: error, "could not start track-changes server"
	else
		logger.log "track changes api listening on http://#{host}:#{port}"

Settings = require "settings-sharelatex"
logger = require "logger-sharelatex"
logger.initialize("track-changes")

HttpController = require "./app/js/HttpController"
express = require "express"
app = express()

app.use express.logger()

app.post "/doc/:doc_id/flush", HttpController.flushUpdatesWithLock

app.get "/status", (req, res, next) ->
	res.send "track-changes is alive"

app.use (error, req, res, next) ->
	logger.error err: error, "an internal error occured"
	res.send 500

port = Settings.internal?.trackchanges?.port or 3014
host = Settings.internal?.trackchanges?.host or "localhost"
app.listen port, host, (error) ->
	if error?
		logger.error err: error, "could not start track-changes server"
	else
		logger.log "track changes api listening on http://#{host}:#{port}"

Add in /status end point

Add in /status end point


define [
  'jquery'
  'underscore'
  'backbone'
  'marionette'
  'cs!views/workspace/content/aloha-edit'
  'hbs!templates/workspace/content/content-edit'
], ($, _, Backbone, Marionette, AlohaEditView, contentEditTemplate) ->

  # Edit Content Body
  # -------
  return AlohaEditView.extend
    # **NOTE:** This template is not wrapped in an element
    template: contentEditTemplate
    modelKey: 'body'

define [
  'jquery'
  'underscore'
  'backbone'
  'marionette'
  'cs!views/workspace/content/aloha-edit'
  'hbs!templates/workspace/content/content-edit'
  'bootstrapPopover'
], ($, _, Backbone, Marionette, AlohaEditView, contentEditTemplate) ->

  # Edit Content Body
  # -------
  return AlohaEditView.extend
    # **NOTE:** This template is not wrapped in an element
    template: contentEditTemplate
    modelKey: 'body'

Enable popovers in content editor

Enable popovers in content editor


App.Followable =

  initialize: ->
    $('.followable-content a[data-toggle]').on 'click', (event) ->
      event.preventDefault()

  update: (followable_id, button) ->
    $("#" + followable_id + " .js-follow").html(button)
    initialize_modules()

App.Followable =

  initialize: ->
    $('.followable-content a[data-toggle]').on 'click', (event) ->
      event.preventDefault()

  update: (followable_id, button) ->
    $("#" + followable_id + " .js-follow").html(button)
    # Temporary line. Waiting for issue resolution: https://github.com/consul/consul/issues/1736
    initialize_modules()

Add comment to temporary bugfix.

Add comment to temporary bugfix.


isActive = (type, inverse = false) ->
  name = 'is'
  name = name + 'Not' if inverse
  name = name + _.capitalize type

  (view) ->
    unless view instanceof Spacebars.kw
      throw new Error "#{name} options must be key value pair such " +
        "as {{#{name} regex='route/path'}}. You passed: " +
        "#{JSON.stringify view}"

    pattern =
      className: Match.Optional String
      regex: String

    check view.hash, pattern

    route = Router.current().route

    return false unless route

    {className, regex} = view.hash

    className ?= if inverse then 'disabled' else 'active'

    isPath = true if type is 'path'

    test = testExp route, regex, isPath

    test = not test if inverse

    if test then className else false

testExp = (route, exp, isPath = false) ->
  if isPath
    pattern = route.path()

  else
    pattern = route.getName()

  re = new RegExp exp, 'i'

  re.test pattern

helpers =
  isActiveRoute: isActive 'route'

  isActivePath: isActive 'path'

  isNotActiveRoute: isActive 'route', true

  isNotActivePath: isActive 'path', true

Template.registerHelper name, func for own name, func of helpers

isActive = (type, inverse = false) ->
  name = 'is'
  name = name + 'Not' if inverse
  name = name + 'Active' + _.capitalize type

  (view) ->
    unless view instanceof Spacebars.kw
      throw new Error "#{name} options must be key value pair such " +
        "as {{#{name} regex='route/path'}}. You passed: " +
        "#{JSON.stringify view}"

    pattern =
      className: Match.Optional String
      regex: String

    check view.hash, pattern

    route = Router.current().route

    return false unless route

    {className, regex} = view.hash

    className ?= if inverse then 'disabled' else 'active'

    isPath = true if type is 'path'

    test = testExp route, regex, isPath

    test = not test if inverse

    if test then className else false

testExp = (route, exp, isPath = false) ->
  if isPath
    pattern = route.path()

  else
    pattern = route.getName()

  re = new RegExp exp, 'i'

  re.test pattern

helpers =
  isActiveRoute: isActive 'route'

  isActivePath: isActive 'path'

  isNotActiveRoute: isActive 'route', true

  isNotActivePath: isActive 'path', true

Template.registerHelper name, func for own name, func of helpers

Fix name of helper in error message

Fix name of helper in error message


# check for subscriptions to be ready
subsReady = (subs...) ->
  return FlowRouter.subsReady() if subs.length is 1
  subs = subs.slice(0, subs.length - 1)
  _.reduce subs, (memo, sub) ->
    memo and FlowRouter.subsReady(sub)
  , true

# return path
pathFor = (path, view) ->
  throw new Error('no path defined') unless path
  if path.hash?.route?
    view = path
    path = view.hash.route
    delete view.hash.route
  query = if view.hash.query then FlowRouter._qs.parse(view.hash.query) else {}
  FlowRouter.path(path, view.hash, query)

# return absolute url
urlFor = (path, view) ->
  relativePath = pathFor(path, view)
  Meteor.absoluteUrl(relativePath.substr(1))

# get parameter
param = (name) ->
  FlowRouter.getParam(name);

# get query parameter
queryParam = (key) ->
  FlowRouter.getQueryParam(key);

# get current route name
currentRouteName = () ->
  FlowRouter.getRouteName()

# deprecated
isSubReady = (sub) ->
  return FlowRouter.subsReady(sub) if sub
  return FlowRouter.subsReady()

helpers =
  subsReady: subsReady
  pathFor: pathFor
  urlFor: urlFor
  param: param
  queryParam: queryParam
  currentRouteName: currentRouteName
  isSubReady: isSubReady

Template.registerHelper name, func for own name, func of helpers

# check for subscriptions to be ready
subsReady = (subs...) ->
  return FlowRouter.subsReady() if subs.length is 1
  subs = subs.slice(0, subs.length - 1)
  _.reduce subs, (memo, sub) ->
    memo and FlowRouter.subsReady(sub)
  , true

# return path
pathFor = (path, view) ->
  throw new Error('no path defined') unless path
  if path.hash?.route?
    view = path
    path = view.hash.route
    delete view.hash.route
  query = if view.hash.query then FlowRouter._qs.parse(view.hash.query) else {}
  hashBang = if view.hash.hash then view.hash.hash else ''
  FlowRouter.path(path, view.hash, query) + hashBang

# return absolute url
urlFor = (path, view) ->
  relativePath = pathFor(path, view)
  Meteor.absoluteUrl(relativePath.substr(1))

# get parameter
param = (name) ->
  FlowRouter.getParam(name);

# get query parameter
queryParam = (key) ->
  FlowRouter.getQueryParam(key);

# get current route name
currentRouteName = () ->
  FlowRouter.getRouteName()

# deprecated
isSubReady = (sub) ->
  return FlowRouter.subsReady(sub) if sub
  return FlowRouter.subsReady()

helpers =
  subsReady: subsReady
  pathFor: pathFor
  urlFor: urlFor
  param: param
  queryParam: queryParam
  currentRouteName: currentRouteName
  isSubReady: isSubReady

Template.registerHelper name, func for own name, func of helpers

Add hashbang option to pathFor

Add hashbang option to pathFor


# reference "_namespace.coffee"
# reference "PartViewModel.coffee"

{ PartViewModel } = @witness.ui

@witness.ui.ScenarioViewModel = class ScenarioViewModel

	constructor: (@scenario) ->
		{ @path, @url } = @scenario.parentSpecification.parentFile
		@parts = (new PartViewModel part for part in [].concat @scenario.given, @scenario.when, @scenario.then)
		@errors = ko.observableArray []

		@scenario.on.failed.addHandler (errors) =>
			if jQuery.isArray errors
				for error in errors when not error.stack or error.fromAssertion
					error.stack = ""
				@errors errors
			else
				error = errors
				if not error.stack or error.fromAssertion
					error.stack = ""
				@errors [ error ]

	templateId: "scenario"

# reference "_namespace.coffee"
# reference "PartViewModel.coffee"

{ PartViewModel } = @witness.ui

@witness.ui.ScenarioViewModel = class ScenarioViewModel

	constructor: (@scenario) ->
		{ @path, @url } = @scenario.parentSpecification.parentFile
		@parts = (new PartViewModel part for part in [].concat @scenario.given, @scenario.when, @scenario.then)
		@errors = ko.observableArray []

		@scenario.on.running.addHandler =>
			@errors.removeAll()

		@scenario.on.failed.addHandler (errors) =>
			if jQuery.isArray errors
				for error in errors when not error.stack or error.fromAssertion
					error.stack = ""
				@errors errors
			else
				error = errors
				if not error.stack or error.fromAssertion
					error.stack = ""
				@errors [ error ]

	templateId: "scenario"

Clear errors when re-running a scenario.


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

# For more detailed documentation see
# https://atom.io/docs/latest/advanced/keymaps
'.editor.agda':
  'ctrl-c ctrl-l': 'agda-mode:load'
  'ctrl-c ctrl-x ctrl-q': 'agda-mode:quit'
  'ctrl-c ctrl-x ctrl-r': 'agda-mode:restart'
  'ctrl-c ctrl-f': 'agda-mode:next-goal'
  'ctrl-c ctrl-b': 'agda-mode:previous-goal'
  'ctrl-c ctrl-space': 'agda-mode:give'
  'ctrl-c ctrl-t': 'agda-mode:goal-type'
  'ctrl-c ctrl-e': 'agda-mode:context'
  'ctrl-c ctrl-,': 'agda-mode:goal-type-and-context'
  'ctrl-c ctrl-.': 'agda-mode:goal-type-and-inferred-type'
  'ctrl-c ctrl-r': 'agda-mode:refine'
  'ctrl-c ctrl-c': 'agda-mode:case'
  'ctrl-c ctrl-a': 'agda-mode:auto'
  'ctrl-c ctrl-n': 'agda-mode:normalize'
  '\\': 'agda-mode:input-symbol'

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

# For more detailed documentation see
# https://atom.io/docs/latest/advanced/keymaps
'.atom-text-editor.agda':
  'ctrl-c ctrl-l': 'agda-mode:load'
  'ctrl-c ctrl-x ctrl-q': 'agda-mode:quit'
  'ctrl-c ctrl-x ctrl-r': 'agda-mode:restart'
  'ctrl-c ctrl-f': 'agda-mode:next-goal'
  'ctrl-c ctrl-b': 'agda-mode:previous-goal'
  'ctrl-c ctrl-space': 'agda-mode:give'
  'ctrl-c ctrl-t': 'agda-mode:goal-type'
  'ctrl-c ctrl-e': 'agda-mode:context'
  'ctrl-c ctrl-,': 'agda-mode:goal-type-and-context'
  'ctrl-c ctrl-.': 'agda-mode:goal-type-and-inferred-type'
  'ctrl-c ctrl-r': 'agda-mode:refine'
  'ctrl-c ctrl-c': 'agda-mode:case'
  'ctrl-c ctrl-a': 'agda-mode:auto'
  'ctrl-c ctrl-n': 'agda-mode:normalize'
  '\\': 'agda-mode:input-symbol'

Use the atom-text-editor tag instead of the editor class.


# Description:
#   Generate code names for things
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   hubot codename - Generates a few potential codenames for you
#
# Author:
#   Scott J Roberts - @sroberts

api_url = "https://gist.github.com"
request_url = api_url + "/sroberts/6529712/raw/1e979071f6a9e8747d2c44cf5af7c4998e068d49/wordlist"

module.exports = (robot) ->
  robot.respond /codename/i, (msg) ->
    robot.http(request_url)
      .get() (err, res, body) ->
        if res.statusCode is 200
          wordlist = body.split(",")
          msg.send """Codewords:
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          """
        else
          msg.send "Error: Couldn't access #{api_url}."

# Description:
#   Generate code names for things
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   hubot codename - Generates a few potential codenames for you
#
# Author:
#   Scott J Roberts - @sroberts

api_url = "https://gist.githubusercontent.com"
request_url = api_url + "/sroberts/6529712/raw/1e979071f6a9e8747d2c44cf5af7c4998e068d49/wordlist"

module.exports = (robot) ->
  robot.respond /codename/i, (msg) ->
    robot.http(request_url)
      .get() (err, res, body) ->
        if res.statusCode is 200
          wordlist = body.split(",")
          msg.send """Codewords:
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          - #{msg.random wordlist} #{msg.random wordlist}
          """
        else
          msg.send "Error: Couldn't access #{api_url}."

Change api_url to reflect Gist raw file URI change

https://developer.github.com/changes/2014-02-21-gist-raw-file-url-change/


Template.CalendarItem.helpers
	style: ->
		user = Meteor.user()

		styles = []

		itemStatus = user?.grade?[@gradeItem._id]
		itemStatus ?= 'pending'

		switch itemStatus
			when 'done'
				styles.push 'color: lightgray'
			when 'doing'
				styles.push 'color: orange'

		return styles.join '; '

	canMarkInterrest: ->
		user = Meteor.user()

		return not user?.grade?[@gradeItem._id]?

	intereseted: ->
		user = Meteor.user()
		key = "#{@calendarItem.shift}#{@calendarItem.day}-#{@gradeItem._id}"
		return user?.calendar?[@calendar._id]?.indexOf(key) > -1

Template.CalendarItem.events
	'click button.remove-interest': (e) ->
		Meteor.call 'updateCalendarItemInterest', @calendar._id, @gradeItem._id, @calendarItem.shift, @calendarItem.day, false

	'click button.mark-interest': (e) ->
		Meteor.call 'updateCalendarItemInterest', @calendar._id, @gradeItem._id, @calendarItem.shift, @calendarItem.day, true

Template.CalendarItem.helpers
	style: ->
		user = Meteor.user()

		styles = []

		itemStatus = user?.grade?[@gradeItem._id]
		itemStatus ?= 'pending'

		switch itemStatus
			when 'done'
				styles.push 'color: lightgray'
			when 'doing'
				styles.push 'color: orange'

		return styles.join '; '

	canMarkInterrest: ->
		user = Meteor.user()

		return user?.grade?[@gradeItem._id] isnt 'done'

	intereseted: ->
		user = Meteor.user()
		key = "#{@calendarItem.shift}#{@calendarItem.day}-#{@gradeItem._id}"
		return user?.calendar?[@calendar._id]?.indexOf(key) > -1

Template.CalendarItem.events
	'click button.remove-interest': (e) ->
		Meteor.call 'updateCalendarItemInterest', @calendar._id, @gradeItem._id, @calendarItem.shift, @calendarItem.day, false

	'click button.mark-interest': (e) ->
		Meteor.call 'updateCalendarItemInterest', @calendar._id, @gradeItem._id, @calendarItem.shift, @calendarItem.day, true

Allow to mark interrest in doing subjects


unless EditableForm
  EditableForm = $.fn.editableform.Constructor
  EditableForm.prototype.saveWithUrlHook = (value) ->
    originalUrl   = @options.url
    model         = @options.model
    nestedName    = @options.nested
    nestedId      = @options.nid
    nestedLocale  = @options.locale

    @options.url = (params) =>
      if typeof originalUrl == 'function'
        originalUrl.call(@options.scope, params)
      else if originalUrl? && @options.send != 'never'
        myName = params.name
        myValue = params.value

        # if there are no values in a list, add a blank value so Rails knows all values were removed
        if Object.prototype.toString.call(params.value) == '[object Array]' && params.value.length == 0
          params.value.push("")

        obj = {}

        if nestedName
          nested          = {}
          nested[myName]  = myValue
          nested['id']    = nestedId

          if nestedLocale
            nested['locale'] = nestedLocale

          obj[nestedName + '_attributes'] = nested
        else if myName != ''
          obj[myName] = myValue

        params[model] = obj

        delete params.name
        delete params.value
        delete params.pk

        $.ajax($.extend({
          url:      originalUrl
          data:     params
          type:     'PUT'
          dataType: 'json'
        }, @options.ajaxOptions))

    @saveWithoutUrlHook(value)

  EditableForm.prototype.saveWithoutUrlHook = EditableForm.prototype.save
  EditableForm.prototype.save = EditableForm.prototype.saveWithUrlHook

unless EditableForm
  EditableForm = $.fn.editableform.Constructor
  EditableForm.prototype.saveWithUrlHook = (value) ->
    originalUrl   = @options.url
    model         = @options.model
    nestedName    = @options.nested
    nestedId      = @options.nid
    nestedLocale  = @options.locale

    @options.url = (params) =>
      if typeof originalUrl == 'function'
        originalUrl.call(@options.scope, params)
      else if originalUrl? && @options.send != 'never'
        myName = params.name
        myValue = params.value

        # if there are no values in a list, add a blank value so Rails knows all values were removed
        if Object.prototype.toString.call(params.value) == '[object Array]' && params.value.length == 0
          params.value.push("")

        obj = {}

        if nestedName
          nested          = {}
          nested[myName]  = myValue
          nested['id']    = nestedId

          if nestedLocale
            nested['locale'] = nestedLocale

          obj[nestedName + '_attributes'] = nested
        else if myName != ''
          obj[myName] = myValue
        else
          obj = myValue

        params[model] = obj

        delete params.name
        delete params.value
        delete params.pk

        $.ajax($.extend({
          url:      originalUrl
          data:     params
          type:     'PUT'
          dataType: 'json'
        }, @options.ajaxOptions))

    @saveWithoutUrlHook(value)

  EditableForm.prototype.saveWithoutUrlHook = EditableForm.prototype.save
  EditableForm.prototype.save = EditableForm.prototype.saveWithUrlHook

Use the value as parameter when the myName field does not exist


class Subjects
  queue: []
  api: null
  query:
    sort: 'queued'
    page_size: "30"

  constructor: (@api, @project, @subject_set_id)->
    @query.workflow_id = @project?.links.workflows[0]
    @query.subject_set_id = @subject_set_id

  update: (opts) ->
    @[opt] = value for opt, value of opts
    @query.workflow_id = @project?.links.workflows[0]
    @query.subject_set_id = @subject_set_id

  current: ->
    @queue[0]

  fetch: ->
    return Promise.resolve [] unless @query.workflow_id? && @query.subject_set_id?
    @api.type('subjects')
    .get @query
    .then (newSubjects) =>
      @queue.push subject for subject in newSubjects

  flush: ->
    subject = null for subject in @queue
    @queue = []

  next: ->
    subject = @queue.shift()
    @fetch() if @queue.length < 2
    subject

module.exports = Subjects

class Subjects
  queue: []
  api: null
  current: null
  query:
    sort: 'queued'
    page_size: "30"

  constructor: (@api, @project, @subject_set_id)->
    @query.workflow_id = @project?.links.workflows[0]
    @query.subject_set_id = @subject_set_id

  update: (opts) ->
    @[opt] = value for opt, value of opts
    @query.workflow_id = @project?.links.workflows[0]
    @query.subject_set_id = @subject_set_id

  fetch: ->
    return Promise.resolve [] unless @query.workflow_id? && @query.subject_set_id?
    @api.type('subjects')
    .get @query
    .then (newSubjects) =>
      @queue.push subject for subject in newSubjects

  flush: ->
    subject = null for subject in @queue
    @current = null
    @queue = []

  next: ->
    @current = @queue.shift()
    @fetch() if @queue.length < 2
    @current

module.exports = Subjects

Fix incorrect reporting of current subject


class UIDemo.Views.TransitionView extends Backbone.View

  transitionRemoveClass: (className, $el = @$el) ->
    p = @_transitionPromise($el)
    @_delay(=> $el.removeClass className).then -> p

  transitionAddClass: (className, $el = @$el) ->
    p = @_transitionPromise($el)
    @_delay(=> $el.addClass className).then -> p

  _transitionPromise: ($el) ->
    return `when`.resolve(this) if $('body').is('.no-transitions')

    defer = `when`.defer()
    transitionEvent = @_whichTransitionEvent()
    transitionEndEventHandler = =>
      $el[0].removeEventListener(
        transitionEvent
        transitionEndEventHandler
        false
      )
      defer.resolve(this)

    $el[0].addEventListener(
      transitionEvent
      transitionEndEventHandler
      false
    )
    defer.promise

  _whichTransitionEvent: ->
    el = document.createElement('fakeelement')
    transitions =
      'transition': 'transitionend'
      'OTransition': 'oTransitionEnd'
      'MozTransition': 'transitionend'
      'WebkitTransition': 'webkitTransitionEnd'
    return event for property, event of transitions when el.style[property]?

  _delay: (code, time = 0) ->
    time = 0 if $('body').is('.no-transitions')
    defer = `when`.defer()
    setTimeout(
      -> `when(code())`.then (result) => defer.resolve(result)
      time
    )
    defer.promise

class UIDemo.Views.TransitionView extends Backbone.View

  transitionRemoveClass: (className, $el = @$el) ->
    p = @_transitionPromise($el)
    @_delay(=> $el.removeClass className).then -> p

  transitionAddClass: (className, $el = @$el) ->
    p = @_transitionPromise($el)
    @_delay(=> $el.addClass className).then -> p

  _transitionPromise: ($el) ->
    return `when`.resolve(this) if $('body').is('.no-transitions')

    defer = `when`.defer()
    transitionEvent = @_whichTransitionEvent()
    transitionEndEventHandler = =>
      $el[0].removeEventListener(
        transitionEvent
        transitionEndEventHandler
        false
      )
      defer.resolve(this)

    $el[0].addEventListener(
      transitionEvent
      transitionEndEventHandler
      false
    )
    defer.promise

  _whichTransitionEvent: ->
    el = document.createElement('fakeelement')
    transitions =
      'transition': 'transitionend'
      'OTransition': 'oTransitionEnd'
      'MozTransition': 'transitionend'
      'WebkitTransition': 'webkitTransitionEnd'
    return event for property, event of transitions when el.style[property]?

  _delay: (code, time = 0) ->
    if $('body').is('.no-transitions')
      result = code()
      `when`.resolve(result)

    defer = `when`.defer()
    setTimeout(
      -> `when(code())`.then (result) => defer.resolve(result)
      time
    )
    defer.promise

Remove asynchronous working if transitions are disabled


define ['jquery'], ($) ->

  class SelectGroup

    constructor: (@parent = null, @callback = false) ->
      @selectParent = (if @parent != null then $(@parent) else $('.js-select-group'))
      @addHandlers()

    addHandlers: ->
      @selectParent.on 'focus', '.js-select', (e) =>
        @getOverlay(e.target).addClass 'dropdown__value--selected'

      @selectParent.on 'blur', '.js-select', (e) =>
        @getOverlay(e.target).removeClass 'dropdown__value--selected'

      @selectParent.on 'keyup', '.js-select', (e) =>
        $(e.target).trigger('change')

      @selectParent.on 'change', '.js-select', (e) =>
        e.preventDefault()
        t = $(e.target).find("option:selected")
        val = t.text()
        @getOverlay(e.target).text(val)
        if @callback then @callback(e.target)

    getOverlay: (target) ->
      $(target).closest(@parent).find('.js-select-overlay')

define ['jquery'], ($) ->

  class SelectGroup

    constructor: (@parent = null, @callback = false) ->
      @selectParent = (if @parent != null then $(@parent) else $('.js-select-group'))
      @selectParent.find('.js-select').each (eltIndex) =>
        @setOverlay(@selectParent[eltIndex])
      @addHandlers()

    addHandlers: ->
      @selectParent.on 'focus', '.js-select', (e) =>
        @getOverlay(e.target).addClass 'dropdown__value--selected'

      @selectParent.on 'blur', '.js-select', (e) =>
        @getOverlay(e.target).removeClass 'dropdown__value--selected'

      @selectParent.on 'keyup', '.js-select', (e) =>
        $(e.target).trigger('change')

      @selectParent.on 'change', '.js-select', (e) =>
        e.preventDefault()
        @setOverlay(e.target)
        if @callback then @callback(e.target)

    getOverlay: (target) ->
      $(target).closest(@parent).find('.js-select-overlay')

    setOverlay: (target) ->
      t = $(target).find("option:selected")
      val = t.text()
      @getOverlay(target).text(val)

Set the value of the overlay on initialition


kd           = require 'kd'
actions      = require './actiontypes'
fetchAccount = require 'app/util/fetchAccount'

dispatch = (args...) -> kd.singletons.reactor.dispatch args...

###*
 * Load account with given id.
 *
 * @param {string} id
###
loadAccount = (id) ->

  origin = generateOrigin id

  dispatch actions.LOAD_USER_BEGIN, { id, origin }

  fetchAccount origin, (err, account) ->
    if err
      dispatch actions.LOAD_USER_FAIL, { err, id, origin }
      return

    dispatch actions.LOAD_USER_SUCCESS, { id, origin, account }

###*
 * Generate an origin object for given id.
 *
 * @param {string} id - JAccount id
 * @return {object}
 * @api private
###
generateOrigin = (id) -> { id, constructorName: 'JAccount', _id: id }

module.exports = {
  loadAccount
}

kd           = require 'kd'
actions      = require './actiontypes'
fetchAccount = require 'app/util/fetchAccount'

###*
 * Load account with given id.
 *
 * @param {string} id
###
loadAccount = (id) ->

  origin = generateOrigin id

  { reactor } = kd.singletons

  reactor.dispatch actions.LOAD_USER_BEGIN, { id, origin }

  fetchAccount origin, (err, account) ->
    if err
      reactor.dispatch actions.LOAD_USER_FAIL, { err, id, origin }
      return

    reactor.dispatch actions.LOAD_USER_SUCCESS, { id, origin, account }

###*
 * Generate an origin object for given id.
 *
 * @param {string} id - JAccount id
 * @return {object}
 * @api private
###
generateOrigin = (id) -> { id, constructorName: 'JAccount', _id: id }

module.exports = {
  loadAccount
}

Use reactor directly inside of action

app: Use reactor directly inside of action


_ = require 'underscore-plus'
{EditorView, View} = require 'atom'
MarkerView = require './marker-view'

module.exports =
class FindResultsView extends View

  @content: ->
    @div class: 'search-results'

  initialize: (@findModel) ->
    @markerViews = {}
    @subscribe @findModel, 'updated', (args...) => @markersUpdated(args...)

  attach: ->
    @getEditor()?.underlayer.append(this)

  detach: ->
    super

  beforeRemove: ->
    @destroyAllViews()

  getEditor: ->
    activeView = atom.workspaceView.getActiveView()
    if activeView?.hasClass('editor') then activeView else null

  markersUpdated: (markers) ->
    editor = @getEditor()

    if not editor?
      @destroyAllViews()
    else
      markerViewsToRemoveById = _.clone(@markerViews)
      for marker in markers
        if @markerViews[marker.id]
          delete markerViewsToRemoveById[marker.id]
        else
          markerView = new MarkerView({editor, marker})
          @append(markerView.element)
          @markerViews[marker.id] = markerView

      for id, markerView of markerViewsToRemoveById
        delete @markerViews[id]
        markerView.remove()

      editor.requestDisplayUpdate()

  destroyAllViews: ->
    @empty()
    @markerViews = {}

_ = require 'underscore-plus'
{EditorView, View} = require 'atom'
MarkerView = require './marker-view'

# TODO: remove this when marker views are in core. Hopefully soon.

module.exports =
class FindResultsView extends View

  @content: ->
    @div class: 'search-results'

  initialize: (@findModel) ->
    @markerViews = {}
    debouncedUpdate = _.debounce(@markersUpdated, 20)
    @subscribe @findModel, 'updated', =>
      if @getEditor()?.hasClass('react')
        # HACK: there are some issues with some of the react editor's components
        # being not available. We shouldnt be doing this rendering anyway.
        # Marker views are coming.
        debouncedUpdate()
      else
        @markersUpdated()

  attach: ->
    editor = @getEditor()
    if editor? and editor.underlayer?
      editor.underlayer.append(this)
    else if editor?
      subscription = @subscribe editor, 'editor:attached', =>
        subscription.off()
        editor.underlayer.append(this)

  detach: ->
    super

  beforeRemove: ->
    @destroyAllViews()

  getEditor: ->
    activeView = atom.workspaceView.getActiveView()
    if activeView?.hasClass('editor') then activeView else null

  markersUpdated: =>
    editor = @getEditor()
    markers = @findModel.markers

    if not editor?
      @destroyAllViews()
    else
      markerViewsToRemoveById = _.clone(@markerViews)
      for marker in markers
        if @markerViews[marker.id]
          delete markerViewsToRemoveById[marker.id]
        else
          markerView = new MarkerView({editor, marker})
          @append(markerView.element)
          @markerViews[marker.id] = markerView

      for id, markerView of markerViewsToRemoveById
        delete @markerViews[id]
        markerView.remove()

      editor.requestDisplayUpdate()

  destroyAllViews: ->
    @empty()
    @markerViews = {}

Fix error with FindResultsView attachment and update on react editor

When you’d split-open a file, the react editor wasn’t attached or
rendered yet. So there was no under layer, and when you’d try to request
a display update, it would call functions on objects that weren’t there.

So I hack this with a delay. This is not a pretty fix. It will all go
away when there are marker views in core.

refs #232


packages: [
  "advanced-open-file"
  "atom-alignment"
  "atom-beautify"
  "atom-transpose"
  "change-case"
  "color-picker"
  "docblockr"
  "editorconfig"
  "emmet"
  "expand-region"
  "language-apache"
  "language-applescript"
  "language-awk"
  "language-babel"
  "language-diff"
  "language-env"
  "language-gitattributes"
  "language-gitignore"
  "language-har"
  "language-hosts"
  "language-ini"
  "language-javascript-jsx"
  "language-latex"
  "language-liquid"
  "language-lisp"
  "language-pegjs"
  "language-pip"
  "language-prolog"
  "language-sca"
  "language-svg"
  "language-tcl"
  "language-viml"
  "language-x86"
  "linter"
  "linter-coffeescript"
  "linter-eslint"
  "linter-flake8"
  "linter-jsonlint"
  "linter-php"
  "linter-shellcheck"
  "linter-ui-default"
  "monokai"
  "package-sync"
  "resize-indent"
  "sort-lines"
  "ssh-config"
  "svg-preview"
  "tabs-to-spaces"
  "teletype"
]

packages: [
  "advanced-open-file"
  "atom-alignment"
  "atom-beautify"
  "atom-transpose"
  "change-case"
  "color-picker"
  "docblockr"
  "editorconfig"
  "emmet"
  "expand-region"
  "git-blame"
  "language-apache"
  "language-applescript"
  "language-awk"
  "language-babel"
  "language-diff"
  "language-env"
  "language-gitattributes"
  "language-gitignore"
  "language-har"
  "language-hosts"
  "language-ini"
  "language-javascript-jsx"
  "language-latex"
  "language-liquid"
  "language-lisp"
  "language-pegjs"
  "language-pip"
  "language-prolog"
  "language-sca"
  "language-svg"
  "language-tcl"
  "language-viml"
  "language-x86"
  "linter"
  "linter-coffeescript"
  "linter-eslint"
  "linter-flake8"
  "linter-jsonlint"
  "linter-php"
  "linter-shellcheck"
  "linter-ui-default"
  "monokai"
  "package-sync"
  "resize-indent"
  "sort-lines"
  "ssh-config"
  "svg-preview"
  "tabs-to-spaces"
  "teletype"
]

Add git-blame to Atom package list

Add git-blame to Atom package list


KDView        = require './../../core/view.coffee'
JTreeItemView = require './../tree/treeitemview.coffee'

module.exports = class JContextMenuItem extends JTreeItemView

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

    options.type       = "contextitem"
    options.cssClass or= "default"

    super options, data

    @unsetClass "jtreeitem"

    if data
      if data.type is "divider" or data.type is "separator"
        @setClass "separator"

      if data.cssClass
        @setClass data.cssClass

      if data.type is "customView"
        @addCustomView data

      if data.disabled
        @setClass "disabled"

  viewAppended:->
    super()  unless @customView

  mouseDown:-> yes

  addCustomView:(data)->

    @setClass "custom-view"
    @unsetClass "default"
    @customView = data.view or new KDView
    delete data.view
    @addSubView @customView

KDView        = require './../../core/view.coffee'
JTreeItemView = require './../tree/treeitemview.coffee'

module.exports = class JContextMenuItem extends JTreeItemView

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

    options.type       = "contextitem"
    options.cssClass or= "default #{KD.utils.slugify data.title}"

    super options, data

    @unsetClass "jtreeitem"

    if data
      if data.type is "divider" or data.type is "separator"
        @setClass "separator"

      if data.cssClass
        @setClass data.cssClass

      if data.type is "customView"
        @addCustomView data

      if data.disabled
        @setClass "disabled"

  viewAppended:->
    super()  unless @customView

  mouseDown:-> yes

  addCustomView:(data)->

    @setClass "custom-view"
    @unsetClass "default"
    @customView = data.view or new KDView
    delete data.view
    @addSubView @customView

ContextMenu: Add slugified title as class name to context menu items.


"use strict"

ObjectID = require('mongodb').ObjectID

exports.param = (req, res, next, id) ->
  return res.json 400, error: 'Invalid ObjectID' if not /[a-f0-9]{24}/.test id
  req.id = ObjectID.createFromHexString id
  next()

exports.options = (req, res, next) ->
  res.setHeader 'Access-Control-Allow-Methods', 'GET, PUT, PATCH, DELETE'
  res.send()

exports.get = (req, res, next) ->
  req.col.findOne _id: req.id, (err, doc) ->
    return next err if err
    return res.json 200, documents: [doc], count: 1 if doc
    return res.json 404, error: 'Document Not Found'

exports.put = (req, res, next) ->
  res.send 501, 'Not Implemented'
  # 200, object

exports.patch = (req, res, next) ->
  res.send 501, 'Not Implemented'
  # 200, object

exports.delete = (req, res, next) ->
  res.send 501, 'Not Implemented'
  # 204

"use strict"

ObjectID = require('mongodb').ObjectID

exports.param = (req, res, next, id) ->
  return res.json 400, error: 'Invalid ObjectID' if not /^[a-f0-9]{24}$/.test id
  req.id = ObjectID.createFromHexString id
  next()

exports.options = (req, res, next) ->
  res.setHeader 'Access-Control-Allow-Methods', 'GET, PUT, PATCH, DELETE'
  res.send()

exports.get = (req, res, next) ->
  req.col.findOne _id: req.id, (err, doc) ->
    return next err if err
    return res.json 200, documents: [doc], count: 1 if doc
    return res.json 404, error: 'Document Not Found'

exports.put = (req, res, next) ->
  res.send 501, 'Not Implemented'
  # 200, object

exports.patch = (req, res, next) ->
  res.send 501, 'Not Implemented'
  # 200, object

exports.delete = (req, res, next) ->
  res.send 501, 'Not Implemented'
  # 204

Fix ObjectID hex string validation

Fix ObjectID hex string validation


hl = require 'highlight.js'
mousetrap = require 'mousetrap'
$ = require 'zeptojs'

processor = require './slide-pack-processor'
ui = require './slide-pack-ui'

executeHooks = ->
  if f = window._slide_pack_process_slides
    f $('.slide')

$('[data-slide-pack]').each ->
  slides = processor.process $(@).html()

  $article = $('

').addClass 'slide-pack'
  for slide in slides
    $slide = $('

')
      .addClass(slide.cssClass)
      .addClass('slide')

    $slide.html(slide.html)

    $article.append $slide

  $('body').append $article

  executeHooks()

ui.init slidePack : $('.slide-pack')

# keyboard navigation
mousetrap.bind ['left', 'up', 'k', 'h'], ui.prev
mousetrap.bind ['right', 'down', 'j', 'l'], ui.next

# mouse/touch navigation
$(document).on 'click', ui.next

hl.initHighlightingOnLoad()

hl = require 'highlight.js'
mousetrap = require 'mousetrap'
$ = require 'zeptojs'

processor = require './slide-pack-processor'
ui = require './slide-pack-ui'

executeHooks = ->
  if f = window._slide_pack_process_slides
    f $('.slide')

$('[data-slide-pack]').each ->
  $slidePack = $(@)
  slides = processor.process $slidePack.html()

  $article = $('

')
  for slide in slides
    $slide = $('

')
      .addClass(slide.cssClass)

    $slide.html(slide.html)

    $article.append $slide

  $('body').append $article

  executeHooks()

ui.init slidePack : $('article')

# keyboard navigation
mousetrap.bind ['left', 'up', 'k', 'h'], ui.prev
mousetrap.bind ['right', 'down', 'j', 'l'], ui.next

# mouse/touch navigation
$(document).on 'click', ui.next

hl.initHighlightingOnLoad()

Remove specific CSS classes for slides and slide-pack


# s2.2.5.3

# For now, only the "Transaction Descriptor" header (s2.2.5.3.2) is supported.

TYPE =
  QUERY_NOTIFICATIONS: 1
  TXN_DESCRIPTOR: 2
  TRACE_ACTIVITY: 3

TXNDESCRIPTOR_HEADER_DATA_LEN = 4 + 8
TXNDESCRIPTOR_HEADER_LEN = 4 + 2 + TXNDESCRIPTOR_HEADER_DATA_LEN

module.exports = (txnDescriptor, outstandingRequestCount) ->

  buffer = new Buffer(4 + (4 + 2 + TXNDESCRIPTOR_HEADER_DATA_LEN))

  position = 0

  buffer.writeUInt32LE(buffer.length, position)
  position += 4

  buffer.writeUInt32LE(TXNDESCRIPTOR_HEADER_LEN, position)
  position += 4

  buffer.writeUInt16LE(TYPE.TXN_DESCRIPTOR, position)
  position += 2

  buffer.writeUInt32LE(txnDescriptor % 0x100000000, position)
  position += 4

  buffer.writeUInt32LE(txnDescriptor / 0x100000000, position)
  position += 4

  buffer.writeUInt32LE(outstandingRequestCount, position)
  position += 4

  buffer

# s2.2.5.3

# For now, only the "Transaction Descriptor" header (s2.2.5.3.2) is supported.

WritableTrackingBuffer = require('../lib/tracking-buffer/tracking-buffer').WritableTrackingBuffer

TYPE =
  QUERY_NOTIFICATIONS: 1
  TXN_DESCRIPTOR: 2
  TRACE_ACTIVITY: 3

TXNDESCRIPTOR_HEADER_DATA_LEN = 4 + 8
TXNDESCRIPTOR_HEADER_LEN = 4 + 2 + TXNDESCRIPTOR_HEADER_DATA_LEN

module.exports = (txnDescriptor, outstandingRequestCount) ->
  buffer = new WritableTrackingBuffer(50)

  buffer.writeUInt32LE(0)                             # Will write buffer length in here later.
  buffer.writeUInt32LE(TXNDESCRIPTOR_HEADER_LEN)
  buffer.writeUInt16LE(TYPE.TXN_DESCRIPTOR)
  buffer.writeUInt32LE(txnDescriptor % 0x100000000)
  buffer.writeUInt32LE(txnDescriptor / 0x100000000)
  buffer.writeUInt32LE(outstandingRequestCount)

  data = buffer.data

  # Write deferred buffer length.
  data.writeUInt32LE(data.length, 0)

  data

Use WritableTrackingBuffer to simplify the creation of AllHeaders.


{ArgumentError, NotImplementedError} = require './errors'

#
# 'Abstract' class for Finitio types
#
class Type

  constructor: (@name)->
    if @name? and typeof(@name) isnt "string"
      throw new ArgumentError("String expected, got", @name)

    @name ?= @defaultName()

  #
  # Dress `value` with this information type and returns the result.
  #
  # @return the dressing result
  # @pre    true
  # @post   this.include(output)
  # @throws `Finitio.Error` if the dressing fails
  #
  dress: (value)->
    throw new NotImplementedError(this, "dress")

  #
  # Undress `value` as a member of `as` type.
  #
  # @param  `as` another Type instance
  # @return the undressed result
  # @pre    this.include(value)
  # @post   as.include(output)
  #
  undress: (value, as)->
    throw new NotImplementedError(this, "undress")

  toString: ->
    @name.toString()

  equal: (other)->
    this is other

module.exports = Type

{ArgumentError, NotImplementedError, TypeError} = require './errors'

#
# 'Abstract' class for Finitio types
#
class Type

  constructor: (@name)->
    if @name? and typeof(@name) isnt "string"
      throw new ArgumentError("String expected, got", @name)

    @name ?= @defaultName()

  #
  # Returns true if `value` is valid member of this type, false otherwise.
  #
  include: (value)->
    throw new NotImplementedError(this, "include")

  #
  # Dress `value` with this information type and returns the result.
  #
  # @return the dressing result
  # @pre    true
  # @post   this.include(output)
  # @throws `TypeError` if the dressing fails
  #
  dress: (value)->
    throw new NotImplementedError(this, "dress")

  #
  # Undress `value` as a member of `as` type.
  #
  # @param  `as` another Type instance
  # @return the undressed result
  # @pre    this.include(value)
  # @post   as.include(output)
  # @throw  `TypeError` if undressing fails
  #
  undress: (value, as)->
    return value if this.equals(as)
    throw new TypeError("Unable to undress `#{value}` to `#{as}`")

  #
  # Returns a String representation of this Type.
  #
  toString: ->
    @name.toString()

  #
  # Returns true if `other` is structurally equivalent to this type, false
  # otherwise.
  #
  equal: (other)->
    this is other

module.exports = Type

Document Type's public API a little bit.


path = require 'path'

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

  grunt.registerTask 'test', 'Run the specs', ->
    done = @async()
    commands = []
    commands.push (callback) ->
      spawn cmd: 'pkill', args: ['Atom'], -> callback()
    commands.push (callback) ->
      atomBinary = path.join(CONTENTS_DIR, 'MacOS', 'Atom')
      spawn cmd: atomBinary, args: ['--test', "--resource-path=#{__dirname}"], (error) ->  callback(error)
    grunt.util.async.waterfall commands, (error) -> done(error)

path = require 'path'

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

  grunt.registerTask 'test', 'Run the specs', ->
    done = @async()
    commands = []
    commands.push (callback) ->
      spawn cmd: 'pkill', args: ['Atom'], -> callback()
    commands.push (callback) ->
      atomBinary = path.join(grunt.config.get('atom.contentsDir'), 'MacOS', 'Atom')
      spawn cmd: atomBinary, args: ['--test', "--resource-path=#{__dirname}"], (error) ->  callback(error)
    grunt.util.async.waterfall commands, (error) -> done(error)

Use config to retrieve contents directory


#= require jquery
#= require jquery_ujs
#= require bootstrap-sprockets
#= require_tree ./admin

Remove useless empty admin JS require

Remove useless empty admin JS require


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

if !Settings.analytics?.postgres?
	module.exports =
		recordEvent: (user_id, event, metadata, callback = () ->) ->
			logger.log {user_id, event, metadata}, "no event tracking configured, logging event"
			callback()
else
	Sequelize = require "sequelize"
	options = _.extend {logging:false}, Settings.analytics.postgres

	sequelize = new Sequelize(
		Settings.analytics.postgres.database,
		Settings.analytics.postgres.username,
		Settings.analytics.postgres.password,
		options
	)

	Event = sequelize.define("Event", {
		user_id: Sequelize.STRING,
		event: Sequelize.STRING,
		metadata: Sequelize.STRING
	})

	module.exports =
		recordEvent: (user_id, event, metadata = {}, callback = (error) ->) ->
			if typeof(metadata) != "string"
				metadata = JSON.stringify(metadata)
			if user_id? and typeof(user_id) != "string"
				user_id = user_id.toString()
			if user_id == Settings.smokeTest?.userId
				# Don't record smoke tests analytics
				return callback()
			Event
				.create({ user_id, event, metadata })
				.then(
					(result) -> callback(),
					(error) ->
						logger.err {err: error, user_id, event, metadata}, "error recording analytics event"
						callback(error)
				)

		sync: () -> sequelize.sync()

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

if !Settings.analytics?.postgres?
	module.exports =
		recordEvent: (user_id, event, metadata, callback = () ->) ->
			logger.log {user_id, event, metadata}, "no event tracking configured, logging event"
			callback()
else
	Sequelize = require "sequelize"
	options = _.extend {logging:false}, Settings.analytics.postgres

	sequelize = new Sequelize(
		Settings.analytics.postgres.database,
		Settings.analytics.postgres.username,
		Settings.analytics.postgres.password,
		options
	)

	Event = sequelize.define("Event", {
		user_id: Sequelize.STRING,
		event: Sequelize.STRING,
		metadata: Sequelize.JSON
	})

	module.exports =
		recordEvent: (user_id, event, metadata = {}, callback = (error) ->) ->
			if user_id? and typeof(user_id) != "string"
				user_id = user_id.toString()
			if user_id == Settings.smokeTest?.userId
				# Don't record smoke tests analytics
				return callback()
			Event
				.create({ user_id, event, metadata })
				.then(
					(result) -> callback(),
					(error) ->
						logger.err {err: error, user_id, event, metadata}, "error recording analytics event"
						callback(error)
				)

		sync: () -> sequelize.sync()

Use a JSON column for metadata

Use a JSON column for metadata


circle =
  radius: 3
  center:
    x: 5
    y: 4
  color: 'green'
  thickness: 2
  lineStyle: 'dashed'

circle =
  radius: 3
  center:
    x: 5
    y: 4
  color: 'green'
  fillColor: 'pink'
  thickness: 2
  lineStyle: 'dashed'

Make some CoffeeScript examples more interesting


BufferedProcess = require 'buffered-process'
path = require 'path'

# Private: Like BufferedProcess, but accepts a node script instead of an
# executable, on Unix which allows running scripts and executables, this seems
# unnecessary, but on Windows we have to separate scripts from executables since
# it doesn't support shebang strings.
module.exports =
class BufferedNodeProcess extends BufferedProcess
  constructor: ({command, args, options, stdout, stderr, exit}) ->
    args = ['--atom-child_process-fork', command].concat(args)
    node =
      if process.platform is 'darwin'
        # On OS X we use the helper process to run script, because it doesn't
        # create an icon on the Dock.
        path.resolve(process.resourcesPath, '..', 'Frameworks',
                     'Atom Helper.app', 'Contents', 'MacOS', 'Atom Helper')
      else
        process.execPath

    super({command: node, args, options, stdout, stderr, exit})

BufferedProcess = require 'buffered-process'
path = require 'path'

# Private: Like BufferedProcess, but accepts a node script instead of an
# executable, on Unix which allows running scripts and executables, this seems
# unnecessary, but on Windows we have to separate scripts from executables since
# it doesn't support shebang strings.
module.exports =
class BufferedNodeProcess extends BufferedProcess
  constructor: ({command, args, options, stdout, stderr, exit}) ->
    node =
      if process.platform is 'darwin'
        # On OS X we use the helper process to run script, because it doesn't
        # create an icon on the Dock.
        path.resolve(process.resourcesPath, '..', 'Frameworks',
                     'Atom Helper.app', 'Contents', 'MacOS', 'Atom Helper')
      else
        process.execPath

    # Tell atom-shell to run like upstream node.
    options = {} if not options?
    options.env = Object.create(process.env) if not options.env?
    options.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = 1

    args.unshift(command)
    super({command: node, args, options, stdout, stderr, exit})

Make BufferedNodeProcess adapt to changes of atom-shell v0.4.4.


mocha = require 'gulp-mocha'
gutil = require 'gulp-util'
webpack = require 'webpack-stream'
runSequence = require 'run-sequence'
karma = require 'gulp-karma'

require 'coffee-loader'

module.exports = (gulp) ->

  gulp.task 'specs', (next) ->
    runSequence 'specs:server', 'specs:client', next

  gulp.task 'specs:client', (next) ->
    runSequence 'specs:client:build', 'specs:client:run', next

  gulp.task 'specs:server', ->
    gulp.src 'src/**/*.coffee'
    .pipe mocha()

  gulp.task 'specs:client:build', ->
    webpackConfig = require('./webpack_config').getDefaultConfiguration()
    webpackConfig.output =
      filename: 'specs.js'

    gulp.src [
      'src/**/*.coffee'
    ]
    .pipe webpack webpackConfig
    .pipe gulp.dest 'dist/specs'

  gulp.task 'specs:client:run', (next) ->
    gulp.src 'dist/specs/specs.js'
    .pipe karma
      configFile: 'karma.conf.coffee'
      action: 'start'

mocha = require 'gulp-mocha'
gutil = require 'gulp-util'
webpack = require 'webpack-stream'
runSequence = require 'run-sequence'
karma = require 'gulp-karma'

require 'coffee-loader'

module.exports = (gulp) ->

  gulp.task 'specs', (next) ->
    runSequence 'specs:server', 'specs:client', next

  gulp.task 'specs:client', (next) ->
    runSequence 'specs:client:build', 'specs:client:run', next

  gulp.task 'specs:server', ->
    gulp.src [
      'src/spec_setup.coffee'
      'src/**/*.coffee'
    ]
    .pipe mocha()

  gulp.task 'specs:client:build', ->
    webpackConfig = require('./webpack_config').getDefaultConfiguration()
    webpackConfig.output =
      filename: 'specs.js'

    gulp.src [
      'src/spec_setup.coffee'
      'src/**/*.coffee'
    ]
    .pipe webpack webpackConfig
    .pipe gulp.dest 'dist/specs'

  gulp.task 'specs:client:run', (next) ->
    gulp.src 'dist/specs/specs.js'
    .pipe karma
      configFile: 'karma.conf.coffee'
      action: 'start'

Gulp: Fix globs for spec tasks, make sure spec_setup always comes first


ExpressHttpResource = require 'bloops/adapters/express_resource'
MongooseAdapter = require 'bloops/adapters/mongoose_adapter'
models = require('./db').models
filters = require 'bloops/filters'

cors = require 'cors'

class BaseResource extends ExpressHttpResource
  adapter: MongooseAdapter
  context:
    models: models

class Resource extends BaseResource
  willAddEndpoint: (app, route, method, handler) ->
    # Enable a pre-flight OPTIONS request
    app.options(route, cors())

  getMiddleware: ->
    [cors()]

module.exports = {Resource, models, filters}

ExpressHttpResource = require 'bloops/adapters/express_resource'
MongooseAdapter = require 'bloops/adapters/mongoose_adapter'
models = require('./db').models
filters = require 'bloops/filters'

cors = require 'cors'

class BaseResource extends ExpressHttpResource
  adapter: MongooseAdapter
  context:
    models: models

class Resource extends BaseResource
  willAddEndpoint: (app, route, method, handler) ->
    # Enable a pre-flight OPTIONS request
    app.options(route, cors())

  getMiddleware: ->
    [cors()].concat(super)

module.exports = {Resource, models, filters}

Use provided middleware in resources by default


require 'semantic-ui-css/components/icon.css'
require 'semantic-ui-css/components/menu.css'
require 'semantic-ui-css/components/sidebar.css'
require '../../css/menu.css'

api = require '../backend.coffee'

React = require 'react'

module.exports = React.createClass
    displayName: 'MainMenu'
    render: ->
        active = (id) =>
            if @props.page is id
                'active item'
            else
                'item'

                Cache Cache

             @props.setPage 'poi'}>

                POI Generator

             @props.setPage 'map' }>

                Geocache Map

                Atom feed

                View Source

require 'semantic-ui-css/components/icon.css'
require 'semantic-ui-css/components/menu.css'
require 'semantic-ui-css/components/sidebar.css'
require '../../css/menu.css'

api = require '../backend.coffee'

React = require 'react'

module.exports = React.createClass
    displayName: 'MainMenu'
    render: ->
        active = (id) =>
            if @props.page is id
                'active item'
            else
                'item'
        # log calculator -> book icon
        # statistics -> bar chart icon

                Cache Cache

             @props.setPage 'poi'}>

                POI Generator

             @props.setPage 'map' }>

                Geocache Map

                Atom feed

                View Source

Add comment for later menu entries

Add comment for later menu entries


if Package.templating?
	Template = Package.templating.Template
	Blaze = Package.blaze.Blaze

	Blaze.toHTMLWithDataNonReactive = (content, data) ->
		makeCursorReactive = (obj) ->
			if obj instanceof Meteor.Collection.Cursor
				obj._depend
					added: true
					removed: true
					changed: true

		makeCursorReactive data

		if data instanceof Spacebars.kw and Object.keys(data.hash).length > 0
			for key, value of data.hash
				makeCursorReactive value

			data = data.hash

		html = ''

		Tracker.nonreactive ->
			html = Blaze.toHTMLWithData content, data

		return html

	Blaze.renderNonReactive = (templateName, data) ->
		return Blaze.toHTMLWithDataNonReactive Template[templateName], data

	Blaze.registerHelper 'nonReactiveRender', Blaze.renderNonReactive

	Blaze.registerHelper 'nrr', Blaze.renderNonReactive

if Package.templating?
	Template = Package.templating.Template
	Blaze = Package.blaze.Blaze
	HTML = Package.htmljs.HTML

	Blaze.toHTMLWithDataNonReactive = (content, data) ->
		makeCursorReactive = (obj) ->
			if obj instanceof Meteor.Collection.Cursor
				obj._depend
					added: true
					removed: true
					changed: true

		makeCursorReactive data

		if data instanceof Spacebars.kw and Object.keys(data.hash).length > 0
			for key, value of data.hash
				makeCursorReactive value

			data = data.hash

		html = ''

		Tracker.nonreactive ->
			html = Blaze.toHTMLWithData content, data

		return html

	Blaze.registerHelper 'nrrargs', ->
		obj = {}
		obj._arguments = arguments
		return obj

	Blaze.renderNonReactive = (templateName, data) ->
		_arguments = this.parentView.dataVar.get()._arguments

		templateName = _arguments[0]
		data = _arguments[1]

		view = undefined
		Tracker.nonreactive ->
			view = new Blaze.View 'nrr', ->
				return HTML.Raw Blaze.toHTMLWithDataNonReactive Template[templateName], data

			view.onViewReady ->
				Template[templateName].onViewReady?.call view

		return view

	Blaze.registerHelper 'nrr', Blaze.Template('nrr', Blaze.renderNonReactive)

Change from simple helper to block to allow track render


Ripper = require './ripper'
NotificationView = require './notification-view'

{ packages: packageManager } = atom

module.exports =
  activate: ->
    return if 'refactor' in packageManager.getAvailablePackageNames() and
              !packageManager.isPackageDisabled 'refactor'
    new NotificationView
  deactivate: ->
  serialize: ->
  Ripper: Ripper

Ripper = require './ripper'
NotificationView = require './notification_view'

{ packages: packageManager } = atom

module.exports =
  activate: ->
    return if 'refactor' in packageManager.getAvailablePackageNames() and
              !packageManager.isPackageDisabled 'refactor'
    new NotificationView
  deactivate: ->
  serialize: ->
  Ripper: Ripper

Rename filename to snake case

Rename filename to snake case


module.exports =

  activate: (state) ->
    atom.workspaceView.command 'table-edit:demo', ->
      Table = require './table'
      TableView = require './table-view'

      table = new Table
      table.addColumn 'key'
      table.addColumn 'value'
      table.addColumn 'foo'

      for i in [0...100]
        table.addRow [
          "row#{i}"
          i * 100
          if i % 2 is 0 then 'yes' else 'no'
        ]

      tableView = new TableView(table)
      tableView.setRowHeight 20
      tableView.setRowOverdraw 10

      tableView.addClass('demo overlay from-top').height(300)
      atom.workspaceView.append(tableView)

      tableView.on 'core:cancel', -> tableView.destroy()

  deactivate: ->

  serialize: ->

module.exports =

  activate: (state) ->
    atom.workspaceView.command 'table-edit:demo', ->
      Table = require './table'
      TableView = require './table-view'

      table = new Table
      table.addColumn 'key'
      table.addColumn 'value', align: 'right'
      table.addColumn 'foo', align: 'right'

      for i in [0...100]
        table.addRow [
          "row#{i}"
          i * 100
          if i % 2 is 0 then 'yes' else 'no'
        ]

      tableView = new TableView(table)
      tableView.setRowHeight 20
      tableView.setRowOverdraw 10

      tableView.addClass('demo overlay from-top').height(300)
      atom.workspaceView.append(tableView)

      tableView.on 'core:cancel', -> tableView.destroy()

  deactivate: ->

  serialize: ->

Add an alignment on columns in demo table


{View, $} = require 'atom'

module.exports =
class SideView extends View
  @content: (side) ->
    @div class: "side #{side.klass()} ui-site-#{side.site()}", =>
      @div class: 'controls', =>
        @label class: 'text-highlight', side.ref
        @span class: 'text-subtle', "// #{side.description()}"
        @button class: 'btn btn-xs pull-right', click: 'useMe', "Use Me"

  initialize: (@side) ->

  installIn: (editorView) ->
    @side.lines.addClass("conflict-line ours")
    @offset left: 0, top: @side.marker.position().top
    @height @side.marker.height()
    @appendTo editorView.find(".overlayer")

  useMe: ->
    console.log "useMe clicked"

  getModel: -> null

{View, $} = require 'atom'

module.exports =
class SideView extends View
  @content: (side) ->
    @div class: "side #{side.klass()} ui-site-#{side.site()}", =>
      @div class: 'controls', =>
        @label class: 'text-highlight', side.ref
        @span class: 'text-subtle', "// #{side.description()}"
        @button class: 'btn btn-xs pull-right', click: 'useMe', "Use Me"

  initialize: (@side) ->

  installIn: (editorView) ->
    @side.lines.addClass("conflict-line #{@side.klass()}")
    @offset left: 0, top: @side.marker.position().top
    @height @side.marker.height()
    @appendTo editorView.find(".overlayer")

  useMe: ->
    console.log "useMe clicked"

  getModel: -> null

Add the appropriate line class.

Add the appropriate line class.


'use strict'

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

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

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

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

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

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

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

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

      return
]

'use strict'

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

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

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

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

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

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

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

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

      return
]

Set unsubmitted for error case of editlinks.


React = require 'react'
Nav = React.createFactory require 'antwar-default-theme/Nav'
Paths = require('antwar-core/PathsMixin')
require 'antwar-default-theme/scss/main.scss'

require 'react-ghfork/gh-fork-ribbon.ie.css' # ie support
require 'react-ghfork/gh-fork-ribbon.css'
Fork = React.createFactory(require 'react-ghfork')

{ div, main, script, link } = require 'react-coffee-elements'

config = require 'config'
if config.theme.customStyles?
  require 'customStyles/' + config.theme.customStyles

module.exports = React.createClass

    displayName: 'Body'

    mixins: [
        Paths
    ]

    render: ->
        sectionName = @getSectionName()

        div { },
            if sectionName and sectionName != '/'
                Nav()
                Fork { className: 'right', project: 'survivejs/webpack_react/issues/new', text: 'Submit feedback', style: {backgroundColor: 'black'}}
            main { role: 'main' }, @props.children

React = require 'react'
Nav = React.createFactory require 'antwar-default-theme/Nav'
Paths = require('antwar-core/PathsMixin')
require 'antwar-default-theme/scss/main.scss'

require 'react-ghfork/gh-fork-ribbon.ie.css' # ie support
require 'react-ghfork/gh-fork-ribbon.css'
Fork = React.createFactory(require 'react-ghfork')

{ div, main, script, link } = require 'react-coffee-elements'

config = require 'config'
if config.theme.customStyles?
  require 'customStyles/' + config.theme.customStyles

module.exports = React.createClass

    displayName: 'Body'

    mixins: [
        Paths
    ]

    render: ->
        sectionName = @getSectionName()

        itemTitle = @getItem().title;

        div { },
            if sectionName and sectionName != '/'
                Nav()
                Fork { className: 'right', project: "survivejs/webpack_react/issues/new?title=#{itemTitle} - ", text: 'Submit feedback', style: {backgroundColor: 'black'}}
            main { role: 'main' }, @props.children

Add the section name when creating a new issue


convict = require 'convict'

config = convict {
  env:
    doc: 'The application environment.'
    default: 'development'
    env: 'NODE_ENV'
  verbose:
    doc: 'speak to me'
    default: false
  port:
    doc: 'Listened port'
    format: 'port'
    default: '1234'
    env: 'SHUSS_PORT'
  dir:
    doc: 'Served file directory'
    default: '.'
    env: 'SHUSS_DIR'
  livereloadport:
    doc: 'Enable livereload'
    default: 35729
    env: 'SHUSS_LR'
  livereload:
    doc: 'The livereload server port'
    default: false
    env: 'SHUSS_LR_PORT'
}

config.validate()

module.exports = config

convict = require 'convict'

config = convict {
  verbose:
    doc: 'speak to me'
    default: false
  port:
    doc: 'Listened port'
    format: 'port'
    default: '1234'
    env: 'SHUSS_PORT'
  dir:
    doc: 'Served file directory'
    default: '.'
    env: 'SHUSS_DIR'
  livereload:
    doc: 'Enable livereload'
    default: false
    env: 'SHUSS_LR'
  livereloadport:
    doc: 'The livereload server port'
    default: 35729
    env: 'SHUSS_LR_PORT'
}

config.validate()

module.exports = config

Remove useless env config, fix livereload settings


# Source: https://github.com/lukehoban/atom-ide-flow/blob/master/lib/tooltip-view.coffee
{$, View} = require 'atom'

module.exports = (Main)->
  class TooltipView extends View
    @content: ->
      @div class: 'ide-hack-tooltip'

    initialize: (@rect, @LeMessage) ->
      @append LeMessage
      $(document.body).append this
      @updatePosition()

    # smart position update
    updatePosition: ->
      coords = [@rect.right, @rect.bottom, undefined]
      offset = 10

      # x axis adjust
      if coords[0] + this[0].offsetWidth >= $(document.body).width()
        coords[0] = $(document.body).width() - this[0].offsetWidth - offset
      if coords[0] < 0
        this.css({ 'white-space': 'pre-wrap' })
        coords[0] = offset
        coords[2] = offset

      # y axis adjust
      if coords[1] + this[0].offsetHeight >= $(document.body).height()
        coords[1] = @rect.top - this[0].offsetHeight

      this.css({ left: coords[0], top: coords[1], right: coords[2] })

# Source: https://github.com/lukehoban/atom-ide-flow/blob/master/lib/tooltip-view.coffee
{$, View} = require 'atom'

module.exports = (Main)->
  class TooltipView extends View
    @content: ->
      @div class: 'ide-hack-tooltip'

    initialize: (rect, @LeMessage) ->
      @append LeMessage
      $(document.body).append this
      Coords = [rect.right, rect.bottom, undefined]
      Offset = 10

      # x axis adjust
      if Coords[0] + this[0].OffsetWidth >= $(document.body).width()
        Coords[0] = $(document.body).width() - this[0].OffsetWidth - Offset
      if Coords[0] < 0
        this.css({ 'white-space': 'pre-wrap' })
        Coords[0] = Offset
        Coords[2] = Offset

      # y axis adjust
      if Coords[1] + this[0].OffsetHeight >= $(document.body).height()
        Coords[1] = @rect.top - this[0].OffsetHeight

      this.css({ left: Coords[0], top: Coords[1], right: Coords[2] })

:art: Merge updatePosition function into Initialize


Validator = require('../main').Validator
fs = require 'fs'
argv = require('optimist')
  .usage('Usage: $0 --projectKey key --clientId id --clientSecret secret --csv file')
  .demand(['projectKey', 'clientId', 'clientSecret', 'csv'])
  .argv

timeout = argv.timeout
timeout or= 60000

options =
  config:
    project_key: argv.projectKey
    client_id: argv.clientId
    client_secret: argv.clientSecret
  timeout: timeout

validator = new Validator options

fs.readFile argv.csv, 'utf8', (err, content) ->
  if err
    console.error "Problems on reading file '#{argv.csv}': " + err
    process.exit 2
  validator.parse content, (data, count) ->
    errors = validator.validate data, (then) ->
      process.exit 0 if validator.errors.length is 0
      console.log validator.errors
      process.exit 1

Validator = require('../main').Validator
fs = require 'fs'
argv = require('optimist')
  .usage('Usage: $0 --projectKey key --clientId id --clientSecret secret --csv file')
  .describe('projectKey', 'your SPHERE.IO project-key')
  .describe('clientId', 'your OAuth client id for the SPHERE.IO API')
  .describe('clientSecret', 'your OAuth client secret for the SPHERE.IO API')
  .describe('csv', 'CSV file containing products to validate or import')
  .demand(['projectKey', 'clientId', 'clientSecret', 'csv'])
  .argv

timeout = argv.timeout
timeout or= 60000

options =
  config:
    project_key: argv.projectKey
    client_id: argv.clientId
    client_secret: argv.clientSecret
  timeout: timeout

validator = new Validator options

fs.readFile argv.csv, 'utf8', (err, content) ->
  if err
    console.error "Problems on reading file '#{argv.csv}': " + err
    process.exit 2
  validator.parse content, (data, count) ->
    errors = validator.validate data, (then) ->
      process.exit 0 if validator.errors.length is 0
      console.log validator.errors
      process.exit 1

Add description for command line options.


define [
  "jquery"
  "backbone"
  "app"
  "lib/extension"
  "lib/fuzzy-match"
], (
  $
  Backbone
  App
  Extension
  FuzzyMatch
) ->
  class Command extends Backbone.Model
    match: null

    getTemplateData: ->
      $.extend {}, @toJSON(), match: @match

    createMatch: (search) ->
      @match = new FuzzyMatch @get("name"), search

    execute: ->
      Extension.trigger "fetch.commands", @attributes
      App.once "fetched.commands", (src) =>
        window.location = "javascript:#{encodeURIComponent src}"
        App.trigger "close"

define [
  "jquery"
  "backbone"
  "app"
  "lib/extension"
  "lib/fuzzy-match"
], (
  $
  Backbone
  App
  Extension
  FuzzyMatch
) ->
  class Command extends Backbone.Model
    match: null

    getTemplateData: ->
      $.extend {}, @toJSON(), match: @match

    createMatch: (search) ->
      @match = new FuzzyMatch @get("name"), search

    execute: ->
      Extension.trigger "fetch.commands", @attributes
      App.once "fetched.commands", (src) =>
        src = decodeURIComponent src
        window.location = "javascript:#{encodeURIComponent src}"
        App.trigger "close"

Make sure code is url decoded before encoding it to avoid double encoding


Mixin = require 'mixto'

module.exports =
class Draggable extends Mixin
  # Allows for user dragging on the screen
  # * `startEvent` (optional) event from a mousedown event
  enableDragging: (startEvent) ->
    return if @_draggingEnabled
    element = @svgEl
    return unless element?

    element.draggable(startEvent)
    element.dragmove = =>
      @updateFromAttributes()
    element.dragend = (event) =>
      @model.setTransformString(null)
      @model.translate([event.x, event.y])
    @_draggingEnabled = true

  disableDragging: ->
    return unless @_draggingEnabled
    element = @svgEl
    return unless element?

    element.fixed?()
    element.dragstart = null
    element.dragmove = null
    element.dragend = null
    @_draggingEnabled = false

Mixin = require 'mixto'

module.exports =
class Draggable extends Mixin
  # Allows for user dragging on the screen
  # * `startEvent` (optional) event from a mousedown event
  enableDragging: (startEvent) ->
    return if @_draggingEnabled
    element = @svgEl
    return unless element?

    element.draggable(startEvent)
    element.dragmove = =>
      @updateFromAttributes()
    element.dragend = (event) =>
      @model.set(transform: null)
      @model.translate([event.x, event.y])
    @_draggingEnabled = true

  disableDragging: ->
    return unless @_draggingEnabled
    element = @svgEl
    return unless element?

    element.fixed?()
    element.dragstart = null
    element.dragmove = null
    element.dragend = null
    @_draggingEnabled = false

Use new model setter in draggable

Use new model setter in draggable


a = DS.attr
ETahi.Paper = DS.Model.extend
  assignees: DS.hasMany('user')
  editors: DS.hasMany('user')
  reviewers: DS.hasMany('user')
  editor: Ember.computed.alias('editors.firstObject')
  collaborations: DS.hasMany('collaboration')

  collaborators: (->
    @get('collaborations').mapBy('user')
  ).property('collaborations.@each')

  authors: DS.hasMany('author')
  figures: DS.hasMany('figure', inverse: 'paper')
  supportingInformationFiles: DS.hasMany('supportingInformationFile')
  journal: DS.belongsTo('journal')
  phases: DS.hasMany('phase')
  tasks: DS.hasMany('task', {async: true, polymorphic: true})
  lockedBy: DS.belongsTo('user')

  body: a('string')
  shortTitle: a('string')
  submitted: a('boolean')
  status: a('string')
  title: a('string')
  paperType: a('string')
  eventName: a('string')
  strikingImageId: a('string')

  relationshipsToSerialize: []

  displayTitle: (->
    @get('title') || @get('shortTitle')
  ).property('title', 'shortTitle')

  allMetadataTasks: (->
    @get('tasks').filterBy('isMetadataTask')
  ).property('tasks.content.@each.isMetadataTask')

  allMetadataTasksCompleted: ETahi.computed.all('allMetadataTasks', 'completed', true)

  editable: (->
    !(@get('allTasksCompleted') and @get('submitted'))
  ).property('allTasksCompleted', 'submitted')

a = DS.attr
ETahi.Paper = DS.Model.extend
  assignees: DS.hasMany('user') # these are admins that have been assigned to the paper.
  editors: DS.hasMany('user') # these are editors that have been assigned to the paper.
  reviewers: DS.hasMany('user') # these are reviewers that have been assigned to the paper.
  editor: Ember.computed.alias('editors.firstObject')
  collaborations: DS.hasMany('collaboration')

  collaborators: (->
    @get('collaborations').mapBy('user')
  ).property('collaborations.@each')

  authors: DS.hasMany('author')
  figures: DS.hasMany('figure', inverse: 'paper')
  supportingInformationFiles: DS.hasMany('supportingInformationFile')
  journal: DS.belongsTo('journal')
  phases: DS.hasMany('phase')
  tasks: DS.hasMany('task', {async: true, polymorphic: true})
  lockedBy: DS.belongsTo('user')

  body: a('string')
  shortTitle: a('string')
  submitted: a('boolean')
  status: a('string')
  title: a('string')
  paperType: a('string')
  eventName: a('string')
  strikingImageId: a('string')

  relationshipsToSerialize: []

  displayTitle: (->
    @get('title') || @get('shortTitle')
  ).property('title', 'shortTitle')

  allMetadataTasks: (->
    @get('tasks').filterBy('isMetadataTask')
  ).property('tasks.content.@each.isMetadataTask')

  allMetadataTasksCompleted: ETahi.computed.all('allMetadataTasks', 'completed', true)

  editable: (->
    !(@get('allTasksCompleted') and @get('submitted'))
  ).property('allTasksCompleted', 'submitted')

Add clarifying comments to model.

Add clarifying comments to model.


angular.module 'qbn.edsl', ['qbn.quality', 'qbn.storylet', 'qbn.choice']
  .factory 'qbnEdsl', (qualities, storylets, frontalChoices, choiceFactory) ->
    api =
      quality: (id, name, description, args = {}) ->
        {defaultValue, defaultProgress, maxProgress, hasProgress, progressEscalation,
         visible} = args
        defaultValue ?= 0
        defaultProgress ?= 0
        maxProgress ?= if hasProgress then 100 else 0
        progressEscalation ?= 0.10
        visible ?= true
        qualities.register id, name, description, defaultValue,
                                defaultProgress, maxProgress, progressEscalation,
                                visible
        return
      storylet: (id, title, text, choices = [], args = {}) ->
        {frontFacingChoice} = args
        storylets.register id, title, text, choices, frontFacingChoice
        return
      choice: (title, text, next, args) ->
        {visibleReqs, activeReqs} = args
        visibleReqs ?= {}
        activeReqs ?= {}
        choiceFactory title, text, visibleReqs, activeReqs, args
      front: (choice) ->
        frontalChoices.register choice
        return
    return Object.freeze api

angular.module 'qbn.edsl', ['qbn.quality', 'qbn.storylet', 'qbn.choice']
  .factory 'qbnEdsl', (qualities, storylets, frontalChoices, choiceFactory) ->
    api =
      quality: (id, name, description, args = {}) ->
        {defaultValue, defaultProgress, maxProgress, hasProgress, progressEscalation,
         visible} = args
        defaultValue ?= 0
        defaultProgress ?= 0
        maxProgress ?= if hasProgress then 100 else 0
        progressEscalation ?= 0.10
        visible ?= true
        qualities.register id, name, description, defaultValue,
                                defaultProgress, maxProgress, progressEscalation,
                                visible
        return
      storylet: (id, title, text, choices = [], args = {}) ->
        {frontFacingChoice} = args
        storylets.register id, title, text, choices, frontFacingChoice
        return
      choice: (title, text, next, args = {}) ->
        {visibleReqs, activeReqs} = args
        visibleReqs ?= {}
        activeReqs ?= {}
        choiceFactory title, text, visibleReqs, activeReqs, args
      front: (choice) ->
        frontalChoices.register choice
        return
    return Object.freeze api

Fix Missing Default Param in choice EDSL


BasePoint = require 'zooniverse-readymade/lib/drawing-tools/point'
ToolControls = require './tool-controls'

class Pinpoint extends BasePoint
  @Controls: ToolControls

  constructor: ->
    super
    @disc.attr 'class', 'pinpoint'

  rescale: (scale) ->
    super

  coords: (e) ->
    @markingSurface.screenPixelToScale @markingSurface.svg.pointerOffset e

  onMove: (e) =>
    {x, y} = @coords e
    @mark.set {x, y}

  render: ->
    super

    @controls.moveTo
      x: @mark.x + 30
      y: @mark.y

module.exports = Pinpoint

BasePoint = require 'zooniverse-readymade/lib/drawing-tools/point'
ToolControls = require './tool-controls'

class Pinpoint extends BasePoint
  @Controls: ToolControls

  constructor: ->
    super
    @disc.attr 'class', 'pinpoint'

  rescale: (scale) ->
    super

  coords: (e) ->
    @markingSurface.screenPixelToScale @markingSurface.svg.pointerOffset e

  onMove: (e) =>
    {x, y} = @coords e
    @mark.set {x, y}

  render: ->
    super

    offset = @radius / @markingSurface.magnification

    @controls.moveTo
      x: @mark.x + offset
      y: @mark.y

module.exports = Pinpoint

Fix point tool controls offset when scaling image.


# Description:
#   Make hubot list what tasty treats are available at Kerb Kings Cross (eat.st)
#
# Dependencies:
#
# Configuration:
#   None
#
# Commands:
#   hubot what's on kerb

jsdom = require "jsdom"

module.exports = (robot) ->
  robot.respond /what\'s on kerb/i, (msg) ->
    url = "http://www.kerbfood.com/kings-cross/"

    jsdom.env url, [ "http://code.jquery.com/jquery-1.5.min.js" ], (errors, window) ->
      d = new Date();
      formatted_date = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate()
      traders = window.$("#date-"+formatted_date+" ul li div.rota_content")
      message_str = "\n"
      traders.each (index, element) =>
        trader_name = window.$(element).children("h4").text()
        trader_desc = window.$(element).children("p").text()

        message_str += trader_name + "\n"
        message_str += "  " + trader_desc + "\n"

      msg.send message_str

# Description:
#   Make hubot list what tasty treats are available at Kerb Kings Cross (eat.st)
#
# Dependencies:
#
# Configuration:
#   None
#
# Commands:
#   hubot what's on kerb

jsdom = require "jsdom"

module.exports = (robot) ->
  robot.respond /what\'s on kerb/i, (msg) ->
    url = "http://www.kerbfood.com/kings-cross/"

    jsdom.env url, [ "http://code.jquery.com/jquery-1.5.min.js" ], (errors, window) ->
      d = new Date();
      day = d.getDate()
      day = (day < 10 ? '0' : '') + number
      formatted_date = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + day
      traders = window.$("#date-"+formatted_date+" ul li div.rota_content")
      message_str = "\n"
      traders.each (index, element) =>
        trader_name = window.$(element).children("h4").text()
        trader_desc = window.$(element).children("p").text()

        message_str += trader_name + "\n"
        message_str += "  " + trader_desc + "\n"

      msg.send message_str

Fix days of week formatting (1 -> 01)

Fix days of week formatting (1 -> 01)


builder = require('xmlbuilder')

class ChatChannel
  constructor: (@reflector) ->

  sendMessage: (player, message) ->
    xml = builder.create('root')
      .ele('chat', { from : player.name, message : message })
      .toString({ pretty: false })

    console.log(xml)

    @reflector.sendAll "<chat from='#{player.name}'>"
    @reflector.scene.dispatchEvent 'chat', { player : player, message : message }

# builder = require('xmlbuilder')

class ChatChannel
  constructor: (@reflector) ->

  sendMessage: (player, message) ->
    return

    xml = builder.create('root')
      .ele('chat', { from : player.name, message : message })
      .toString({ pretty: false })

    console.log(xml)

    @reflector.sendAll "<chat from='#{player.name}'>"
    @reflector.scene.dispatchEvent 'chat', { player : player, message : message }

Fix for broken chat channel stuff.

Fix for broken chat channel stuff.


class Timer
  constructor: (@id, @elapsed) ->
    @seconds = 0
    @minutes = 0
    @hours = 0
    @interval = undefined

    if @elapsed
      time = parseSeconds(@elapsed)
      @seconds = time.seconds
      @minutes = time.minutes
      @hours = time.hours

  parseSeconds = (seconds) ->
    hours = Math.floor(seconds/3600)
    seconds -= hours*3600

    minutes = Math.floor(seconds/60)
    seconds -= minutes*60

    {hours: hours, minutes: minutes, seconds: seconds}

  timeToString = (seconds, minutes, hours) ->
    hoursString = ""
    minutesString = ""
    secondsString = ""
    if hours < 10
      hoursString = "0" + hours
    else
      hoursString = hours
    if minutes < 10
      minutesString = "0" + minutes
    else
      minutesString = minutes
    if seconds < 10
      secondsString = "0" + seconds
    else
      secondsString = seconds
    timeString = ""
    if hours > 0
      timeString += hoursString + ":"
    timeString += "#{minutesString}:#{secondsString}"
    return timeString

  startInterval: () ->
    stepSecond = () =>
      @seconds++
      if @seconds >= 60
        @seconds = @seconds % 60
        @minutes++
      $(@id).html(timeToString(@seconds, @minutes, @hours))

    @interval = setInterval(stepSecond, 1000)

  stop: () ->
    clearInterval(@interval)

module.exports = Timer

class Timer
  constructor: (@id, @elapsed) ->
    @seconds = 0
    @minutes = 0
    @hours = 0
    @startTime = null
    @interval = undefined

    if @elapsed
      time = parseSeconds(@elapsed)
      @seconds = time.seconds
      @minutes = time.minutes
      @hours = time.hours

  parseSeconds = (seconds) ->
    hours = Math.floor(seconds/3600)
    seconds -= hours*3600

    minutes = Math.floor(seconds/60)
    seconds -= minutes*60

    {hours: hours, minutes: minutes, seconds: seconds}

  timeToString = (seconds, minutes, hours) ->
    hoursString = ""
    minutesString = ""
    secondsString = ""
    if hours < 10
      hoursString = "0" + hours
    else
      hoursString = hours
    if minutes < 10
      minutesString = "0" + minutes
    else
      minutesString = minutes
    if seconds < 10
      secondsString = "0" + seconds
    else
      secondsString = seconds
    timeString = ""
    if hours > 0
      timeString += hoursString + ":"
    timeString += "#{minutesString}:#{secondsString}"
    return timeString

  startInterval: () ->
    @startTime = Date.now()
    stepSecond = () =>
      totalSeconds = Math.floor((Date.now() - @startTime) / 1000) + @elapsed
      time = parseSeconds(totalSeconds)
      @hours = time.hours
      @minutes = time.minutes
      @seconds = time.seconds
      $(@id).html(timeToString(@seconds, @minutes, @hours))

    @interval = setInterval(stepSecond, 500)

  stop: () ->
    clearInterval(@interval)

module.exports = Timer

Set timer based on time, not setInterval calls

- timer was drifting like crazy


scrollHandler = ->
  url = $(".actvty-pagination .next_page a").attr("href")
  if url and $(window).scrollTop() > $(document).height() - $(window).height() - 300
    $(".actvty-pagination").text "Nicht so schnell..."
    showSpinner()
    $.getScript url
  return

if $(".actvty-pagination").length
  $(window).scroll(scrollHandler)
  $(window).scroll()
  $(document).on 'page:load', ->
    $(window).off "scroll", scrollHandler

showActivitiesClickHandler = ->
  $(this).closest(".grouped-activities").children(".activity").each ->
    $(this).slideDown()
  $(this).parent().hide()

$(".show-activities").click showActivitiesClickHandler

for id of window.unread["activity"]
  $("#activity-#{id} .unread-flag").show();

scrollHandler = ->
  url = $(".actvty-pagination .next_page a").attr("href")
  if url and $(window).scrollTop() > $(document).height() - $(window).height() - 300
    $(".actvty-pagination").text "Nicht so schnell..."
    showSpinner()
    $.getScript url
  return

if $(".actvty-pagination").length
  $(window).scroll(scrollHandler)
  $(window).scroll()
  $(document).on 'page:load', ->
    $(window).off "scroll", scrollHandler

showActivitiesClickHandler = ->
  $(this).closest(".grouped-activities").children(".activity").each ->
    $(this).slideDown()
  $(this).parent().hide()

$(".show-activities").click showActivitiesClickHandler

$.turboInit ->
  for k, v of window.unread["activity"]
    $("#activity-#{v} .unread-flag").show();

Fix adding of unread astericks

Fix adding of unread astericks


debug = require('debug')('meshblu:getThrottles')
Limitus = require 'limitus'
limiter = new Limitus()

config = require '../config'

config.rateLimits ?= {};
windowRate = 1000

createThrottle = (name, rate) ->
  debug 'createThrottle', name, rate
  limiter.rule name, max: rate, interval: windowRate
  rateLimit: (id="", callback=->) =>
    debug 'rateLimit', name, id
    limiter.drop(name, id, callback)

module.exports =
  connection: createThrottle 'connection', config.rateLimits.connection
  query:      createThrottle 'query', config.rateLimits.query
  message:    createThrottle 'message', config.rateLimits.message
  data:       createThrottle 'data', config.rateLimits.data
  whoami:     createThrottle 'whoami', config.rateLimits.whoami
  unthrottledIps : config.rateLimits.unthrottledIps

debug = require('debug')('meshblu:getThrottles')
Limitus = require 'limitus'
limiter = new Limitus()

config = require '../config'

config.rateLimits ?= {};
windowRate = 1000

createThrottle = (name, rate) ->
  debug 'createThrottle', name, rate
  limiter.rule name, max: rate, interval: windowRate, mode: 'interval'
  rateLimit: (id="", callback=->) =>
    debug 'rateLimit', name, id
    limiter.drop(name, id, callback)

module.exports =
  connection: createThrottle 'connection', config.rateLimits.connection
  query:      createThrottle 'query', config.rateLimits.query
  message:    createThrottle 'message', config.rateLimits.message
  data:       createThrottle 'data', config.rateLimits.data
  whoami:     createThrottle 'whoami', config.rateLimits.whoami
  unthrottledIps : config.rateLimits.unthrottledIps

Switch to interval rate limiting

Switch to interval rate limiting


# spec/javascripts/foobar_spec.js.coffee
describe "foobar", ->
  it 'works', -> expect(1 + 1).toEqual(2);

describe "wanted failure", ->
  it 'fails', -> expect(1 + 1).toEqual(42);

Remove failing test since Travis works.

Remove failing test since Travis works.


FactlinkJailRoot.contentBox = (element) ->
  $element = $(element)
  offset = $element.offset()

  top: offset.top + parseInt window.getComputedStyle(element)['padding-top']
  left: offset.left + parseInt window.getComputedStyle(element)['padding-left']
  width: $element.width()
  height: $element.height()

FactlinkJailRoot.contentBox = (element) ->
  $element = $(element)
  offset = $element.offset()

  top: offset.top + parseInt window.getComputedStyle(element).paddingTop
  left: offset.left + parseInt window.getComputedStyle(element).paddingLeft
  width: $element.width()
  height: $element.height()

Use paddingTop/Left, as this also works in firefox


Q = require 'bluebird-q'
Channel = require "../../models/channel"
Block = require "../../models/block"
Comments = require "../../collections/comments"
User = require "../../models/user"
markdown = require '../../lib/markdown'
sd = require("sharify").data
_ = require 'underscore'

@block = (req, res, next) ->
  block = new Block id: req.params.block_id
  comments = new Comments [], block: block

  Q.all [
    block.fetch data: auth_token: req.user?.get('authentication_token')
    comments.fetch(data: auth_token: req.user?.get('authentication_token')) if req.user?.has('username')
  ]
  .then ->
    res.locals.sd.BLOCK = block.toJSON()
    res.locals.sd.COMMENTS = comments.toJSON()
    res.locals.sd.CURRENT_ACTION = 'block'
    canIndexConnections = _.all block.get('connections'), (c) -> c.can_index
    canIndexUser = block.get('user')?.can_index

    res.render 'index',
      block: block
      comments: comments
      md: markdown
      canIndex: canIndexUser && canIndexConnections
      tab: req.params.tab || 'info'
      connections: block.connections()

  .catch next
  .done()

Q = require 'bluebird-q'
Channel = require "../../models/channel"
Block = require "../../models/block"
Comments = require "../../collections/comments"
User = require "../../models/user"
markdown = require '../../lib/markdown'
sd = require("sharify").data
_ = require 'underscore'

@block = (req, res, next) ->
  block = new Block id: req.params.block_id
  comments = new Comments [], block: block

  Q.all [
    block.fetch data: auth_token: req.user?.get('authentication_token')
    comments.fetch(data: auth_token: req.user?.get('authentication_token')) if req.user?.has('username')
  ]
  .then ->
    res.locals.sd.BLOCK = block.toJSON()
    res.locals.sd.COMMENTS = comments.toJSON()
    res.locals.sd.CURRENT_ACTION = 'block'
    canIndexConnections = _.all block.get('connections'), (c) -> c.user?.can_index
    canIndexUser = block.get('user')?.can_index

    res.render 'index',
      block: block
      comments: comments
      md: markdown
      canIndex: canIndexUser && canIndexConnections
      tab: req.params.tab || 'info'
      connections: block.connections()

  .catch next
  .done()

Check for can_index on the user, not the connection


parser = require 'nomnom'

braveMouse = require '../brave-mouse'

module.exports = (argv) ->
	parser
	.script 'brave-mouse'
	.parse argv.slice 2

parser = require 'nomnom'

braveMouse = require '../brave-mouse'
braveMousePackageJson = require '../../package.json'

module.exports = (argv) ->
	opts = parser
	.script 'brave-mouse'
	.options
		version:
			abbr: 'v'
			flag: true
			help: 'Print brave-mouse’s version'
	.parse argv.slice 2

	if opts.version
		return console.log 'v' + braveMousePackageJson.version

Print version on ‘brave-mouse -v’

Print version on ‘brave-mouse -v’


# variant autocompletion
$(document).ready ->
  if $("#variant_autocomplete_template").length > 0
    window.variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text())
    window.variantStockTemplate = Handlebars.compile($("#variant_autocomplete_stock_template").text())
    window.variantLineItemTemplate = Handlebars.compile($("#variant_line_items_autocomplete_stock_template").text())
  return

formatVariantResult = (variant) ->
  variant.image = variant.images[0].mini_url  if variant["images"][0] isnt `undefined` and variant["images"][0].mini_url isnt `undefined`
  variantTemplate variant: variant

$.fn.variantAutocomplete = ->
  @select2
    placeholder: Spree.translations.variant_placeholder
    minimumInputLength: 3
    initSelection: (element, callback) ->
      $.get Spree.routes.variants_search + "/" + element.val(), {}, (data) ->
        callback data
    ajax:
      url: Spree.url(Spree.routes.variants_api)
      quietMillis: 200
      datatype: "json"
      data: (term, page) ->
        q:
          product_name_or_sku_cont: term
        token: Spree.api_key

      results: (data, page) ->
        window.variants = data["variants"]
        results: data["variants"]

    formatResult: formatVariantResult
    formatSelection: (variant) ->
      if !!variant.options_text
        variant.name + " (#{variant.options_text})"
      else
        variant.name

# variant autocompletion
$(document).ready ->
  if $("#variant_autocomplete_template").length > 0
    window.variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text())
    window.variantStockTemplate = Handlebars.compile($("#variant_autocomplete_stock_template").text())
    window.variantLineItemTemplate = Handlebars.compile($("#variant_line_items_autocomplete_stock_template").text())
  return

formatVariantResult = (variant) ->
  variant.image = variant.images[0].mini_url  if variant["images"][0] isnt `undefined` and variant["images"][0].mini_url isnt `undefined`
  variantTemplate variant: variant

$.fn.variantAutocomplete = ->
  @select2
    placeholder: Spree.translations.variant_placeholder
    minimumInputLength: 3
    initSelection: (element, callback) ->
      $.get Spree.routes.variants_api + "/" + element.val(), { token: Spree.api_key }, (data) ->
        callback data
    ajax:
      url: Spree.url(Spree.routes.variants_api)
      quietMillis: 200
      datatype: "json"
      data: (term, page) ->
        q:
          product_name_or_sku_cont: term
        token: Spree.api_key

      results: (data, page) ->
        window.variants = data["variants"]
        results: data["variants"]

    formatResult: formatVariantResult
    formatSelection: (variant) ->
      if !!variant.options_text
        variant.name + " (#{variant.options_text})"
      else
        variant.name

Fix initSelection of variant autocomplete.

Fixes #6631